Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/31.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/spring/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/video/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular 角度+;Spring boot Jwt刷新令牌功能_Angular_Spring_Jwt_Refresh Token - Fatal编程技术网

Angular 角度+;Spring boot Jwt刷新令牌功能

Angular 角度+;Spring boot Jwt刷新令牌功能,angular,spring,jwt,refresh-token,Angular,Spring,Jwt,Refresh Token,我在我的网站上创建了一个刷新令牌功能来保护Jwt身份验证。但有一个问题,jwt令牌被刷新的次数和它过期的次数一样多,直到用户决定注销。我决定让刷新令牌在一段时间内过期,以便让用户定期登录 在春季,当这样一个令牌过期时,我只能抛出一个500异常。稍后,Angular中的令牌拦截器将其捕获并注销。然而,这段代码可以工作,但我怀疑我的实现不是很好。你能给我一个建议,如何改进我的代码,使它更干净 这是我的代码(Spring): AuthController.java @PostMapping(&quo

我在我的网站上创建了一个刷新令牌功能来保护Jwt身份验证。但有一个问题,jwt令牌被刷新的次数和它过期的次数一样多,直到用户决定注销。我决定让刷新令牌在一段时间内过期,以便让用户定期登录

在春季,当这样一个令牌过期时,我只能抛出一个500异常。稍后,Angular中的令牌拦截器将其捕获并注销。然而,这段代码可以工作,但我怀疑我的实现不是很好。你能给我一个建议,如何改进我的代码,使它更干净

这是我的代码(Spring):

AuthController.java

 @PostMapping("/refresh/token")
    public ResponseEntity<AuthenticationResponse> refreshTokens(@Valid @RequestBody RefreshTokenRequest refreshTokenRequest) throws Exception {
        return ResponseEntity.status(HttpStatus.OK).body(authService.refreshToken(refreshTokenRequest));
    }
RefreshTokenService.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;
    }
 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;
    }
(角度代码)

令牌拦截器

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)
        });
    }
}
导出类令牌拦截器实现HttpInterceptor{
Istoken=假;
refreshTokenSubject:BehaviorSubject=新的BehaviorSubject(null);
构造函数(公共authService:authService,专用路由器:路由器){}
截取(req:HttpRequest,next:HttpHandler):可观察{
if(请求url.indexOf('refresh')!=-1 | |请求url.indexOf('login')!=-1){
返回next.handle(req);
}
const jwtToken=this.authService.getJwtToken();
if(jwtToken){
返回next.handle(this.addToken(req,jwtToken)).pipe(catchError(error=>{
if(HttpErrorResponse的错误实例&&error.status==403){
返回此.handleAuthErrors(请求,下一步);
}否则{
返回投掷器(错误);
}
}));
}
返回next.handle(req);
}
私有handleAuthErrors(req:HttpRequest,next:HttpHandler):可观察{
如果(!this.istoken){
this.istokenreshing=true;
this.refreshTokenSubject.next(null);
返回此.authService.refreshToken()管道(
switchMap((refreshTokenResponse:AuthenticationResponse)=>{
this.istokenreshing=false;
这是一个重要的主题
.next(refreshTokenResponse.authenticationToken);
返回next.handle(this.addToken(req,refreshtTokenResponse.authenticationToken));
}),catchError(错误=>{
if(HttpErrorResponse的错误实例&&error.status==500){
this.istokenreshing=false;
this.authService.logout();
this.router.navigateByUrl('/login');
返回(空);
}否则{
返回投掷器(错误);
}
})
) 
}否则{
返回此.refreshTokenSubject.pipe(
过滤器(结果=>result!==null),
以(1)为例,
开关图((分辨率)=>{
返回next.handle(this.addToken(req,this.authService.getJwtToken()))
})
)
}
}
addToken(请求:HttpRequest,jwtToken:any){
返回请求克隆({
headers:req.headers.set('Authorization','Bearer'+jwtToken)
});
}
}
auth-service.ts

导出类身份验证服务{

  @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;
  }

}
@Output()loggedIn:EventEmitter=neweventemitter();
@Output()用户名:EventEmitter=neweventemitter();
罗吉努尔酒店http://localhost:8080/api/auth/login';
注销URL=http://localhost:8080/api/auth/logout';
刷新令牌URL=http://localhost:8080/api/auth/refresh/token';
刷新令牌请求={
refreshToken:this.getRefreshToken(),
用户名:this.getUserName()
}
构造函数(私有http:HttpClient,私有localStorage:LocalStorageService){}
登录(loginRequest:loginRequest):可观察{
返回this.http.post(this.loginUrl,loginRequest).pipe(
地图(
数据=>{
this.localStorage.store('authenticationToken',data.authenticationToken);
this.localStorage.store('userName',data.userName);
this.localStorage.store('refreshttoken',data.refreshttoken);
this.loggedIn.emit(true);
this.username.emit(data.username);
console.log('登录成功')
console.log(“令牌:+this.localStorage.retrieve('authenticationToken'))
log(“令牌:+this.localStorage.retrieve('userName'))
返回true;
}
)
)
}
注销(){
this.http.post(this.logoutUrl,this.refreshtTokenRequest,{responseType:'text'})
.订阅(数据=>{
控制台日志(数据);
},错误=>{
投掷者(错误)
}
)
this.localStorage.clear('refreshttoken');
这个.localStorage.clear('userName');
this.localStorage.clear('authenticationToken');
this.loggedIn.emit(false);
控制台日志(“注销完成”);
console.log(this.localStorage.retrieve('refreshtToken'))
}
刷新令牌(){
返回this.http.post(this.refreshtTokenURL,this.refreshtTokenRequest)
.烟斗(
水龙头(
响应=>{
this.localStorage.clear('authenticationToken');
this.localStorage.store('authenticationToken',response.authenticationToken);
日志(“令牌已刷新”)
console.log(this.localStorage.retrieve('authenticationToken'))
},错误=>{
投掷者(错误)
}
)
)
}
getJwtToken(){
返回此.localStorage.retrieve('authenticationToken');
}
getUserName(){
返回this.localStorage.retrieve('userName');
}
getRefreshToken(){
返回this.localStorage.retrieve('refreshToken');
}
isLoggedIn():布尔值{
返回此。getJwtToken()!=null;
}
}

谢谢大家!

jwt令牌到期时,刷新方法将抛出状态500

要解决这个问题

  • 当令牌过期时,使登录会话无效,这将导致