目錄:
1.功能描述
2.客戶端的授權模式
3.授權模式認證流程
4.代碼實現
1.功能描述
- OAuth在"客戶端"與"服務提供商"之間,設置了一個授權層(authorization layer)。"客戶端"不能直接登錄"服務提供商",只能登錄授權層,以此將用戶與客戶端區分開來。
- "客戶端"登錄授權層所用的令牌(token),與用戶的密碼不同。用戶可以在登錄的時候,指定授權層令牌的權限范圍和有效期。
2.客戶端的授權模式
Oautho2.0為客戶端定義了4種授權模式:
- 授權碼模式
- 簡化模式
- 密碼模式
- 客戶端模式
授權碼模式是功能最完整、流程最嚴密的授權模式。它的特點就是通過客戶端的后台服務器,與"服務提供商"的認證服務器進行互動。
3.授權模式認證流程
授權碼模式的認證流程:
(A)用戶訪問客戶端,后者將前者導向認證服務器。
(B)用戶選擇是否給予客戶端授權。
(C)假設用戶給予授權,認證服務器首先生成一個授權碼,並返回給用戶,認證服務器將用戶導向客戶端事先指定的"重定向URI"(redirection URI),同時附上一個授權碼。
(D)客戶端收到授權碼,附上早先的"重定向URI",向認證服務器申請令牌。這一步是在客戶端的后台的服務器上完成的,對用戶不可見。
(E)認證服務器核對了授權碼和重定向URI,確認無誤后,向客戶端發送訪問令牌(access token)和更新令牌(refresh token)。
注意:(C)和(D)中兩個重定向URI是不一樣的,(C)中的重定向URI是用來核對的,這個是服務器事先指定並保存在數據庫里面。而(D)中的重定向URI指的是生成access_token的url。
4.代碼實現
1)定義客戶端信息,並保存在數據庫中
例如:
id:“app”, secret: 'xffcncgmveu6slxg', redirectUri: 'http://127.0.0.1:3000/example/auth/callback'
以上字段是必須的,如果還需要其他描述,可以自行添加字段。
2)判斷用戶是否登錄:
function ensureLogin(req,res,next){ //判斷用戶是否登錄
//這里假設用戶已經登錄,且默認如下
req.loginUserId = 'Along'; next(); }
3)生成授權碼代碼:
http://127.0.0.1:3000/OAuth2/authorize?client_id=a10086&response_type=code&redirect_uri=http%3A%2F%2F127.0.0.1%3A3000%2Fexample%2Fauth%2Fcallback
- response_type:表示授權類型,必選項,此處的值固定為"code"
- client_id:表示客戶端的ID,必選項
- redirect_uri:表示重定向URI,可選項
- scope:表示申請的權限范圍,可選項
- state:表示客戶端的當前狀態,可以指定任意值,認證服務器會原封不動地返回這個值。
生成授權碼的代碼如下:
授權碼的信息包括:授權碼、用戶的id、客戶端的id、重定向url
exports.generatorCode = function(req,res,next){ var code = randomString(20); //生成20長度字符串
var cdinfo = { code:code, userId:userId, clientId:clientId, redirectUri:redirectUri }; //存入數據庫
(new codeInfo(cdinfo)).save(function(err,doc){ if(err){ return callback(err); } }) callback(null, code); };
4)生成access_token:
服務器生成授權碼后,將授權碼添加到url后面,然后導向這個url如:
http://127.0.0.1:3000/example/auth/callback?code=Bu9C5OBmO2odzuWpVTpn
生成access_token的代碼如下:
access_token的信息包括:token、用戶id、客戶端id
exports.generateToken = function (userId, clientId,expires,callback) { var code = utils.randomString(20) + '.' + (getTimestamp() + expires); var tkinfo = { token:code, userId:userId, clientId:clientId }; (new tokenInfo(tkinfo)).save(function(err,doc){ if(err) return callback(err); callback(null,code); }) };
可以看到生成code和token的方式是一樣的,你也可以定義不一樣的方式。