I'm trying to start my angular app and i'm getting this error below for some reason. I tried removing the auth service provider from my component and removing also the auth service from my constractor inside my component, but nothing changed... I can't figure out what i'm doing wrong and i'm beginner on angular.
The error:
Can't resolve all parameters for AuthService: (?, ?, [object Object]).
My component:
import { Component } from '#angular/core';
import { Router } from '#angular/router';
import { AuthService } from '../../Services/auth.service';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css'],
providers: [AuthService]
})
export class LoginComponent {
isUserLoggedIn: boolean;
emailAddress: string;
password: string;
invalidLogin: boolean;
invalidText: string;
constructor(private authService: AuthService, private router: Router) {
if (authService.getCurrentUser() != null) {
router.navigate(['/home']);
}
}
login() {
if (!this.authService.login(this.emailAddress.toString(), this.password.toString())) {
this.invalidLogin = true;
this.invalidText = "Wrong Email Address or password";
}
}
}
My service:
import { Inject } from '#angular/core';
import { HttpClient } from '#angular/common/http';
import { Router } from '#angular/router';
import { UserModel } from "../Models/UserModel";
export class AuthService {
constructor(private router: Router, private http: HttpClient, #Inject('BASE_URL') private baseUrl: string) {}
login(email: string, password: string) {
const headers = {'Content-Type': 'application/json', };
const body = { emailAddress: email, password: password };
let userLoggedIn: Boolean = false;
this.http.post<any>(this.baseUrl + "Api/Login", body, { headers }).subscribe(response => {
if (response.username != null) {
let user: UserModel
user = response;
this.router.navigate(['/home']);
this.saveUserToLocalStorage(user);
userLoggedIn = true
}
}, error => console.error(error));
return userLoggedIn;
}
saveUserToLocalStorage(loggedInUser: UserModel) {
sessionStorage.setItem("loggedInUser", JSON.stringify(loggedInUser));
}
getCurrentUser() {
return sessionStorage.getItem("loggedInUser")
}
logout() {
sessionStorage.removeItem("loggedInUser")
this.router.navigate([''])
}
createUser(userData: UserModel) {}
sendResetPasswordEmail() {}
}
I think this is because you use Router in your constructor, try to do this
constructor(private readonly injector: Injector,
...) {}
public get router(): Router {
return this.injector.get(Router);
}
I found what was the problem. I had to mark my service class as #Injectable()
Like this:
#Injectable()
export class SchoolService {
...
}
Related
actually i am using angular 11 and i want to show username in header component but my header is load first then my login component is load so after loading login component data store in local storage that why when i refresh page then user name is show but i dont want refresh page so what can i do for that please help me
below code is my authservice
import { Injectable } from '#angular/core';
import { environment } from 'src/environments/environment'
import { HttpClient } from '#angular/common/http';
import { Router } from '#angular/router';
#Injectable({
providedIn: 'root'
})
export class AuthService {
baseUrl = environment.apiUrl;
constructor(private http: HttpClient, private router: Router) { }
loginUser(data: {}) {
return this.http.post(this.baseUrl + 'signin', data)
}
isLoggedIn() {
//console.log(localStorage.getItem('user_details'))
if (localStorage.getItem('user_details') !== undefined && localStorage.getItem('user_details') !== null) {
//console.log("if")
return true;
} else {
return false;
}
//return !!localStorage.getItem('user_details')
}
getUserName(): any {
const userName = localStorage.getItem('user_details');
if (userName) {
return JSON.parse(userName);
}
return false;
}
isLoggedOut() {
localStorage.removeItem('user_details');
this.router.navigate(['/login']);
}
}
this is my header component
import { Component, OnInit, HostListener } from '#angular/core';
import { AuthService } from '../../login/services/auth.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
scrolled: boolean = false;
userName: string = '';
fname: string = '';
lname: string = "";
#HostListener("window:scroll", [])
onWindowScroll() {
this.scrolled = window.scrollY > 1;
}
constructor(public auth: AuthService, private router: Router) { }
ngOnInit(): void {
if (this.auth.isLoggedIn()) {
this.router.navigate(['dashboard']);
}
const user = this.auth.getUserName();
this.userName = user.role_name;
this.fname = user.first_name.charAt(0);
this.lname = user.last_name.charAt(0);
}
logOut() {
localStorage.removeItem('user_details');
this.router.navigate(['/login']);
}
}
below is login component
import { Component, OnInit } from '#angular/core';
import { FormGroup, FormControl, Validators } from '#angular/forms';
import { AuthService } from './services/auth.service';
import { Router } from '#angular/router';
import { Md5 } from 'md5-typescript';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
loginForm: any;
data: any;
success: any;
message: any;
constructor( private auth: AuthService, private router: Router ) {
this.loginForm = new FormGroup({
email: new FormControl('', [Validators.required, Validators.pattern('^[\\w-\\.]+#([\\w-]+\\.)+[\\w-]{2,4}$')]),
password: new FormControl('', Validators.required)
});
}
ngOnInit(): void { }
onSubmit() {
console.log(this.loginForm.value);
let data = {
"email_id": this.loginForm.value.email,
"password": Md5.init(this.loginForm.controls['password'].value)
}
this.auth.loginUser(data).subscribe(
(response: any) => {
this.data == response;
this.success == response.success;
if (response.success == 1) {
localStorage.setItem("user_details", JSON.stringify(JSON.parse(response.data).user_details))
console.log(localStorage.getItem('user_details'));
this.router.navigate(['dashboard']);
} else {
this.message = response.message;
}
}
);
this.loginForm.reset();
}
}
You can't use local storage to get logged in user details, because you component is already loaded. You need to create shared service using Subject or Behaviorsubject (RXJS operatoer) You can find example https://medium.com/#hitensharma1515/sharing-data-between-components-using-service-2d662a653a89
I'm building a angular spa front-end that consumes a GraphQL endpoint. After the users login, i set the token on localstorage and on my AuthService i set the auth state.My idea (coming from a React) was when the App component mounts ngOnInit i'll make a request for a me query who will return the user from the token stored on local storage, and i want to set the user on the AuthService. The problem i'm facing is that i've created a dashboard route which is protected, but the AuthGuard is not waiting for the App Component ngOnInit to finish and it will redirect to the login page.
import {Component, OnDestroy, OnInit} from '#angular/core';
import {MeGQL, User} from "../generated/graphql";
import {AuthService} from "./auth.service";
import {Router} from "#angular/router";
#Component({
selector: 'app-root',
templateUrl: 'app.component.html'
})
export class AppComponent implements OnInit {
title = 'frontend';
loading: boolean = true
private meSubs: any;
constructor(private meQuery: MeGQL, private authService: AuthService, private router: Router) {
}
async ngOnInit() {
this.loading = true
console.log("MONTOU APP")
this.loading = true
return this.meQuery.fetch({}, {
fetchPolicy: "network-only",
}).toPromise()
.then(({data}) => {
console.log("ENTROU NO THEN")
if (data.me) {
console.log(data.me)
this.authService.setUser(data.me)
this.loading = false
}
}).catch(e => {
this.loading = false
console.log("ERROR: ", e)
})
}
}
{{ loading }}
<div *ngIf="loading">Carregando...</div>
<div *ngIf="!loading">
<router-outlet></router-outlet>
</div>
import { Injectable } from '#angular/core';
import {ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot, UrlTree} from "#angular/router";
import {AuthService} from "../auth.service";
import {Observable} from "rxjs";
#Injectable({
providedIn: 'root'
})
export class AuthGuardService implements CanActivate{
constructor(private authService: AuthService, private router: Router) { }
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean > {
console.log("Auth Guard user mount")
if(!this.authService.isAuthenticated()) {
console.log("Não autenticado")
await this.router.navigate(['/login'])
return false
}
return true
}
}
import {Injectable} from '#angular/core';
import {User, MeQuery, MeDocument, MeQueryVariables} from "../generated/graphql";
import {BehaviorSubject} from "rxjs";
import {Apollo} from "apollo-angular";
export type CurrentUserType = Pick<User, 'id' | 'name' | 'email' | 'active' | 'type'>
#Injectable({
providedIn: 'root'
})
export class AuthService {
private TOKEN_KEY = "AGENDEI_TOKEN"
private currentUser: CurrentUserType | null = null
private _isAuthenticated = new BehaviorSubject(false);
private authSource = new BehaviorSubject<CurrentUserType | null>(null)
constructor(private apollo: Apollo) { }
loginUser(user: CurrentUserType, accessToken: string) {
localStorage.setItem(this.TOKEN_KEY, accessToken)
this.setUser(user)
this._isAuthenticated.next(true)
}
setUser(user: CurrentUserType) {
this.currentUser = user
}
async logout() {
localStorage.removeItem(this.TOKEN_KEY)
await this.apollo.getClient().resetStore()
this._isAuthenticated.next(false);
}
public isAuthenticated(): Boolean {
return this._isAuthenticated.value
}
public getUserFromMeQuery() {
return this.apollo.query<MeQuery, MeQueryVariables>({
query: MeDocument
}).toPromise()
}
}
I believe making changes in canActivate method in your guard service will work.
Cause While checking if a user is logged in or not you are not waiting for auth service to set the Authentication state.
AuthService
public isAuthenticated(): Promise<boolean> {
return this._isAuthenticated.toPromise();
}
AuthGuardService
async canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<boolean > {
console.log("Auth Guard user mount")
const isAuthenticated = await this.authService.isAuthenticated()
if(!isAuthenticated) {
console.log("Não autenticado")
await this.router.navigate(['/login'])
return false
}
return true
}
Try to use await in ngOninit of AppComponent:
async ngOnInit() {
this.loading = true
console.log("MONTOU APP")
this.loading = true
let response;
try {
response = await this.meQuery.fetch({}, {
fetchPolicy: "network-only",
}).toPromise()
let {data} = response;
if (data.me) {
console.log(data.me)
this.authService.setUser(data.me)
}
this.loading = false
} catch (err) {
this.loading = false
console.log("ERROR: ", err)
}
}
I am facing trouble in logging in with JWT in angular, I have successfully logged in via the login and also stored the token, but my frontend is not updating itself with the same
Auth.service.ts
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { ErrorprocessorService } from './errorprocessor.service';
import { Observable, Subject } from 'rxjs';
import { map } from 'rxjs/operators';
interface LogUser {
success: boolean;
message: string;
token: string;
user: {
name: string;
username: string;
email: string;
};
}
interface JWTResponse {
success: boolean;
message: string;
user: any;
}
#Injectable({
providedIn: 'root'
})
export class AuthService {
tokenKey = 'JWT';
isAuthenticated: Boolean = false;
username: Subject<string> = new Subject<string>();
authToken: string = undefined;
constructor(private http: HttpClient, private errorProcessor: ErrorprocessorService) { }
loadUserCredentials() {
const credentials = JSON.parse(localStorage.getItem(this.tokenKey));
console.log('Loading User Credentials : ', credentials);
if (credentials && credentials.username !== undefined) {
this.useCredentials(credentials);
if (this.authToken) {
this.checkJWTtoken();
}
}
}
checkJWTtoken() {
this.http.get<JWTResponse>('http://localhost:3000/auth/checkToken')
.subscribe(res => {
console.log('JWT Token Valid: ', res);
this.sendUsername(res.user.username);
}, err => {
console.log('JWT Token Invalid: ', err);
this.destroyUserCedentials();
});
}
storeUserCredentials(credentials: any) {
console.log('Storing User Credentials : ', credentials);
localStorage.setItem(this.tokenKey, JSON.stringify(credentials));
this.storeUserCredentials(credentials);
}
useCredentials(credentials: any) {
this.isAuthenticated = true;
this.sendUsername(credentials.username);
this.authToken = credentials.token;
}
sendUsername(name: string) {
this.username.next(name);
}
loginUser(user: any): Observable<any> {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'application/json'
})
};
return this.http.post<LogUser>('http://localhost:3000/auth/login', user, httpOptions)
.pipe(map(res => {
this.storeUserCredentials({ username: user.username, token: res.token });
return { 'success': true, 'username': user.username };
}))
}
destroyUserCedentials() {
this.authToken = undefined;
this.clearUsername();
this.isAuthenticated = false;
localStorage.removeItem(this.tokenKey);
}
clearUsername() {
this.username.next(undefined);
}
logOut() {
this.destroyUserCedentials();
}
isLoggedIn(): Boolean {
return this.isAuthenticated;
}
getUsername(): Observable<string> {
return this.username.asObservable();
}
getToken(): string {
return this.authToken;
}
}
Login.component.ts
import { Component, OnInit } from '#angular/core';
import { AuthService } from '../services/auth.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
errMsg: string;
user = {
username: '',
password: ''
};
constructor(private authService: AuthService, private router: Router) { }
ngOnInit(): void {
}
onSubmit(): void {
console.log(this.user);
this.authService.loginUser(this.user)
.subscribe(res => {
if (res.success) {
this.router.navigate(['/dashboard']);
} else {
console.log(res);
}
}, err => {
this.errMsg = <any>err;
});
}
}
Auth-guard.server.ts
import { Injectable } from '#angular/core';
import { Router, CanActivate } from '#angular/router';
import { AuthService } from './auth.service';
#Injectable({
providedIn: 'root'
})
export class AuthGuardService implements CanActivate {
constructor(public auth: AuthService, public router: Router) { }
canActivate(): boolean {
if (!this.auth.isLoggedIn()) {
this.router.navigate(['login']);
return false;
}
return true;
}
}
Header.component.ts
import { Component, OnInit, OnDestroy } from '#angular/core';
import { Subscription } from 'rxjs';
import { AuthService } from '../services/auth.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
username: string = undefined;
subscription: Subscription;
constructor(private authService: AuthService, private router: Router) { }
ngOnInit(): void {
this.authService.loadUserCredentials();
this.subscription = this.authService.getUsername()
.subscribe(name => { console.log(name); this.username = name; });
}
ngOnDestroy(): void {
this.subscription.unsubscribe();
}
openProfile(): void {
this.router.navigate(['/profile']);
}
logOut(): void {
this.username = undefined;
this.authService.logOut();
}
}
can anyone help me with this?
Thanks in advance and also if you need any other files ping me ill send you those
Your code has infinite loop:
storeUserCredentials(credentials: any) {
console.log('Storing User Credentials : ', credentials);
localStorage.setItem(this.tokenKey, JSON.stringify(credentials));
this.storeUserCredentials(credentials);
}
It could be be an error that blocking your app running
I want that when one logs in it check for the admin type then redirect him to the specific component for examp HOD should acces the admidashboard cict should access admin2 dashboard, etc.
Here is my mongoose schema
const mongoose = require('mongoose');
const ClearAdminSchema = new mongoose.Schema({
email:
{
type:String,
required:true,
trim:true
},
password:{
type:String,
required:true
},
name:{
type:String,
required:true,
trim:true
},
admintype:{
type:String,
type:String,
enum :['HOD','CICT','Sports','SUASAB','Admin']
},
university:{
type:String,
default:"Sokoine University of Agriculture"
},
college:{
type:String,
required:true
},
department:{
type:String,
required:true
}
});
const ClearAdmin = mongoose.model('ClearAdmin', ClearAdminSchema);
module.exports = ClearAdmin;
Here is my auth.guard.ts
import { Injectable } from '#angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '#angular/router';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';
import { UserService } from './user.service';
import { map } from 'rxjs/operators';
import { Router } from '#angular/router'
#Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private auth: AuthService,private router:Router, private user: UserService)
{
}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
if(this.auth.isLoggedIn)
{
return true
}
return this.user.isLoggedIn().pipe(map(res => {
if(res.status)
{
this.auth.setLoggedIn(true)
return true
}
else
{
this.router.navigate(['login'])
return false
}
}))
}
}
Here is my auth.service.ts
import { Injectable } from '#angular/core';
import{ HttpClient } from '#angular/common/http';
interface myData
{
success:boolean,
message: string,
token:"user_token"
admintype:String
}
interface moData
{
success:boolean,
message:String
}
#Injectable({
providedIn: 'root'
})
export class AuthService {
uri : String = 'http://localhost:4000';
private loggedInStatus = false
constructor(private http: HttpClient) { }
setLoggedIn(value: boolean)
{
this.loggedInStatus = value
}
get isLoggedIn()
{
return this.loggedInStatus
}
getUserDetails(email: String,password:String){
//post these details to the database
return this.http.post<myData>(`${this.uri}/auth`,{ email,password});
}
signupadminsections(email:String,password:String,name:String,
admintype:String,college:String,department:String)
{
//add new admin section
return this.http.post<moData>(`${this.uri}/register`,{ email,password,name,admintype,college,department});
}
}
Here is my Login.component.ts
import { Component, OnInit } from '#angular/core';
import { AuthService } from 'src/app/auth.service';
import { Router } from '#angular/router';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
constructor(private Auth: AuthService,private router: Router) { }
ngOnInit() {
}
loginUser(event)
{
event.preventDefault()
const target = event.target
const email= target.querySelector('#email').value
const password = target.querySelector('#password').value
this.Auth.getUserDetails(email, password).subscribe(data => {
if(data.token)
{
localStorage.setItem('user_token',data.token);
//redirect the person to admin page
this.router.navigate(['admin'])
this.Auth.setLoggedIn(true)
}
else
{
window.alert(data.message);
}
});
console.log(email, password)
}
logoutUser()
{
localStorage.removeItem('user_token');
this.router.navigate(['login'])
this.Auth.setLoggedIn(false);
console.log(event);
}
}
I want that when one logs in it check for the admin type then redirect him to the specific component for examp HOD should acces the admidashboard cict should access admin2 dashboard, etc.
This is my Roleguard.ts
import { Injectable } from '#angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree } from '#angular/router';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';
#Injectable({
providedIn: 'root'
})
export class RoleGuard implements CanActivate {
constructor( public auth: AuthService) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
return true;
}
}
https://www.npmjs.com/package/ngx-permissions
This package is very good for role based permission, You can set condition on routing level, component level or on individual element as well.
Can useable in template like below -
<ng-template ngxPermissionsOnly="ADMIN">
<div>You can see this text congrats</div>
</ng-template>
Compatible with all version of Angular (v2+)
I recommond to use an canActivate RoleGuardService.
import { Injectable } from '#angular/core';
import { AuthService } from './auth.service';
import { Router, ActivatedRouteSnapshot } from '#angular/router';
#Injectable({
providedIn: 'root'
})
export class RoleGuardService {
constructor(public auth: AuthService) {}
canActivate(route: ActivatedRouteSnapshot): boolean {
// Here only return true if only user have that permission or have that role
// Otherwise return false
// You can read data route.data.expectedRoles
return true;
}
}
In your app.routes.ts
export const ROUTES: Routes = [
{
path: 'dashboard',
canActivate: [RoleGuardService],
data: {
expectedRoles: ['Admin', 'HOD']
}
}
By this mechanism it prevents route changing if user doesn't have that access(Role or Permission)
And in your components also you can easily use this way
<div *ngIf="*** an condition to check your logged user have a role or privillage ***">
</div>
It is better to user have role with set of permissions
I want to show a snackbar when my login fails that says 'error connecting'. That much is simple. But then I would like it to try again either after 10 seconds when it is dismissed or after the action dismisses the snackbar. But my observable runs immediately and I am stuck in an infinite observable loop trying to login immediately after it has failed.
login.page.ts
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { UserService, HelpersService, AuthService } from '../../services/';
#Component({
selector: 'login-page',
templateUrl: './login.page.html',
styleUrls: ['./login.page.scss']
})
export class LoginPage {
loginError: any;
constructor(
private router: Router,
private auth: AuthService,
public helpers: HelpersService,
) { }
login() {
this.auth.login().then((response) => {
this.router.navigate(['/']);
}).catch(error => {
this.loginError = this.helpers.notify('error connecting', 'try again', 10000);
this.helpers.notifyAction(this.loginError, this.login());
});
};
}
helpers.service.ts
import { Injectable } from '#angular/core';
import { MdSnackBar, MdSnackBarRef } from '#angular/material';
#Injectable()
export class HelpersService {
constructor(public snackBar: MdSnackBar) {}
notify(message: string, action: string, duration: number) {
return this.snackBar.open(message, action, {duration});
}
notifyAction(notification: MdSnackBarRef<any>, next) {
return notification.onAction().subscribe(() => next);
}
}
You were almost there. Please pay attention to my comments in your sources.
login.page.ts
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { UserService, HelpersService, AuthService } from '../../services/';
#Component({
selector: 'login-page',
templateUrl: './login.page.html',
styleUrls: ['./login.page.scss']
})
export class LoginPage {
loginError: any;
constructor(
private router: Router,
private auth: AuthService,
public helpers: HelpersService,
) { }
login() {
this.auth.login().then((response) => {
this.router.navigate(['/']);
}).catch(error => {
this.loginError = this.helpers.notify('error connecting', 'try again', 10000);
this.helpers.notifyAction(this.loginError, this.login); // no parenthesis here!
});
};
}
helpers.service.ts
import { Injectable } from '#angular/core';
import { MdSnackBar, MdSnackBarRef } from '#angular/material';
#Injectable()
export class HelpersService {
constructor(public snackBar: MdSnackBar) {}
notify(message: string, action: string, duration: number) {
return this.snackBar.open(message, action, {duration});
}
notifyAction(notification: MdSnackBarRef<any>, next) {
return notification.onAction().subscribe(() => next()); // they are here!
}
}
Live Example Infinity Login
You need to pass function instead of calling it. And also take care about context by using arrow function or bind.
login.page.ts
this.helpers.notifyAction(this.loginError, () => this.login());
helpers.service.ts
notifyAction(notification: MdSnackBarRef<any>, next) {
notification.afterDismissed().subscribe(next);
return notification.onAction().subscribe(notification.dismiss);
}