要求
后台提供的接口,不能讓人隨便輸入個鏈接就能訪問,而是要加入一個token,token是動態的,每次訪問的時候判斷,有權限並且未過期的時候才可以訪問接口。
后台的設計是
在登錄的時候,首先要post提交一個請求,根據用戶名密碼,返回一個動態token,這個token會在服務器保存一段時間。在前端的其他接口請求的時候,都要在header中添加這個token,后台會進行驗證。只有驗證成功,才會返回對應的接口內容,否則會拋出401異常。
請求效果
首先使用postman查看正常請求的效果
第一次登錄請求時,添加了Header和Body以后,返回一個動態token,其結果如下:

服務器中保存了這個token值,然后再請求其他的get請求時,需要在Header中拼接這個token,才可以正常返回

添加token驗證
Ionic的使用的是httpclient 實現的請求,所有的請求被我寫到了一個公共的http-api.service.ts 里面去了
方法如下:
public access_token: string = ''; get<T>(endpoint: string, params?: any) { const headers = { headers: { 'Authorization': this.access_token } }; if (params) { if (!options) { options = {'params': params}; } else { options['params'] = params; } } return this.http.get<T>(this.url + '/' + endpoint, headers); }
在登錄的時候,先進行token驗證,並且將返回的驗證碼信息保存在http-api.service.ts 中
public firstPost(username: string, password: string) { const headers = { headers: { 'Authorization': 'Basic Y2xpZW50OnNlY3JldA==', 'Content-Type': 'application/x-www-form-urlencoded' } }; /*先token驗證,雖然是post請求,但是發現直接將參數寫到params 里面報錯,所以就直接寫到了url里面去了*/ this.httpApi.post('oauth/token?grant_type=password&username=' + username + '&password=' + password, null , headers).subscribe(val => { //返回值里,access_token代表生成的token驗證碼 if (val != null && val['access_token'] != null) { this.httpApi.access_token = 'Bearer ' + val['access_token']; } }, response => { let toast = this.toastCtrl.create({ message: '賬號或密碼錯誤', duration: 2000, position: 'bottom' }); toast.present(toast); }, () => { }); }
備注:這樣做的有一個缺點。因為把token值保存在service中,service是單例的,當service刷新的時候,這個token值就不存在了。而在angular中,網上說,刷新頁面,就會刷新service。所以每次刷新頁面,必須重新登錄生成新的token 值,否則就會報401錯誤。為了解決這個問題,只有想辦法把token值 保存在一個能夠永遠取到的地方了,比如 window.localStorage ,事實上這也是比較好的一個辦法。
window.localStorage.setItem('access_token', 'Bearer ' + val['access_token']);
實現token超時,返回登錄頁面功能
1、添加自定義攔截器custom.error.handler.ts,如果返回401錯誤,這調用一個監聽器方法,返回登錄頁(注意:a.這里Ionic 和 Angular是不一樣的;b.沒有@Injectable(),就沒法使用構造函數)
import {ErrorHandler, Injectable} from "@angular/core"; import {Events} from "ionic-angular"; @Injectable() export class MyErrorHandler implements ErrorHandler { constructor(private events: Events) { } handleError(err: any): void { if (err.status === 401) { this.events.publish('userCheck'); } // do something with the errorswitch (res.status) { } }
2、在app.module.ts 中添加引入
import {MyErrorHandler} from "./service/custom.error.handler"; ... providers: [ {provide: ErrorHandler, useClass: MyErrorHandler} ] ...
3、在一個Service 中添加一個全局變量,保證token超時只執行一次返回登錄頁方法
@Injectable() export class CommonService { /** * 全局變量,保證userCheck 監聽器方法,只執行一次 * @type {boolean} true可以執行, false不可以執行 */ public userCheckNum: boolean = true; ...
4、在tabs.ts文件中添加監聽器
ionViewDidLoad() { this.userCheckListenEvents(); } ionViewWillUnload() { this.events.unsubscribe('userCheck'); } userCheckListenEvents() { this.events.subscribe('userCheck', () => { if(this.commonService.userCheckNum){ this.commonService.userCheckNum = false; let loader = this.loadingCtrl.create({ content: "鏈接超時,正在返回登錄頁", duration: 3000 }); loader.present(); loader.onDidDismiss(() => { this.commonService.userCheckNum = true; this.nav.setRoot(LoginPage); }); } }); }
附錄
后台使用的是cuba platform 框架,cuba中關於token的設計是直接集成在登錄功能里面的,在web-app.properties 配置文件里面可以進行配置
如果添加 cuba.rest.anonymousEnabled = true ,那么任何人都可以訪問了,就沒有token驗證
如果有token驗證,可以添加下面的配置,設置過期時間,單位是秒
cuba.rest.client.tokenExpirationTimeSec=60
具體參考官網文檔:https://doc.cuba-platform.com/manual-6.8/rest_api_v2_ex_get_token.html
原創文章,歡迎轉載,轉載請注明出處!
