首页 文章

如何在角度4中使用刷新令牌

提问于
浏览
0

我已经完成了授权步骤并获得了Laravel Passport的访问令牌和刷新令牌 .

我的Angular前端和Laravel后端工作正常 .

我的主要问题是:

  • 我应该如何以及何时使用刷新令牌来制作新的访问令牌?

  • 这应该在后台完成还是用户必须单击按钮刷新令牌?

  • 创建新令牌时是否应重新加载Angular页面?

1 回答

  • 0

    我在我的角度项目中使用JWT身份验证,其中令牌由API设置 .

    令牌过期时我正在采取的方法,如下所述 -

    • 公开一个新的API,它将获取一个过期的令牌并返回新创建的令牌 .

    • API应检查每个REST API调用中的令牌过期 .

    • 如果令牌过期,API应返回一个状态(根据标准,498 - 过期/无效) .

    • 在angular中,创建一个服务层(令牌刷新),它将每个API调用委托给服务器(内部使用http服务) .

    • 此服务的作用是检查API响应的状态(如果它是498)并在内部进行额外调用以刷新令牌 .

    • 然后,服务可以使用新创建的令牌重新启动原始呼叫以获取响应 .

    • 所有api服务都会调用令牌刷新器来获取响应 .

    在更广泛的层面上,令牌刷新是默认http服务的包装器,它执行额外的检查 .

    这将避免恼人的页面加载并使应用程序更快 .

    编辑 - HTTP拦截器的示例

    import { Injectable } from "@angular/core";
    import { XHRBackend, RequestOptions, Request, RequestOptionsArgs, Response, Http, Headers } from "@angular/http";
    import { Store } from "@ngrx/store";
    import { Observable } from "rxjs/Rx";
    import { Observer } from "rxjs/Observer";
    import { Response as ApiResponse } from "../../models/base/response.model";
    import { ToastModel } from "../../redux/app-reducers";
    import { ReducerActions } from "../../redux/reducer-actions";
    
    @Injectable()
    export class HttpInterceptor extends Http {
        constructor(private _XHRBackend: XHRBackend,
            private _RequestOptions: RequestOptions,
            private _ToastStore: Store<ToastModel>,
            private _LoaderStore: Store<boolean>) {
            super(_XHRBackend, _RequestOptions);
        }
    
        public request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
            return this.handleResponse(super.request(url, options));
        }
    
        public get(url: string, options?: RequestOptionsArgs): Observable<Response> {
            this.beforeRequest(url);
            return super.get(url, this.getRequestOptionArgs(options));
        }
    
        public post(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
            this.beforeRequest(url, body);
            return super.post(url, body, this.getRequestOptionArgs(options));
        }
    
        public put(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
            this.beforeRequest(url, body);
            return super.put(url, body, this.getRequestOptionArgs(options));
        }
    
        public delete(url: string, options?: RequestOptionsArgs): Observable<Response> {
            this.beforeRequest(url);
            return super.delete(url, this.getRequestOptionArgs(options));
        }
    
        private getRequestOptionArgs(options?: RequestOptionsArgs): RequestOptionsArgs {
            if (options == null) {
                options = new RequestOptions();
            }
            if (options.headers == null) {
                options.headers = new Headers();
            }
            options.headers.append('Content-Type', 'application/json');
    
            return options;
        }
    
        private handleResponse(response: Observable<Response>): Observable<Response> {
            return response
                .catch(this.onCatch)
                .do(this.onSuccess.bind(this), this.onError.bind(this))
                .finally(this.afterResponse.bind(this));
        }
    
        private beforeRequest(url: string, body?: string): void {
            this._LoaderStore.dispatch({ type: ReducerActions.Loader.Set, payload: true });
        }
    
        private afterResponse(): void {
            this._LoaderStore.dispatch({ type: ReducerActions.Loader.Set, payload: false });
        }
    
        private onCatch(error: any, caught: Observable<Response>): Observable<Response> {
            console.log("interceptor catch called");
            return Observable.throw(error);
        }
    
        private onSuccess(res: Response): void {
            let response: ApiResponse<any> = res.json();
            if (!response.message) {
                return;
            }
            let toast: ToastModel = {
                text: response.message,
                duration: 5000,
                type: "success"
            };
            this._ToastStore.dispatch({ type: ReducerActions.Toast.Update, payload: toast });
        }
    
        private onError(error: any): void {
            let toast: ToastModel = {
                text: "Error occurred!",
                duration: 5000,
                type: "failure"
            };
            this._ToastStore.dispatch({ type: ReducerActions.Toast.Update, payload: toast });
        }
    }
    

    在上面的例子中, handleResponse 回调是执行任何操作的钩子 . (在这种情况下,令牌刷新API调用) .

    我希望这有帮助 . :)

相关问题