开放平台统一OAuth认证的实现

原文链接:http://www.touchsunlight.com/coding/66.html

话说现在互联网是越来越开放,各大互联网巨头都推出了自己的开放平台,虽然都是基于OAuth2.0的,但毕竟还是有点区别。本文讨论,抽象OAuth2.0的共性,实现一个比较合理的统一。

1.OAuth简介

OAuth为客户端提供了一种代表资源拥有者访问受保护资源的方法。在客户端访问受保护资源之前,它必须先从资源拥有者获取授权(访问许可),然后用访问许可交换访问令牌(代表许可的作用域、持续时间和其它属性)。客户端通过向资源服务器出示访问令牌来访问受保护资源。

2.OAuth原理

访问令牌提供了一个抽象层,将不同的授权结构(如用户名密码、断言)替换成资源服务器可以理解的单一令牌。这种抽象使得分发短期有效的访问令牌成为可能,也使得资源服务器不必理解多种多样的授权机制。

 

上图所示的抽象流程协议的总体架构,它包含下列步骤:
(A) 客户端从资源拥有者那里请求授权。授权请求能够直接发送给资源拥有者,或者间接地通过授权服务器这样的中介,而后者更为可取。
(B) 客户端收到一个访问许可,它代表由资源服务器提供的授权。
(C) 客户端使用它自己的私有证书到授权服务器上验证,并出示访问许可,来请求一个访问令牌。
(D) 授权服务器验证客户端私有证书和访问许可的有效性,如果验证通过则分发一个访问令牌。
(E) 客户端通过出示访问令牌向资源服务器请求受保护资源。
(F) 资源服务器验证访问令牌的有效性,如果验证通过则响应这个资源请求。

3.OAuth统一认证架构

(A)架构类图

(B)类图说明

l  OAuthConfig:配置类,定义了OAuth的公共配置,以便继承和扩展。
l  OAuthToken对应于AccessToken的实体类,定义了OAuth的AccessToken的公共属性,用来序列化,可以继承和扩展。
l  OAuthCore:核心类,定义了OAuth认证的公共核心方法,部分方法由于平台差异,定义为抽象方法,可以实现和覆盖。
l  OAuthService:服务接口类,定义了OAuth服务接口,调用Core接口实现功能,可以覆盖和扩展。

4.OAuthConfig

1 public string ApiUrl { getprivate set; }          // API服务地址
2 public string AuthUrl { getprivate set; }         // 授权服务地址
3 public string ClientID { getprivate set; }        // 应用ID
4 public string TokenUrl { getprivate set; }        // Token服务地址
5 public string SessionUrl { getprivate set; }      // Session服务地址
6 public string RedirectUri { getprivate set; }     // 回调重定向地址
7 public string ClientSecret { getprivate set; }    // 应用Secret

5.OAuthToken

1 [JsonProperty("Expires_In")]
2 public long ExpiresIn { getset; }         // 过期时间
3 [JsonProperty("Access_Token")]
4 public string AccessToken { getset; }     // AccessToken

备注:
(A)这里抽象的Token是QQ、Sina、人人所公共的部分,可以继承扩展。
(B)JsonProperty特性是为了调用Json的序列化,直接反序列化对象

6.OAuthCore

(A)原型

01 abstract class OAuthCore<config, token="">
02     where Config : OAuthConfig
03     where Token : OAuthToken
04 {
05     protected Config config;
06     public OAuthCore(Config config)
07     {
08         this.config = config;
09     }
10 }
11 </config,>

备注:使用泛型,很好地解决了Config和Token由于继承关系需要的强制类型转换。

(B)继承的方法

01 // 根据授权码获得AccessToken
02 protected string GetAccessTokenByCode(string code)
03 {
04     try
05     {
06         OAuthParams paramz = new OAuthParams();
07         paramz.Add("grant_type""authorization_code");
08         paramz.Add("code", code);
09         paramz.Add("client_id", config.ClientID);
10         paramz.Add("client_secret", config.ClientSecret);
11         paramz.Add("redirect_uri", config.RedirectUri);
12  
13         string queryString = HttpUtil.GetQueryString(paramz);
14         string content = Common.HttpRequest.DoPost(config.TokenUrl, queryString);
15  
16         return content;
17     }
18     catch
19     {
20         return null;
21     }
22 }
23  
24 // 根据用户名和密码获得AccessToken
25 protected string GetAccessTokenByUser(string username, stringpassword)
26 {
27     try
28     {
29         OAuthParams paramz = new OAuthParams();
30         paramz.Add("grant_type""password");
31         paramz.Add("username", username);
32         paramz.Add("password", password);
33         paramz.Add("client_id", config.ClientID);
34         paramz.Add("client_secret", config.ClientSecret);
35         paramz.Add("redirect_uri", config.RedirectUri);
36  
37         string queryString = HttpUtil.GetQueryString(paramz);
38         string content = Common.HttpRequest.DoPost(config.TokenUrl, queryString);
39  
40         return content;
41     }
42     catch
43     {
44         return null;
45     }
46 }
47 // 调用API
48 protected string CallMethod(string url, OAuthParams paramz, HttpType type)
49 {
50     if (paramz == null || paramz.Count == 0)
51     {
52         return string.Empty;
53     }
54  
55     if (type == HttpType.Post)
56     {
57         return Common.HttpRequest.DoPost(url, HttpUtil.GetQueryString(paramz));
58     }
59     else
60     {
61         return Common.HttpRequest.DoGet(HttpUtil.Combine(url, paramz));
62     }
63 }

(C)公开的接口

01 // 授权以获得AuthorizationCode
02 public void GetAuthorizeCode(string redirectUri)
03 {
04     string authUrl = config.AuthUrl;
05     OAuthParams paramz = new OAuthParams();
06     paramz.Add("client_id", config.ClientID);
07     paramz.Add("response_type""code");
08     paramz.Add("redirect_uri", HttpUtility.UrlEncode(redirectUri));
09     string requestUrl = HttpUtil.Combine(authUrl, paramz);
10     HttpContext.Current.Response.Redirect(requestUrl);
11 }
12  
13 // 获得AccessToken,前提AccessToken已经获得
14 public abstract Token GetAccessToken();
15  
16 // 获得SessionKey,前提SessionKey已经获得
17 public abstract string GetSessionKey();
18  
19 // 获得SessionKey
20 // 由于各开放平台参数差异,故定为抽象方法
21 public abstract string GetSessionKey(string accessToken);
22  
23 // 获得AccessToken
24 public abstract Token GetAccessToken(string code);
25  
26 // 获得AccessToken
27 public abstract Token GetAccessToken(string username, stringpassword);
28  
29 // 调用API方法
30 public abstract string CallMethod(string url, OAuthParams paramz);

7.OAuthService

(A)原型

01 public abstract class OAuthService<config, token="">
02     where Token : OAuthToken
03     where Config : OAuthConfig
04 {
05     protected Config config;
06     internal OAuthCore<config, token=""> core;
07  
08     internal void Init(OAuthCore<config, token=""> core, Config config)
09     {
10         this.core = core;
11         this.config = config;
12     }
13 }
14 </config,></config,></config,>

备注:Init方法用来实现子类对其父类的初始化,即参数传入。

(B)公开的接口

01 // 获得AccessToken,前提已经授权
02 public virtual Token AccessToken
03 {
04     get return core.GetAccessToken(); }
05 }
06  
07 // 获得SessionKey,前提已经授权
08 public virtual string SessionKey
09 {
10     get return core.GetSessionKey(); }
11 }
12  
13 // 授权,以获得AuthorizeCode
14 public void Authorize()
15 {
16     core.GetAuthorizeCode(config.RedirectUri);
17 }
18  
19 // 授权,以获得AuthorizeCode
20 public void Authorize(string redirectUri)
21 {
22     core.GetAuthorizeCode(redirectUri);
23 }
24  
25 // 接入,已获得AccessToken
26 public Token Access(string code)
27 {
28     Token token = core.GetAccessToken();
29     if (token == null)
30         token = core.GetAccessToken(code);
31     return token;
32 }
33  
34 // 接入,已获得AccessToken
35 public Token Access(string username, string password)
36 {
37     Token token = core.GetAccessToken();
38     if (token == null)
39         token = core.GetAccessToken(username, password);
40     return token;
41 }
42  
43 // 认证,以获得SessionKey
44 public string Session(string accessToken)
45 {
46     string sessionKey = core.GetSessionKey();
47     if (string.IsNullOrEmpty(sessionKey))
48         sessionKey = core.GetSessionKey(accessToken);
49     return sessionKey;
50 }
51  
52 // 调用API方法
53 // 前提必须已经获得AccessToken
54 public abstract string CallMethod(string method, OAuthParams paramz = null);

示例下载: OAuthDemo.zip

你可能感兴趣的:(OAuth)