#angular #frontend
Вопрос:
Я создаю форму входа в систему с помощью угловой загрузки 12 Spring(с базовой аутентификацией spring security). Когда пользователь войдет в систему, он будет перенаправлен на главную страницу, на которой есть действия CRUD, как показано ниже:
Но, когда страница обновляется или перезагружается, она возвращается к этому (обратите внимание на консоль, она возвращает статус 401 несанкционированный, даже если я уже вошел в систему).:
Вот мой код из 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
.
- Вы нигде не сохраняете пароль, когда пользователь успешно вошел в систему.
- А затем, когда вы перейдете к обновлению этой страницы, вы
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
класса, который возвращает зашифрованные учетные данные.
Таким образом, каждый раз, когда мы обновляемся после входа в систему, учетные данные сохраняются в сеансе и проверяются каждый раз, когда страница загружается и/или перезагружается. Учетные данные будут действительны только до тех пор, пока не будут прекращены серверные или интерфейсные службы или когда браузер или вкладка будут закрыты.