i have been working on a project as intern and is new to mean stack
this is the issue i am facing ,
i have been asked to create a login page that is done , but the catch is the login is authenticated by the company side . So basically in my login component the following logic is what i have implemented.
login.component.ts file’s component goes like the following
onSubmit(event) {
event.preventDefault()
console.log('value',this.loginForm.value)
if(this.errorMail.length === 0) {
this.loginService.login(this.loginForm.value).subscribe((res:any) => {
console.log('login response', res)
if(res.auth.success === true) {
localStorage.setItem('auth', JSON.stringify(res.auth))
this.loginService.loggedIn$.next(res.auth)
this.router.navigateByUrl('/search/list')
} else {
this.errorMail='Email or password is not valid'
}
})
}
the following is login.service.ts
import { Injectable } from '#angular/core';
import {HttpClient} from '#angular/common/http'
import { BehaviorSubject } from 'rxjs';
interface LoginResponse {
success: boolean
}
#Injectable({
providedIn: 'root'
})
export class LoginService {
constructor(private http: HttpClient) { }
loggedIn$ = new BehaviorSubject(null)
login(creds) {
// console.log('creds',creds)
return this.http.post<LoginResponse>('url-of-company', {creds})
}
and in my header component where i have the logout button :
the content of header.component.ts ;
import { Router } from '#angular/router';
import { Component, OnInit } from '#angular/core';
import { HeaderService } from './header.service';
#Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
constructor(public authService: HeaderService,public router:Router) { }
onLogout(){
this.authService.logout();
this.router.navigateByUrl('/');
}
the authService in above code is imported from header.service.ts and the header.service.ts goes like;
import { LoginService } from './../../login/login.service';
import { Injectable } from '#angular/core';
import {HttpClient} from '#angular/common/http'
import { Router } from '#angular/router';
interface LoginResponse {
success: boolean
}
export class HeaderService{
constructor(private router: Router,private http: HttpClient,private user:LoginService) {}
logout() {
this.http.delete<LoginResponse>('url-of-comapy');
this.router.navigate(['/']);
}
Basically i am trying to delete the authentication creds which i am getting from the url-of-company and is redirecting it to the login page
please help me with what is wrong an where i should do the correction and what to do for logout in my scenario .
I think what you need to do is delete the creds from localStorage not from the database which is what you are trying to do in the code above in logout() function.
You do not need the logout() function in authService and change your onLogout() function in header.component.ts to this:
onLogout(){
localStorage.removeItem('auth');
this.router.navigateByUrl('/login');
}
Related
I am a new coder with nestjs, I want to use passport-jwt , nestjs/passport and firebase to build my app's authetication part, below are my codes. But I just got http 401 response, how can i fix it ?
here is my strategy:
import { ExtractJwt, Strategy } from 'passport-jwt';
import { PassportStrategy } from '#nestjs/passport';
import { Injectable } from '#nestjs/common';
import { getAuth } from 'firebase-admin/auth';
#Injectable()
export class FirebaseStrategy extends PassportStrategy(Strategy, 'firebase') {
constructor() {
super({
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
ignoreExpiration: false,
secretOrKeyProvider: async (request, rawJwtToken, done) => {
try {
const decodedToken = await getAuth().verifyIdToken(rawJwtToken);
done(null, decodedToken);
} catch (error) {
done(error);
}
},
});
}
async validate(payload: any) {
console.log('validate');
return payload;
}
}
here is my guard:
import { Injectable } from '#nestjs/common';
import { AuthGuard } from '#nestjs/passport';
#Injectable()
export class FirebaseAuthGuard extends AuthGuard('firebase') {}
here is my auth.module.ts:
import { Module } from '#nestjs/common';
import { AuthService } from './auth.service';
import { UsersModule } from '../users/users.module';
import { PassportModule } from '#nestjs/passport';
import { JwtModule } from '#nestjs/jwt';
import { FirebaseStrategy } from './firebase.stragety';
import { AuthController } from './auth.controller';
#Module({
controllers: [AuthController],
imports: [UsersModule, PassportModule, JwtModule.register({})],
providers: [AuthService, FirebaseStrategy],
exports: [AuthService],
})
export class AuthModule {}
and here is my controller:
import { Controller, Get, Request, UseGuards } from '#nestjs/common';
import { AuthService } from './auth.service';
import { FirebaseAuthGuard } from './firebase.guard';
#Controller('auth')
export class AuthController {
constructor(private authService: AuthService) {}
#UseGuards(FirebaseAuthGuard)
#Get('login')
async logIn(#Request() req) {
return 'login';
}
}
I just found my validate method in FirebaseStrategy not invoked, it should be invoked everytime when secretOrKeyProvider verified jwt in http header, isn't it ?
If you're getting a 401 with no call of the validate method of your JwtStrategy that means that for some reason passport is reading the JWT you send as invalid. To find the specific reason for it you can modify your FirebaseAuthGuard to have the following handleRequest method, which will log out extra details
handleRequest(err, user, info, context, status) {
console.log({ err, user, info, context, status });
return super.handleRequest(err, user, info, context, status);
}
As mentioned, this will print out what error or info passport is reading and throwing for, and will allow you to properly adjust your JWT/know to refresh it/change it because of invalid signature/whatever else.
In Angular 13, I created basic CRUD app of employee. When i insert new data and hit submit it run the createEmployee() service and print data on console. Then it redirect to home page that shows all entry in table which call getEmployeeList(). But sometimes it shows newly created entry and sometimes it not shows. In database it perfectly entered. When i goto some other page and come back to home page it shows.
create-employee.components.ts
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { Employee } from 'src/app/employee';
import { EmployeeService } from 'src/app/Services/employee.service';
#Component({
selector: 'app-create-employee',
templateUrl: './create-employee.component.html',
styleUrls: ['./create-employee.component.css']
})
export class CreateEmployeeComponent implements OnInit {
employee: Employee = new Employee();
constructor(private employservice: EmployeeService,private router: Router) { }
ngOnInit(): void {
}
saveEmployee() {
this.employservice.createEmployee(this.employee).subscribe(data => {
console.log(data);
})
console.error();
}
gotoemployeelist() {
this.router.navigate(['employees']);
}
onSubmit() {
this.saveEmployee();
this.gotoemployeelist();
}
}
employee-service.ts
import { HttpClient } from '#angular/common/http';
import { Injectable } from '#angular/core';
import { map, Observable } from 'rxjs';
import { Employee } from '../employee';
#Injectable({
providedIn: 'root'
})
export class EmployeeService {
public baseURL="http://localhost:8080/api/v1/employees";
constructor(private httpClient: HttpClient) {}
getEmployeeList(): Observable<Employee[]> {
return this.httpClient.get<Employee[]>(this.baseURL).pipe(
map(employees => {
for(let employee of employees) {
employee.bdate = new Date(employee.bdate);
employee.jdate = new Date(employee.jdate);
}
console.log("Employees Service: GetEmployee() called");
return employees;
}));
}
createEmployee(employee: Employee): Observable<Object> {
console.log("Employees Service: CreateEmployee() called");
return this.httpClient.post(this.baseURL,employee);
}
getEmployeebyId(id: Number): Observable<Employee> {
console.log("Employees Service: GetEmployeeById() called");
return this.httpClient.get<Employee>(this.baseURL+"/"+id);
}
updateEmployee(employee: Employee,id: number): Observable<Object> {
console.log("Employees Service: UpdateEmployee() called");
console.log(employee);
return this.httpClient.put(this.baseURL+"/"+id,employee);
}
deleteEmployee(id: number): Observable<Object> {
console.log("Employees Service: DeleteEmployee() called");
return this.httpClient.delete(this.baseURL+"/"+id);
}
}
Home-component.ts
import { Component, OnInit } from '#angular/core';
import { Router } from '#angular/router';
import { Employee } from 'src/app/employee';
import { EmployeeService } from 'src/app/Services/employee.service';
#Component({
selector: 'app-employee-list',
templateUrl: './employee-list.component.html',
styleUrls: ['./employee-list.component.css',]
})
export class EmployeeListComponent implements OnInit {
employees: Employee[];
constructor(private employeeservice: EmployeeService,private router: Router) {
}
ngOnInit(): void {
this.getEmployees();
}
private getEmployees() {
this.employeeservice.getEmployeeList().subscribe(data => {
console.log(data);
this.employees=data;
});
}
updateEmployee(id: Number) {
this.router.navigate(['update-employee',id]);
}
deleteEmployee(id: number) {
this.employeeservice.deleteEmployee(id).subscribe(data => {
console.log(id+"employeed Deleted.");
this.getEmployees();
});
}
employeeDetails(id: number) {
this.router.navigate(['emloyee-details',id]);
}
}
In console you can see that createEmployee() called then GetEmployee() called and then it print console.log(newEntry) after navigation.
What is happening program is not waiting to complete createEmployee API before navigating to the home page. You need to call gotoemployeelist() only after the you get response from createEmployee API. You can do this by calling the method inside the subscribe
saveEmployee() {
this.employservice.createEmployee(this.employee).subscribe(data => {
console.log(data);
this.gotoemployeelist();
})
console.error();
}
gotoemployeelist() {
this.router.navigate(['employees']);
}
onSubmit() {
this.saveEmployee();
}
I use two pages with login and crud operations in my project. I need some help. I want to check user login first and redirect to login page if not logged. There are crud operations after the user logs in. Whichever user logs in, only the products added by them will appear. How can I do that? I used node js on backend.
this is login.component.ts
import { Component, OnInit } from '#angular/core';
import { FormBuilder, Validators, FormGroup, FormControl } from '#angular/forms';
import { ActivatedRoute, Router } from '#angular/router';
import { HttpClient } from '#angular/common/http';
import { LoginService } from '../shared/login.service';
#Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
loginForm: FormGroup;
username = new FormControl('');
password = new FormControl('');
constructor(
private http: HttpClient,
private authService: LoginService,
private formBuilder: FormBuilder,
private _router: Router) { }
ngOnInit() {
this.loginForm = this.formBuilder.group({
username: ['', Validators.required],
password: ['', Validators.required]
});
}
get f() { return this.loginForm.controls; }
loginSubmit() {
this.http.post("http://localhost:3000/login", { username: this.username.value, password: this.password.value })
.subscribe(result => {
debugger;
if(result.result){
this._router.navigate(["/payment"]);
// sessionstorage
}else{
alert("Bilgiler yanlış");
}
}, error => {
alert('hata oluştur');
});
}
}
and this is login.service.ts
import { loginDetail } from './login.model';
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from "#angular/common/http";
import { Router } from '#angular/router';
#Injectable({
providedIn: 'root'
})
export class LoginService {
//private readonly mockedUser = new SignInData()
isAuthenticated = false;
loginFormData: loginDetail= {
username: null,
password: null,
user_id: null
};
list : loginDetail[];
readonly rootURL = 'http://localhost:5000/api';
readonly rootURLnode = 'http://localhost:3000/';
constructor(private http: HttpClient, private router: Router) { }
login() {
//debugger;
//console.log(this.loginFormData)
this.isAuthenticated = true;
this.router.navigate(['payment-details']);
return this.http.post(this.rootURLnode + 'payment-details', this.loginFormData);
}
}
Use a route guard to check if the user is authenticated or not. Below you can find an example:
#Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private _authService: AuthService, private _router: Router) {}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
const url: string = state.url;
return this.checkLogin(url);
}
checkLogin(url: string): boolean {
if (this._authService. isAuthenticated) {
return true;
}
// Store the attempted URL for redirecting
this._authService.redirectUrl = url;
// Navigate to the login page
this.router.navigate(['/login']);
return false;
}
}
You can use it in the routing module like so:
const routes: Routes = [
{
path: '',
loadChildren: () => import('.home/home.module').then((m) => m.HomeModule),
canActivate: [AuthGuard]
}
];
Your login method should be like this:
login() {
return this.http.post(this.rootURLnode + 'payment-details',
this.loginFormData).pipe(
tap(() => {
// you need to do this only for the success case
this.isAuthenticated = true;
this.router.navigate(['payment-details']);
})
}
}
I recommend you to go through the tutorial from the Angular docs https://angular.io/guide/router-tutorial
In my angular application i have used login and logout concept by MEAN(mongo,Express,Angular,Node).
After login within few min if i reload the page automatically going to login page.Token is there but it is redirecting to login page.I do not know why it is happening like this.Below given my code.
auth.guard.ts:
import { Injectable } from '#angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot } from
'#angular/router';
import { Observable } from 'rxjs';
import { UserService } from "../shared/user.service";
import { Router } from "#angular/router";
#Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private userService : UserService,private router : Router){}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): boolean {
if (!this.userService.isLoggedIn()) {
this.router.navigateByUrl('/login');
this.userService.deleteToken();
return false;
}
return true;
}
}
user.service.ts:
getToken() {
return localStorage.getItem('usertoken');
}
setToken(token: string) {
localStorage.setItem('token', token);
}
getToken() {
return localStorage.getItem('token');
}
deleteToken() {
localStorage.removeItem('token');
}
getUserPayload() {
var token = this.getToken();
if (token) {
var userPayload = atob(token.split('.')[1]);
return JSON.parse(userPayload);
}
else
return null;
}
isLoggedIn() {
var userPayload = this.getUserPayload();
if (userPayload)
return userPayload.exp > Date.now() / 1000;
else
return false;
}
After logged within 2 or 3 min if i refresh the page getting err.error.auth is false.Why it is happening like this?
auth.intercepter.ts:
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from "#angular/common/http";
import { Injectable } from '#angular/core';
import { tap } from 'rxjs/operators';
import { Router } from "#angular/router";
import { UserService } from "../shared/user.service";
#Injectable()
export class UserAuthInterceptor implements HttpInterceptor {
constructor(private userService : UserService,private router : Router){}
intercept(req: HttpRequest<any>, next: HttpHandler) {
if (req.headers.get('noauth'))
return next.handle(req.clone());
else {
const clonedreq = req.clone({
headers: req.headers.set("Authorization", "Bearer " + this.userService.getToken())
});
return next.handle(clonedreq).pipe(
tap(
event => { },
err => {
if (err.error.auth == false) {
this.router.navigateByUrl('/login'); //After login within 2 or 3 min if i refresh or reload the page this is working.I do not know why this is calling on reload the page
}
})
);
}
}
}
Service.ts code
import { Injectable } from '#angular/core';
import { HttpClient } from '#angular/common/http';
#Injectable({
providedIn: 'root'
})
export class ClientService {
constructor(private http: HttpClient) { }
getClients() {
return this.http.get<any>('http://localhost:8080/admin-api/client?count=15&page=0&q=', { withCredentials: true })
}
}
Component.ts code
import { Component, OnInit } from '#angular/core';
import { LazyLoadEvent } from 'primeng/api'
import { ClientService } from '../../services/client.service';
#Component({
selector: 'app-client',
templateUrl: './client.component.html',
styleUrls: ['./client.component.css']
})
export class ClientComponent implements OnInit {
constructor(private clientService: ClientService) { }
ngOnInit() {
this.loading = true
this.clientService.getClients().subscribe(data => {
console.log(data)
}, error => {
console.log(error)
})
}
}
The error I get when I run this
I don't understand why the same request can succeed using axios but not with the HttpClient in Angular.
Apparently, Axios adds the "X-XSRF-TOKEN" header when it detects the "XSRF-TOKEN" cookie whereas the HttpClient in Angular doesn't.
So you have to read the value of the "XSRF-TOKEN" cookie and set it as the header "X-XSRF-TOKEN" when sending your requests.