I have a problem in my angular project with the login component as it won't load the login page but instead it will show this:HTTP ERROR 401
When I try to log in using Postman, it works perfectly so I don't understand why does it have this behaviour since I don't get any error in the console or browser. login.component.ts:
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { LoginService } from '../services/login.service';
import { first } from 'rxjs/operators';
import {ToastrManager} from 'ng6-toastr-notifications';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
loginForm: FormGroup;
loading = false;
submitted = false;
constructor(private formBuilder: FormBuilder,
private route: ActivatedRoute,
private router: Router,
private loginService: LoginService,
public toast: ToastrManager, ) { }
ngOnInit() {
this.loginForm = this.formBuilder.group({
email: ['', Validators.required],
password: ['', Validators.required]
});
}
get loginFormControl() {return this.loginForm.controls; }
onSubmit() {
this.submitted = true;
if (this.loginForm.invalid) {
return;
}
this.loading = true;
this.loginService.login(this.loginFormControl.email.value, this.loginFormControl.password.value)
.pipe(first())
.subscribe(
() => {
this.toast.successToastr('Login succesfully');
this.router.navigate(['/']);
},
() => {
this.loading = false;
this.toast.errorToastr('Something went wrong');
this.loginForm.reset();
this.loginForm.setErrors({
invalidLogin: true
});
});
}
}
login.service.ts:
import { Injectable } from '@angular/core';
import {Register} from '../Models/register';
import { HttpClient, HttpHeaders, HttpErrorResponse} from '@angular/common/http';
import { BehaviorSubject, Observable, throwError } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { Router } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class LoginService {
httpOptions = { headers: new HttpHeaders(
{ 'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer',
})
};
userData = new BehaviorSubject<Register>(new Register());
ApiUrl = 'https://localhost:5001';
constructor(private http: HttpClient, public router: Router) {
}
login(email, password) {
return this.http.post<any>(this.ApiUrl + '/login/login', { email, password}, this.httpOptions
)
.pipe(map(response => {
localStorage.setItem('authToken', response.token);
this.setUserDetails();
return response;
}));
}
GetById(id) {
return this.http.post(this.ApiUrl + '/register/' + id , this.httpOptions);
}
doLogout() {
const removeToken = localStorage.removeItem('access_token');
if (removeToken == null) {
this.router.navigate(['/login']);
}
}
setUserDetails() {
if (localStorage.getItem('authToken')) {
const userDetails = new Register();
const decodeUserDetails = JSON.parse(window.atob(localStorage.getItem('authToken').split('.')[1]));
userDetails.email = decodeUserDetails.sub;
userDetails.name = decodeUserDetails.name;
userDetails.isLoggedIn = true;
userDetails.role = decodeUserDetails.role;
this.userData.next(userDetails);
}
}
handleError(error: HttpErrorResponse) {
let msg = '';
if (error.error instanceof ErrorEvent) {
msg = error.error.message;
} else {
msg = `Error Code: ${error.status}\nMessage: ${error.message}`;
}
return throwError(msg);
}
}
login.component.html:
<div class="col-md-6 offset-md-3 mt-5">
<div *ngIf="loginForm.errors?.invalidLogin" class="alert alert-danger mt-3 mb-0">
Email or Password is incorrect.
</div>
<div class="card">
<div class="card-body">
<form [formGroup]="loginForm" (ngSubmit)="onSubmit()">
<div class="form-group">
<label for="email">Email</label>
<input type="text" formControlName="email" class="form-control" autofocus
[ngClass]="{ 'is-invalid': submitted && loginFormControl.email.errors }" />
<div *ngIf="submitted && loginFormControl.email.errors" class="invalid-feedback">
<div *ngIf="loginFormControl.email.errors.required">Email is required</div>
</div>
</div>
<div class="form-group">
<label for="password">Password</label>
<input type="password" formControlName="password" class="form-control"
[ngClass]="{ 'is-invalid': submitted && loginFormControl.password.errors }" />
<div *ngIf="submitted && loginFormControl.password.errors" class="invalid-feedback">
<div *ngIf="loginFormControl.password.errors.required">Password is required</div>
</div>
</div>
<button [disabled]="loading" class="btn btn-primary">
<span *ngIf="loading" class="spinner-border spinner-border-sm mr-1"></span>
Login
</button>
</form>
</div>
</div>
</div>
LoginController.cs:
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using AnotherAP.Helpers;
using AnotherAP.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;
namespace AnotherAP.Controllers
{
[EnableCors("CorsPolicy")]
[Authorize]
[ApiController]
[Produces("application/json")]
[Route("[controller]")]
public class LoginController : ControllerBase
{
private readonly IConfiguration _config;
private readonly DataContext _context;
public LoginController(IConfiguration config,DataContext context)
{
_context = context;
_config = config;
}
[AllowAnonymous]
[HttpPost]
[Route("login")]
public IActionResult Login([FromBody] Register model)
{
IActionResult response = Unauthorized();
Register user = AuthenticateUser(model.Email,model.Password);
if (user != null)
{
var tokenString = GenerateJWT(user);
response = Ok(new
{
token = tokenString,
userDetails = user,
});
}
return response;
}
string GenerateJWT(Register user)
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:SecretKey"]));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub, user.Email),
new Claim("Name", user.Name.ToString()),
new Claim("role",user.Role),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
};
var token = new JwtSecurityToken(
issuer: _config["Jwt:Issuer"],
audience: _config["Jwt:Audience"],
claims: claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: credentials
);
return new JwtSecurityTokenHandler().WriteToken(token);
}
public Register AuthenticateUser(string email,string password)
{
if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(password))
return null;
var user = _context.register.FirstOrDefault(x => x.Email == email && x.Password==password);
if (user == null)
return null;
return user;
}
}
}
This behaviour started happening after I modified the code in the controller for AutheticateUser() by using the data context instead of list declaration. Before that it would not recognise the credentials but the page was properly displayed, instead it would not work with Postman.Now it returns 200 Ok with Postman, but the page will not load.Did anyone encounter a similar problem and might know the cause?Any help would be appreciated!Best regards!
What I have tried:
I have tried to set the headers locally in login.service.ts in login() method and declare the values email and password as strings.I also changed to a single value named user but without any luck as nothing changed.