Угловая ошибка 12 401 при обновлении страницы

#angular #frontend

Вопрос:

Я создаю форму входа в систему с помощью угловой загрузки 12 Spring(с базовой аутентификацией spring security). Когда пользователь войдет в систему, он будет перенаправлен на главную страницу, на которой есть действия CRUD, как показано ниже:

войти
Главная страница

Но, когда страница обновляется или перезагружается, она возвращается к этому (обратите внимание на консоль, она возвращает статус 401 несанкционированный, даже если я уже вошел в систему).:

error_console

Вот мой код из Angular

 import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { map } from 'rxjs/operators';
@Injectable({
  providedIn: 'root',
})
export class AuthService {
  USER_NAME_SESSION_ATTRIBUTE_NAME = 'authenticatedUser';

  public username: String = '';
  public password: String = '';

  constructor(private http: HttpClient) {}

  authenticationService(username: String, password: String) {
    return this.http
      .get(`http://localhost:8081/webapp/login/`, {
        headers: {
          Authorization: this.createBasicAuthToken(username, password),
        },
      })
      .pipe(
        map((res) => {
          this.username = username;
          this.password = password;
          this.registerSuccessfulLogin(username, password);
        })
      );
  }

  createBasicAuthToken(username: String, password: String) {
    return 'Basic '   window.btoa(username   ':'   password);
  }

  registerSuccessfulLogin(username: any, password: String) {
    sessionStorage.setItem(this.USER_NAME_SESSION_ATTRIBUTE_NAME, username);
  }

  isUserLoggedIn() {
    let user = sessionStorage.getItem(this.USER_NAME_SESSION_ATTRIBUTE_NAME);
    if (user === null) return false;
    return true;
  }

}
 

Перехватчик:

 import { Injectable } from '@angular/core';
import {
  HttpInterceptor,
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpHeaders,
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';
@Injectable({
  providedIn: 'root',
})
export class HttpinterceptorService implements HttpInterceptor {
  USER_NAME_SESSION_ATTRIBUTE_NAME = 'authenticatedUser';

  constructor(private authenticationService: AuthService) {}
  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    if (
      this.authenticationService.isUserLoggedIn() amp;amp;
      req.url.indexOf('basicauth') === -1
    ) {
      const authReq = req.clone({
        headers: new HttpHeaders({
          'Content-Type': 'application/json',
          Authorization: `Basic ${window.btoa(
            this.authenticationService.username  
              ':'  
              this.authenticationService.password
          )}`,
        }),
      });
      return next.handle(authReq);
    } else {
      return next.handle(req);
    }
  }
}
 

Ответ №1:

Проблема в вашем AuthService .

  1. Вы нигде не сохраняете пароль, когда пользователь успешно вошел в систему.
  2. А затем, когда вы перейдете к обновлению этой страницы, вы isUserLoggedIn найдете только username в хранилище сеансов [Плюс вы не обновляете оба username and password в AuthService ].

Таким intercepter образом, не находит ни username одного или password в this.authenticationService.username/password

  createBasicAuthToken(username: String, password: String) {
    return 'Basic '   window.btoa(username   ':'   password);
  }

  registerSuccessfulLogin(username: any, password: String) {
    // HERE ONLY username is stored
    sessionStorage.setItem(this.USER_NAME_SESSION_ATTRIBUTE_NAME, username);
  }

  isUserLoggedIn() {
    // HERE username and password for this service should be updated.
    let user = sessionStorage.getItem(this.USER_NAME_SESSION_ATTRIBUTE_NAME);
    if (user === null) return false;
    return true;
  }
 

Каким-то образом их хранение должно работать на вас, хотите ли вы хранить пароль просто или в зашифрованном формате-это ваш выбор.

Комментарии:

1. Я попытался ввести имя пользователя и пароль, скорее, я зашифровал их, используя базовую аутентификацию. Проверьте мой ответ ниже. Тем не менее, это не работает.

Ответ №2:

[РЕШЕНО]

Проблема: Когда страница перезагружается/обновляется после входа в систему/входа в систему, данные теряются и выдает статус 401 несанкционированный.

Причина: Учетные данные не сохраняются в сеансе при входе в систему, таким образом, страница обновления теряет учетные данные при входе в систему

Решение:

В AuthenticationService , пересмотрите registerSuccessfulLogin() , добавив это в тело:

   registerSuccessfulLogin(username: any, password: String) {
    let basicAuthToken = this.createBasicAuthToken(username, password);
    sessionStorage.setItem(
      this.USER_NAME_SESSION_ATTRIBUTE_NAME,
      basicAuthToken
    );
  }
 

Что было добавлено?

let basicAuthToken = this.createBasicAuthToken(username, password);

Это присваивает возвращаемое значение createBasicAuthToken(username, password) метода, который возвращает строку в кодировке basic64 ‘Basic : xxxxxxx’. Зачем вам включать оба учетных данных в кодировку? Потому что моя ошибка заключалась в том, что я кодировал только имя пользователя, а не оба учетных данных(которые также включают пароль). В sessionStorage.setItem(this.USER_NAME_SESSION_ATTRIBUTE_NAME,basicAuthToken); сохраненном значении теперь есть имя пользователя и пароль, зашифрованные в base64(не только имя пользователя, по сравнению с предыдущей версией).

Кроме того, в AuthenticationService класс входит следующий метод:

   getIt() {
    return sessionStorage.getItem(this.USER_NAME_SESSION_ATTRIBUTE_NAME);
  }
 

Подождите, для чего был предназначен этот метод? Он извлекает сохраненные данные из хранилища сеансов. Вам это понадобится, когда мы введем класс в класс перехватчика.

Далее, класс перехватчика. Ниже приведены изменения, внесенные по сравнению с предыдущим:

 import { Injectable, Injector } from '@angular/core';

export class HttpinterceptorService implements HttpInterceptor {

  constructor(
    private authenticationService: AuthService,
    private injector: Injector
  ) {}
  intercept(
    req: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    let authService = this.injector.get(AuthService);
    if (
      this.authenticationService.isUserLoggedIn() amp;amp;
      req.url.indexOf('basicauth') === -1
    ) {
      const authReq = req.clone({
        headers: new HttpHeaders({
          'Content-Type': 'application/json',
          Authorization: `${authService.getIt()}`,
        }),
      });
      return next.handle(authReq);
    } else {
      return next.handle(req);
    }
    console.log(this.intercept);
  }
}
 

Во-первых, импортируйте класс инжектора, он будет использоваться через некоторое время.

 constructor(private authenticationService: AuthService,private injector: Injector)
 

Внедрив службы аутентификации и службы инжекторов, мы теперь можем получить доступ к методам, которые мы будем использовать в наших перехватчиках.

 let authService = this.injector.get(AuthService);
 

Эта строка присваивает authService переменную экземпляру на основе предоставленного маркера ( AuthService ).

 Authorization: `${authService.getIt()}`
 

Теперь мы можем использовать переменную, содержащую экземпляр токена, в авторизации, используя приведенный выше код, в котором вызывается getIt() из нашего AuthenticationService класса, который возвращает зашифрованные учетные данные.

Таким образом, каждый раз, когда мы обновляемся после входа в систему, учетные данные сохраняются в сеансе и проверяются каждый раз, когда страница загружается и/или перезагружается. Учетные данные будут действительны только до тех пор, пока не будут прекращены серверные или интерфейсные службы или когда браузер или вкладка будут закрыты.