1. 程式人生 > >通過js和ajax獲取token及刷新token示例

通過js和ajax獲取token及刷新token示例

ssi ole func 存在 dom 可選 nbsp scope 網頁

基於Oauth2.0協議授權碼模式

授權碼模式工作流程:

(A)瀏覽器訪問該js客戶端,js將網頁重定向到認證服務器(/oauth/authorize),攜帶clientid等信息

(B)用戶選擇是否給予客戶端授權(可自動授權)

(C)認證服務器將瀏覽器重定向到"重定向URI"(redirection URI),同時附上一個授權碼

(D)瀏覽器拿到授權碼,附上早先的"重定向URI",向認證服務器申請令牌(/oauth/token)

(E)認證服務器核對了授權碼和重定向URI,向客戶端發送訪問令牌(access token)和更新令牌(refresh token)

A步驟中,客戶端申請認證的URI,包含以下參數:

  • response_type:表示授權類型,必選項,此處的值固定為"code"
  • client_id:表示客戶端的ID,必選項
  • redirect_uri:表示重定向URI,可選項
  • scope:表示申請的權限範圍,可選項
  • state:一般隨機生成,標識客戶端的當前狀態,認證服務器會原樣返回這個值,

通過JS ajax攔截器獲取token及刷新token示例,適用於前後端分離項目中前端的授權。

auth.js

const FULL_CHARTER = ‘ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopgrstuvwxyz‘;
const oauth_server
=‘http://localhost:9000/server‘; const redirect_uri=‘http://localhost:8002/client-front/‘; const client_id=‘demo‘; const client_secret=‘demo‘; const token_storage = localStorage;//sessionStorage function ajaxSetup() { $.ajaxSetup({ timeout : 30000, beforeSend : function(xhr) { if(this
.url.endsWith(‘/oauth/token‘)){ return true; } if (getAuth() == null){ fetchToken(); } var auth = getAuth(); if(auth != null){ xhr.setRequestHeader("Authorization", auth.token_type + ‘ ‘ + auth.access_token); } else { return false; } return true; }, complete : function(xhr, ts) { if (xhr.status == 401 && xhr.responseJSON.error ==‘invalid_token‘) { refreshToken(); } } }); } function getAuth(){ let auth = token_storage.getItem(‘auth‘); return JSON.parse(auth); } function saveAuth(sResponse){ token_storage.setItem("auth", JSON.stringify(sResponse)); } function clearAuth(){ token_storage.removeItem(‘auth‘); } function logout(){ token_storage.removeItem(‘auth‘); window.location.href = oauth_server+"/logout?redirect_uri="+redirect_uri; } function getCode(){ var state=‘‘; for (var a=0;a<6;a++){ state+=FULL_CHARTER[Math.floor(Math.random() * 52)]; } var url = oauth_server+"/oauth/authorize?client_id="+client_id+"&client_secret="+client_secret+ "&response_type=code&state="+state+"&redirect_uri="+redirect_uri; window.location = url; //window.open(url); } function fetchToken(){ let url = window.location.toString(); if(!url.includes(‘code‘)){ getCode(); } if(url.includes(‘code‘)) { let code=url.substr(url.indexOf(‘code=‘)+5,6); let state=url.substr(url.indexOf(‘state=‘)+6,6); var data={ ‘code‘:code, ‘state‘:state, ‘grant_type‘:‘authorization_code‘, ‘redirect_uri‘:redirect_uri }; $.ajax({ url: oauth_server+"/oauth/token", type:"post", data:data, async: false, contentType: ‘application/x-www-form-urlencoded‘, beforeSend:function(xhr){ xhr.setRequestHeader("Authorization", ‘Basic ‘ + Base64.encode(client_id+‘:‘+client_secret)); }, success: function (sResponse) { saveAuth(sResponse); console.log(‘fetch_token ok: ‘ + sResponse.access_token+‘ expires_in:‘+sResponse.expires_in); //window.location.href = redirect_uri; }, error:function(a,b,c){ console.log(a, b, c); } }); } } function refreshToken(){ var auth = getAuth(); var data={ ‘client_id‘: client_id, ‘client_secret‘: client_secret, ‘grant_type‘:‘refresh_token‘, ‘refresh_token‘:auth.refresh_token }; $.ajax({ url: oauth_server+"/oauth/token", type:"post", data:data, async: false, contentType: ‘application/x-www-form-urlencoded‘, success: function (sResponse) { saveAuth(sResponse); console.log(‘refresh_token ok: ‘ + sResponse.access_token+‘ expires_in:‘+sResponse.expires_in); }, error:function(a,b,c){ if (a.status==400 && a.responseJSON.error==‘invalid_grant‘){ console.log(‘refresh token invalid‘); clearAuth(); } } }); } function checkToken(){ $.ajax({ url: oauth_server+"/oauth/check_token", type:"get", async: false, data: {‘token‘: getAuth().access_token}, contentType: ‘application/x-www-form-urlencoded‘, success: function (sResponse) { console.log(‘check_token : ‘ + sResponse); }, error:function(a,b,c){ console.log(a.responseJSON); } }); } function getServerdata(){ $.get(oauth_server+"/msg", function(data) { $("#user").html(data); }); } $(function() { ajaxSetup(); });

---

其中使用了base64.js,界面如下,點擊GET Data按鈕將發送/msg請求到授權服務器獲取一段文本。

技術分享圖片

瀏覽器所有請求如下:

技術分享圖片

首先訪問/msg,返回401無權限,然後瀏覽器轉到/oauth/authorize去獲取code,然後授權服務器返回302重定向到授權登錄頁,用戶填寫用戶名密碼後post到/login,然後授權服務器重定向到rediret_url,末尾拼接了code,取出code,post發送/oauth/token請求,授權服務器返回token信息如下,並保存在LocalStorage中。

技術分享圖片

獲取token後/msg請求中攜帶token信息,bearer為token類型

技術分享圖片

由於是跨域請求數據,所以先發送的是OPTIONS請求,需要服務器支持跨域:

技術分享圖片

刷新token:

當服務器返回401,並且responseMsg為invalid_token時表示token已失效,post以下信息到/oauth/token,刷新token的失效時間

技術分享圖片

checktoken:需要服務器permitAll()該請求

登出:

授權服務器中的token:

技術分享圖片

end

通過js和ajax獲取token及刷新token示例