如何在angular中自动获取新的JWT令牌和刷新令牌



我使用的是angular和asp.net core,我在
这篇文章的帮助下实现了JWT令牌和刷新令牌,我已经编写了代码来检查JWT在Authguard中是否有效,如果JWT无效,那么使用刷新令牌将调用api并获得新的JWT和刷新令牌。这种情况只发生在我执行任何事件,如刷新页面和导航到另一个页面。我想知道是否有任何方法,如果我们的jwt令牌过期没有执行任何事件角检测它,并自动调用api与刷新令牌,并获得新的jwt令牌

这里是代码

authguard

在authguard中isUserAuthenticated()将检查jwt是否过期如果过期,它将使用刷新令牌调用api并获得新的jwt和刷新令牌

async canActivate(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Promise<boolean> {
if((await this._authService.isUserAuthenticated()) === true){
return true;
}
else{
this._router.navigate([RouteConstant.SIGN_IN]);
return false;
}
}
public async isUserAuthenticated(){
if(this._storageService.getToken() !== null){
if(!this._jwtHelperService.isTokenExpired(this._storageService.getToken()?.toString())){
return true;
}
else{
if(!this._storageService.refreshTokenExists()){
return false;
}
else{
let authTokenClient: AuthTokenClient = {
token: this._storageService.getToken() as string,
refreshToken: this._storageService.getRefreshToken() as string
};
let response: AuthToken = await this._serverService.refreshAuthToken(authTokenClient).toPromise<AuthToken>();
console.log(response);
this.setAuth(response);
return !this._jwtHelperService.isTokenExpired(this._storageService.getToken()?.toString());
}
}
}
else{
return false;
}
}
}
public setAuth(authToken: AuthToken){
this._storageService.saveToken(authToken.token?.toString());
this._storageService.saveRefreshToken(authToken.refreshToken);
}
public async refreshAuthToken(authTokenClient: AuthTokenClient) {
const response = await this._http.post<AuthToken>(environment.apiHost + UrlConstant.ACCOUNT_REFRESH, authTokenClient,{observe: 'response'}).toPromise();
console.log(response);
const newToken = (<any>response).body.token;
console.log(newToken);
const newRefreshToken = (<any>response).body.refreshToken;
console.log(newRefreshToken);
localStorage.setItem("token", newToken);
localStorage.setItem("refreshToken",newRefreshToken);
if (newToken && newRefreshToken == null){
return false
}
else {
return true;
}
}

Startup.cs

services.AddAuthentication(opt =>
{
opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtSettings.ValidIssuer,
ValidAudience = jwtSettings.ValidAudience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration[ConfigurationKeyConstant.JWT_SECRET_KEY])),
ClockSkew = TimeSpan.Zero
};
});

Controller.cs

[Route("refresh")]
public IActionResult Refresh(AuthTokenBase authTokenBase)
{
if (authTokenBase is null)
{
return BadRequest("Invalid client request");
}
string accessToken = authTokenBase.Token;
string refreshToken = authTokenBase.RefreshToken;
var principal = this._jwtHandler.GetPrincipalFromExpiredToken(accessToken);
var username = principal.Identity.Name; 
string newAccessToken = this._jwtHandler.GenerateToken(); 
string newRefreshToken = this._jwtHandler.GenerateRefreshToken();
return Ok(new AuthToken()
{
Token = newAccessToken,
RefreshToken = newRefreshToken,
IsAuthSuccessful = true
});
}

您可以在service.AddAuthentication()的ConfigureServices下添加事件OnAuthenticationFailed。

检查异常类型,如果是SecurityTokenExpiredException,则设置响应头tokenExpired=true.

稍后在客户端检查响应头并根据tokenExpired值调用刷新令牌API。

伪代码:

services.AddAuthentication(opt =>
{
opt.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
opt.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtSettings.ValidIssuer,
ValidAudience = jwtSettings.ValidAudience,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration[ConfigurationKeyConstant.JWT_SECRET_KEY])),
ClockSkew = TimeSpan.Zero
};
options.Events = new JwtBearerEvents {
OnAuthenticationFailed = context => {
if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
{
context.Response.Headers.Add("IS-TOKEN-EXPIRED", "true");
}
return Task.CompletedTask;
}
};
});

在响应头中设置IS-TOKEN-EXPIRED真正为,如果令牌过期。要了解更多细节,你可以查看我写的这篇博客文章。

你可以使用angular拦截器。拦截http请求中的所有错误

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
var modifiedRequest = this.normalizeRequestHeaders(request);
return next.handle(modifiedRequest)
.pipe(
catchError(error => {
if (error instanceof HttpErrorResponse && error.status === 401) {
return this.tryGetRefreshTokenService(request, next, error);
} else {
return this.handleErrorResponse(error);
}
}),
switchMap((event) => {
return this.handleSuccessResponse(event);
})
);
}

最新更新