基于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;//sessionStoragefunction 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示例
原文地址:https://www.cnblogs.com/luangeng/p/9346553.html