澳门新浦京娱乐场网站-www.146.net-新浦京娱乐场官网
做最好的网站

第三方登录开发

需求:OAuth2实现第三方网站授权并获取其相关数据来实现登录等功能

OAuth2.0协议

国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:
内部邀请码:C8E245J **(不写邀请码,没有现金送) 国内私募机构九鼎控股打造,九鼎投资是在全国股份转让系统挂牌的公众公司,股票代码为430719,为“中国PE第一股”,市值超1000亿元。 **

暂时支持Facebook ,LinkedIn ,基本大同小异,只是返回时的数据不同,需根据具体返回类型进行相应处理

定义

OAuth: OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容。


 

开放授权(Open Authorization)

 

1.OAuth2认证流程

酒店泊车

  • 主钥匙:完全功能
  • 泊车钥匙:功能受限(行驶距离有限、无法打开后备箱、无法使用车内其他设备)

原文地址: 

OAuth2认证协议涉及3方(应用、用户和服务方),加之流程较为繁琐,实现命名不尽相同,

应用授权

小明是新浪微博的用户,想要通过第三方客户端来浏览微博,那第三方客户端如何获取小明在新浪微博的用户信息和时间线?

直接授予账号密码的弊端:
1、第三方客户端可能会保存小明的账号密码;
2、第三方客户端可以访问小明在新浪微博上的所有数据;
3、要收回第三方客户端的权限,只有修改密码。

目录[-]

容易忘记和混淆,简述认证流程如下

OAuth 2.0协议

  • OAuth support
  • 关于接入的一些背景:
  • step1. 应用配置,获得client_id和client_secret
  • step2. Oauth client 构造url,获取authorization_code
  • step3. 授权码交换access_token
  • step4. 根据access_token获取用户信息
  • 第三方登录开发。总结

1、向使用OAuth2认证的服务方申请应用,获取应用的client_id(应用唯一标识)和client_secret(应用私钥)

协议的参与者

OAuth的参与者至少有以下四个:

  • RO(Resource Owner):资源所有者,对资源具有授权能力的人。如上文的小明。
  • RS(Resource Server):资源服务器,它存储资源,并处理对资源的访问请求。如上文的新浪微博资源服务器。
  • Client:第三方应用,它获取RO的授权后就可以访问RO的资源。如上文的第三方客户端。
  • AS(Authorization Server):授权服务器,它认证RO的身份,为RO提供授权审批流程,并最终颁发授权令牌(Access Token)。AS和RS的功能可以由同一个服务器来提供。

OAuth support

CAS3.5.x提供了oauth的支持,包括客户端和服务端,cas-server-support-oauth依赖架包

scribe-1.3.5.jar 
scribe-up-1.2.0.jar 
jackson-core-2.3.0.jar,jackson-databind-2.3.0.jar。

CAS默认提供了三个服务: 
/oauth2.0/authorize 
Input GET parameters required : client_id and redirect_uri. 
/oauth2.0/accessToken 
Input GET parameters required : client_id, redirect_uri, client_secret and code. 
/oauth2.0/profile 
Input GET parameter required : access_token.

2、使用key/secret向服务方请求用户授权Token(code也就是authorization_code)

OAuth的思路

OAuth在Client和RS之间设置了一层授权层。Client不能直接登录RS,只能利用令牌来登录授权层,而且这个令牌有权限范围和有效期。

关于接入的一些背景:

1.cas的web登录访问路径为 
2.回调地址为) 
3.client_Id为key 
4.client_secret为secret 
5.应用名称为DoubanNote 
6.核心类为org.jasig.cas.support.oauth.web.OAuth20WrapperController

下面配置cas server支持oauth2 server,我们从oauth2 client向cas接入为步骤来分析每一步的配置:

3、使用用户授权Token换取用户信息访问Token(access_token ),

时序图

图片 1

基本流程:
1、RO打开Client,Client请求RO授权。
2、RO同意授权给Client,并将授权证据发给Client。这里RO如何批准是关键,后面会讲到。
3、Client向AS请求“访问令牌(Access Token),同时出示RO提供的授权证据。
4、AS通过认证后,向Client返回访问令牌。
5、Client携带访问令牌去访问RS上的资源。
6、RS验证令牌的有效期和真伪,验证通过后才能提供服务。

step1. 应用配置,获得client_id和client_secret

在成熟的系统中,通常提供页面供用户申请应用,然后提供用户client_id和client_secret,并允许用户配置回调地址,那么oauthserver端(即CAS Server)首先考虑的就是需要持久化这些配置。默认在文件deployerConfigContext.xml的serviceRegistryDao中配置应用服务,实际使用中,我们可以将申请的应用信息存储在数据库中:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<bean
    id="serviceRegistryDao"
    class="org.jasig.cas.services.InMemoryServiceRegistryDaoImpl">
        <property name="registeredServices">
            <list>
                <bean class="org.jasig.cas.services.RegisteredServiceImpl">
                    <property name="id" value="1" />
                    <property name="name" value="HTTP" />
                    <property name="description" value="oauth wrapper callback url" />
                    <property name="serviceId" value="${server.prefix}/oauth2.0/callbackAuthorize" />
                </bean>
               <bean class="org.jasig.cas.services.RegisteredServiceImpl">
                <property name="id" value="2" />
                <property name="name" value="key" />
                <property name="description" value="secret" />
                <property name="serviceId" value="http://www.doubannote.org/" />
                <property name="theme" value="DoubanNote" />
              </bean>
              ......

如代码所示,我们新注册了两个bean,关于应用的配置在第二个bean中,name为client_id,description为client_secret,serviceId为回调地址,theme为应用名称。 
关于第一个bean的用途将在下面介绍。【终于搞明白了为何是这样了,服务器间接获取 ST】

4、使用access_token(用户信息访问令牌)获取相关信息

客户端的授权

上面讲到RO给Client授权这一步是关键。Client必须得到RO的授权才能获得令牌。Auth2.0定义了四种授权方式:

  • 授权码模式
  • 简化模式
  • 密码模式
  • 客户端模式

step2. Oauth client 构造url,获取authorization_code

通常客户端构造的url可能如下(参数可以参照标准的oauth2 protocol,但是不同的oauth server通常提供了自己的标准):

?

1
https://cas.sayi.com:8443/cas/oauth2.0/authorize?client_id=key&redirect_uri=http://www.doubannote.org/&response_type=code

在这里就要求cas server能对/oauth2.0/authorize的url进行处理,那么就需要配置映射,在web.xml中配置如下:

?

1
2
3
4
<servlet-mapping>
    <servlet-name>cas</servlet-name>
    <url-pattern>/oauth2.0/*</url-pattern>
</servlet-mapping>

在cas-servlet.xml中配置映射:

?

1
2
3
4
5
6
7
<prop key="/oauth2.0/*">oauth20WrapperController</prop>
...
...
<bean id="oauth20WrapperController"
    class="org.jasig.cas.support.oauth.web.OAuth20WrapperController"
    p:loginUrl="${server.prefix}/login" p:servicesManager-ref="servicesManager"
    p:ticketRegistry-ref="ticketRegistry" p:timeout="7200" />

如上配置了之后,我们获取授权码的链接会转向login页面,此时的service地址就是step1中配置的第一个bean的serviceId,通过这个默认提供的地址间接的获取到ST。

?

1
https://cas.sayi.com:8443/cas/login?service=https://cas.sayi.com:8443/cas/oauth2.0/callbackAuthorize

认证成功之后,就会携带值为ST的参数跳转到callbackAuthorize页面,此时生成的ST即为授权码,回调地址、服务名称通过session传递过来。

?

1
https://cas.sayi.com:8443/cas/oauth2.0/callbackAuthorize?ticket=ST-5-ywMLFaXQFnDeFI7erFy7-cas.sayi.com

默认授权码只能使用一次,且有效时间为10s,可以通过票根过期策略进行配置时间。

 

授权码模式

授权码模式是功能最完整、流程最严密的授权模式。其特点是通过Client的后台服务器与AS进行互动。

图片 2

基本流程:
1、Client初始化协议的执行流程,通过HTTP 302来重定向RO用户代理到AS。这里的用户代理基本上就是指浏览器。Client申请认证的URI包含以下参数:

  • response_type:授权类型,此处的值固定为“code”(必选)
  • client_id:客户端的ID(必选)
  • redirect_uri:重定向URI(可选)
  • scope:申请的权限范围(可选)
  • state:客户端的当前状态,可指定任意值,认证RS会原封不动地返回这个值

2、AS认证RO身份证,并提供页面供RO决定是否批准或拒绝Client的此次请求。
3、若请求被批准,AS使用步骤(1)中Client提供的redirect_url重定向RO用户代理到Clietnt。redirect_uri必须包含authorization_code,以及步骤(1)中Client提供的state。若请求被拒绝,AS将通过redirect_uri返回相应的错误信息。

  • code:授权码(必选)。该码的有效期应该很短,通常设为10分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。该码与客户端ID和重定向URI是一一对应的关系。
  • state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。

4、Client拿authorization_code去访问AS以交换所需的access_token。Client请求信息中应包含用于认证Client身份所需的认证数据,以及上一步请求authorization_code时所需的redirect_uri。

  • grant_type:授权模式,此处的值固定位“authorization_code”(必选)
  • code:上一步获取的授权码(必选)
  • redirect_uri:重定向URI,必须与步骤(1)中的该参数值保持一致(必选)
  • client_id:客户端ID(必选)

5、AS收到authorization_code时需要验证Client的身份,并验证收到的redirect_uri与步骤(3)请求authorization_code时所用的redirect_uri相匹配。如果验证通过,AS将返回access_token以及refresh_token。

  • access_token:访问令牌
  • token_type:令牌类型
  • token_type:表示过期时间
  • refresh_token:更新令牌,用来获取下一次的访问令牌
  • scope:权限范围,如果与客户端申请的范围一致,此项可省略

step3. 授权码交换access_token

构造的URL如下:

?

1
2
3
https://cas.sayi.com:8443/cas/oauth2.0/accessToken?client_id=key&client_secret=secret&grant_type=authorization_code&redirect_uri=http://www.doubannote.org/&code=ST-1-3jLuZnhcAvLiLdy7R6ft-cas.sayi.com
 
access_token=TGT-2-qWkLyEbeoby043q05p5GHXfBg7qtdPZjEUhfemgg3UKbxAyB5s-cas.sayi.com&expires=7143

通过返回的值可以获得access_token.

2.授权访问流程

更新令牌

如果Client的访问令牌过期,则需要使用更新令牌申请一个新的访问令牌。
Client发出更新令牌的HTTP请求,包含以下参数:

  • grant_type:授权模式,此处的值固定为“refreshtoken”
  • refresh_token:之前收到的更新令牌
  • scope:申请的授权范围,不可以超出上一次申请的范围,如果省略该参数,则表示与上一次一致

step4. 根据access_token获取用户信息

构造URL如下:

?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
https://cas.sayi.com:8443/cas/oauth2.0/profile?access_token=TGT-1-gn3p9EMfFEajKOJ9DdNqd2PefJdIbIeXuESyzU4EctMtBqITRG-cas.sayi.com
 
{
"id":"sayi",
    "attributes":[
        {
            "uid":"uid"
        },
        {
            "eduPersonAffiliation":"eduPersonAffiliation"
        },
        {
            "groupMembership":"groupMembership"
        }
    ]
}

1、向第三方平台申请访问权限得到(client_id和client_secret)

OAuth2.0协议实例化描述

总结

cas server支持oauth2 server,无非就是考虑对/authorize、/accessToken、/profile的请求的处理,在服务端进行应用配置后,对接入的应用进行校验,比如回调地址、client_secret等。在与cas server的融合中,主要就是cas认证与/authorize的融合。在这里使用的是callbackAuthorize的方式,cas默认提供了/oauth2.0/callbackAuthorize的service地址,通过此地址cas认证成功之后生成ST,此值即为授权码,传递给应用的回调地址即可。 
总体来说oauth2的支持在cas3.5.x中并不完善,而且OAuth2的实现也不是标准的,对于3.5.x版本我们需要扩展OAuth20WrapperController来进一步融合oauth2 protocol。

2、填写Oauth2.0本站返回链接

通过instagram登录

3、向第三方平台发送授权请求

时序图

图片 3

在上面Client拿到授权码后去申请令牌时将client_secret发送给AS来证明自己的身份,即证明自己是User批注授权的Client。

具体步骤
1、首先第三方客户端要在instagram的开发者平台注册为client,得到一个client_id和一个client_secret:

图片 4

2、当用户请求通过instagram登录时,把用户重定向到instagram提供的验证授权页面:

图片 5

图片 6

图片 7

3、当用户验证通过且允许授权时instagram会将用户重定向到之前设置的redirect_uri,并在后面附上授权码:

图片 8

图片 9

4、我们得到授权码之后再去请求access_token:

图片 10

图片 11

5、最后返回access_token:

图片 12

4、再返回url中进行业务潮处理

OAuth1.0a

OAuth 1.0a的登录流程共有三个步骤

1、获取未授权的Request Token,与服务器交互。

POST https://www.example.com/oauth/request_token

-2、请求用户授权Request Token,客户端使用webview打开登录页面,用户登录授权。

https://www.example.com/oauth/authorize

3、使用授权后的Request Token换取Access Token,与服务器交互。

POST https://www.example.com/oauth/access_token

注意:申请的网址需要与实际访问的url保持一致

获取Request Token

请求参数参数

  • oauth_consumer_key是注册你的应用后获得。
  • oauth_signature_method="HMAC-SHA1",仅支持HMAC-SHA1。
  • oauth_timestamp是当前时间戳,以秒为单位。
  • oauth_nonce是随机字符串,与oauth_timestamp唯一对应,用来标识唯一,防止一些攻击。
  • oauth_callback在注册你的应用时需要提供的回调URL,需要URLEncode。
  • oauth_signature签名结果,如何签名最后一节讨论,需要URLEncode。
  • oauth_version协议版本号。

返回结果

  • oauth_token:未授权的token。
  • oauth_token_secret:参与第三步的签名。
  • oauth_callback_confirmed:对oauth_callback的确认信号 (true/false)

 

请求用户授权

GET

https://www.example.com/oauth/authorize?oauth_token=hh5s93j4hdidpola

服务器返回重定向结果

http://printer.example.com/ready?
oauth_token=hh5s93j4hdidpola&oauth_verifier=hfdp7dh39dks9884

  • oauth_token:与第一步返回的结果是一样的。
  • oauth_verifier:授权验证码。
  1. AuthHelper代码

     public abstract class AuthHelper
     {
         public static AuthToken GetToken(string code, string token_url, string cliend_id, string client_secret, string return_url)
         {
             var strResult = GetTokenStr(code, token_url, cliend_id, client_secret, return_url);
             try
             {
                 var res = JsonConvert.DeserializeObject<AuthToken>(strResult);
                 return res;
             }
             catch (Exception ex)
             {
                 Tool.Log.Write(ex.ToString());
             }
             return default(AuthToken);
         }
    
         /// <summary>
         /// 向第三方平台发送获取token请求
         /// </summary>
         /// <param name="code"></param>
         /// <param name="token_url"></param>
         /// <param name="cliend_id"></param>
         /// <param name="client_secret"></param>
         /// <param name="return_url"></param>
         /// <returns></returns>
         public static string GetTokenStr(string code, string token_url, string cliend_id, string client_secret, string return_url)
         {
             Dictionary<string, string> dicPara = new Dictionary<string, string>();
             dicPara.Add("grant_type", "authorization_code");
             dicPara.Add("code", code);
             dicPara.Add("redirect_uri", return_url);
             dicPara.Add("client_id", cliend_id);
             dicPara.Add("client_secret", client_secret);
    
             var token = WebApiHelper.PostResponseStr(token_url, dicPara);
             return token;
         }
    
         /// <summary>
         /// header中发送token
         /// </summary>
         /// <param name="accessToken"></param>
         /// <param name="profile_url"></param>
         /// <returns></returns>
         public static string GetProFileAuth(string accessToken, string profile_url)
         {
             Dictionary<string, string> dicAuth = new Dictionary<string, string>();
             dicAuth.Add("Authorization", "Bearer "   accessToken);
             var profile = WebApiHelper.GetResponseStr(profile_url, null, dicAuth);
             return profile;
         }
         /// <summary>
         /// get方式获取token
         /// </summary>
         /// <param name="accessToken"></param>
         /// <param name="profile_url"></param>
         /// <returns></returns>
         public static string GetProFileStr(string accessToken, string profile_url)
         {
             Dictionary<string, string> dicQuery = new Dictionary<string, string>();
             dicQuery.Add("access_token", accessToken);
             var profile = WebApiHelper.GetResponseStr(profile_url, dicQuery, null);
             return profile;
         }
     }
    

获取Access Token

请求参数

  • oauth_consumer_key="dpf43f3p2l4k3l03",
  • oauth_signature_method="HMAC-SHA1",
  • oauth_timestamp="137131201",
  • oauth_nonce="walatlh",
  • oauth_signature="gKgrFCywp7rO0OXSjdot/IHF7IU="
  • oauth_token="hh5s93j4hdidpola",
  • oauth_verifier="hfdp7dh39dks9884",

返回

  • oauth_token=nnch734d00sl2jdk
  • oauth_token_secret=pfkkdhi9sl3r4s00

4.返回业务处理

关于签名oauth_signature

开发者注册APP时除了会得到oauth_consumer_key之外,还会得到一个consumer_secret。为了得到签名,需要用以下的参数拼成字符串:

  • consumer secret - "MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98"
  • oauth_consumer_key - GDdmIQH6jhtmLUypg82g
  • oauth_nonce - QP70eNmVz8jvdPevU3oJD2AfF7R7odC2XJcn4XlZJqk
  • oauth_signature_method - HMAC-SHA1
  • oauth_timestamp - 1272323042
  • oauth_version - 1.0

拼接结果(HTTP请求方式(get或者post) 网址 上述各值):

POST&https://api.t.sina.com.cn/oauth/request_token&oauth_consumer_key=GDdmIQH6jhtmLUypg82g&oauth_nonce=QP70eNmVz8jvdPevU3oJD2AfF7R7odC2XJcn4XlZJqk&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1272323042&oauth_version=1.0

然后用consumer_key作为key对base string进行HMAC-SHA1签名,最终得到签名结果oauth_signature。客户端将oauth_signature以及除了consumer_secret以外的其他参数一并发给认证服务器。因为服务器端本身也保有客户端申请时的consumer_secret,它再对以上信息进行签名一次,将签名结果与客户端发来的结果进行比较,如果结果一致,就可以确认客户端的身份。这种方式避免了传递consumer_secret。

OAuth2.0直接传递client_secret,是因为它改用SSL(HTTPS)确保安全性,因此也省去了签名。

https://gist.github.com/JakeWharton/f26f19732f0c5907e1ab

   public ActionResult ReturnLinkedin()
        {
            string description = string.Empty;

            string code = RequestString("code");
            string state = RequestString("state");
            string error = RequestString("error");
            string error_description = RequestString("error_description");
            if (code == "" || error != "")
            {
                if (code == "user_cancelled_authorize" || code == "user_cancelled_login ")
                {
                    description = code;
                }
                else
                    description = error != "" ? error_description : "no authentication !";
            }
            else
            {
                var res = Tools.Auth.LinkinHelper.GetToken(code, Tools.Auth.LinkinConfig.ReturnUrl);
                if (res.access_token != "")
                {
                    var entity = Tools.Auth.LinkinHelper.GetProFileStr(res.access_token, Tools.Auth.LinkinConfig.ProfileResourceUrl);
                    description = entity;
            /***具体业务处理
            **/
                }
                else
                {
                    description = "access token error";
                }
            }
            ViewBag.Description = description;
            return View();
        }

Github地址:

第一次发博客 ,有疑问或者有建议的请留言

 

本文由澳门新浦京娱乐场网站发布于www.146.net,转载请注明出处:第三方登录开发