[英]token jwt work with spring boot but with angular there are error
[英]Angular + Spring boot Jwt refresh token feature
我创建了一个刷新令牌功能来保护我网站中的 Jwt 身份验证。 但是有一个问题,jwt 令牌会随着它过期而被刷新多次,直到用户决定注销为止。 我决定让刷新令牌在一段时间内过期,让用户定期登录。
当这样的令牌过期时,除了在春季抛出 500 异常之外,我想不出任何办法。 稍后,Angular 中的令牌拦截器将其捕获并注销。 但是,此代码有效,但我怀疑我的实现效果不佳。 你能给我一些建议如何改进我的代码以使其更干净吗?
这是我的代码(Spring):
验证控制器.java
@PostMapping("/refresh/token")
public ResponseEntity<AuthenticationResponse> refreshTokens(@Valid @RequestBody RefreshTokenRequest refreshTokenRequest) throws Exception {
return ResponseEntity.status(HttpStatus.OK).body(authService.refreshToken(refreshTokenRequest));
}
验证服务.java
public AuthenticationResponse refreshToken(RefreshTokenRequest refreshTokenRequest) throws Exception {
var authenticationResponse = new AuthenticationResponse();
if(refreshTokenService.validateRefreshToken(refreshTokenRequest.getRefreshToken())){
String token = jwtUtil.generateToken(refreshTokenRequest.getUserName());
authenticationResponse.setAuthenticationToken(token);
authenticationResponse.setRefreshToken(refreshTokenRequest.getRefreshToken());
authenticationResponse.setUserName(refreshTokenRequest.getUserName());
} else {
throw new Exception("Refresh Token has expired");
}
return authenticationResponse;
}
刷新令牌服务.java
boolean validateRefreshToken(String token){
System.out.println("refreshtoken name: " + refreshTokenRepository.findByToken(token));
RefreshToken refreshToken = refreshTokenRepository.findByToken(token)
.orElseThrow(() -> new ResourceNotFoundException("The Refresh Token hasn't been found"));
long dateCreated = refreshToken.getCreatedDate().toEpochMilli();
if(Instant.now().toEpochMilli() - dateCreated > 160000){
return false;
}
return true;
}
(角度代码)
令牌拦截器.ts
export class TokenInterceptor implements HttpInterceptor {
isTokenRefreshing = false;
refreshTokenSubject: BehaviorSubject<any> = new BehaviorSubject(null);
constructor(public authService: AuthService, private router: Router){}
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (req.url.indexOf('refresh') !== -1 || req.url.indexOf('login') !== -1) {
return next.handle(req);
}
const jwtToken = this.authService.getJwtToken();
if(jwtToken){
return next.handle(this.addToken(req, jwtToken)).pipe(catchError(error => {
if(error instanceof HttpErrorResponse && error.status === 403) {
return this.handleAuthErrors(req, next);
} else {
return throwError(error);
}
}));
}
return next.handle(req);
}
private handleAuthErrors(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (!this.isTokenRefreshing){
this.isTokenRefreshing = true;
this.refreshTokenSubject.next(null);
return this.authService.refreshToken().pipe(
switchMap((refreshTokenResponse: AuthenticationResponse) => {
this.isTokenRefreshing = false;
this.refreshTokenSubject
.next(refreshTokenResponse.authenticationToken);
return next.handle(this.addToken(req, refreshTokenResponse.authenticationToken));
}), catchError(error => {
if(error instanceof HttpErrorResponse && error.status === 500) {
this.isTokenRefreshing = false;
this.authService.logout();
this.router.navigateByUrl('/login');
return of(null);
} else {
return throwError(error);
}
})
)
} else {
return this.refreshTokenSubject.pipe(
filter(result => result !== null),
take(1),
switchMap((res) => {
return next.handle(this.addToken(req, this.authService.getJwtToken()))
})
)
}
}
addToken(req: HttpRequest<any>, jwtToken: any) {
return req.clone({
headers: req.headers.set('Authorization', 'Bearer '+ jwtToken)
});
}
}
auth-service.ts
导出类 AuthService {
@Output() loggedIn: EventEmitter<boolean> = new EventEmitter();
@Output() username: EventEmitter<string> = new EventEmitter();
loginUrl='http://localhost:8080/api/auth/login';
logoutUrl='http://localhost:8080/api/auth/logout';
refreshTokenUrl='http://localhost:8080/api/auth/refresh/token';
refreshTokenRequest = {
refreshToken: this.getRefreshToken(),
userName: this.getUserName()
}
constructor(private http: HttpClient, private localStorage: LocalStorageService) { }
login(loginRequest: LoginRequest): Observable<boolean>{
return this.http.post<AuthenticationResponse>(this.loginUrl, loginRequest).pipe(
map(
data => {
this.localStorage.store('authenticationToken', data.authenticationToken);
this.localStorage.store('userName', data.userName);
this.localStorage.store('refreshToken', data.refreshToken);
this.loggedIn.emit(true);
this.username.emit(data.userName);
console.log('Login successful')
console.log("Token: " + this.localStorage.retrieve('authenticationToken'))
console.log("Token: " + this.localStorage.retrieve('userName'))
return true;
}
)
)
}
logout(){
this.http.post(this.logoutUrl, this.refreshTokenRequest, {responseType: 'text'})
.subscribe(data => {
console.log(data);
}, error => {
throwError(error)
}
)
this.localStorage.clear('refreshToken');
this.localStorage.clear('userName');
this.localStorage.clear('authenticationToken');
this.loggedIn.emit(false);
console.log("logout completed");
console.log(this.localStorage.retrieve('refreshToken'))
}
refreshToken(){
return this.http.post<AuthenticationResponse>(this.refreshTokenUrl, this.refreshTokenRequest)
.pipe(
tap(
response => {
this.localStorage.clear('authenticationToken');
this.localStorage.store('authenticationToken', response.authenticationToken);
console.log("Token has been refreshed")
console.log(this.localStorage.retrieve('authenticationToken'))
}, error => {
throwError(error)
}
)
)
}
getJwtToken(){
return this.localStorage.retrieve('authenticationToken');
}
getUserName(){
return this.localStorage.retrieve('userName');
}
getRefreshToken() {
return this.localStorage.retrieve('refreshToken');
}
isLoggedIn(): boolean {
return this.getJwtToken() != null;
}
}
谢谢!
jwt 令牌过期的那一刻,您的刷新方法将抛出状态 500
解决这个问题
还可以捕获 ExpiredJwtException 并强制进行令牌刷新,但我还没有尝试过
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.