1 背景

  OAuth2.0作为新一代的“用户验证和授权”标准,在现实当中应用非常广泛。现在阿里开放平台、百度开放平台,腾讯开放平台等大部分的开放平台都是使用的OAuth 2.0协议作为支撑。 在实际的项目中,DataViz也遇到越来越多的项目有需要对接OAuth2.0登录验证。

2 OAuth2.0 简介

  OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。
  OAuth2.0是OAuth协议的第二代版本,主要关注客户端开发者的简易性,同时为Web应用,桌面应用和手机,和起居室设备提供专门的认证流程。

  在认证和授权的过程中涉及的三方包括:

  • 服务提供方:用户使用服务提供方来存储受保护的资源,如照片,视频,联系人列表。
  • 用户:存放在服务提供方的受保护的资源的拥有者。
  • 客户端:要访问服务提供方资源的第三方应用,通常是网站,如提供照片打印服务的网站。在认证过程之前,客户端要向服务提供者申请客户端标识。

  OAuth 2.0定义了四种授权方式:

  1. 授权码模式(authorization code)   授权码是通过客户端的后台服务器,与"服务提供方"的认证服务器进行互动,设计了auth code,通过这个code再获取token的过程,是功能最完整、流程最严密的授权模式,也是使用最多的模式。

  2. 密码模式(resource owner password credentials)
      密码模式是用户向客户端提供自己的用户名和密码,客户端使用这些信息,向"服务提供方"索要授权的过程,这种模式是最不推荐的,主要用来做遗留项目升级为oauth2的适配方案。

  3. 简化模式(implicit)
      简化模式是不通过第三方应用程序的服务器,所有步骤在浏览器中完成的授权过程,这种模式比授权码模式少了auth code环节,回调url直接携带token,令牌对访问者是可见的,且客户端不需要认证。

  4. 客户端模式(client credentials)   客户端模式是客户端以自己的名义,向"服务提供商"进行认证,无需用户参与,严格地说客户端模式并不属于OAuth框架所要解决的问题。

3 OAuth2.0 登录集成说明

  DataViz目前只支持授权码模式(authorization code)的授权方式,如果选择使用OAuth2.0进行登录,那么将无法在DataViz的登录页面使用账号密码进行登录。

3.1 登录流程说明

  DataViz集成OAuth2.0 登录的处理流程示意,如下图: 001

  1. 第一步中用户访问的是DataViz中OAuth2的登录入口地址:http://10.4.53.105:8080/dataviz-web/src/index.html#/access/oauth2(其中的IP地址和端口要根据实际的部署环境而定)
  2. 从第2步到第7步是OAuth2.0的标准处理流程,总结老说就是先获取code,然后再用code获取token。
  3. 第8步和第9步是根据获取的token信息获取当前的登录用户,并会把用户存储到session中。
  4. 最后返回到DataViz的登录成功页面。

3.2 集成说明

  想要使用OAuth2.0进行登录需要修改一个配置,并实现我们预留的接口。

3.2.1 第一步 修改前台配置

  修改 dataviz-web/common/congif.js中的配置,把oauth2Login的值设置为true:

oauth2Login: true,

修改后,用户在未登录状态下将默认跳转到oauth2的登录入口(http://10.4.53.105:8080/dataviz-web/src/index.html#/access/oauth2)

3.2.2 第二步 实现后台的接口

  OAuth2.0在实际项目的使用过程中,有时候项目会根据自己的一些实际需要进行一定的定制,定制后的OAuth的与标准的OAuth2.0就会产生一些区别, 为了可以兼容这些定制,我们准备了个套接口。标准的OAuth2.0认证集成是只需要实现一个接口,非标准的OAuth2.0认证集成则需要实现两个接口。 我们需要根据自己项目的实际情况,进行实现。

  标准的OAuth2.0需要满足以下条件:

  1. 在3.1登录流程中的第2步,拼接的url要符合标准,如下:

     https://authorization-server.com/auth
      ?response_type=code
      &client_id=29352915982374239857
      &redirect_uri=https%3A%2F%2Fexample-app.com%2Fcallback
      &scope=create+delete
      &state=xcoiv98y2kd22vusuye3kch
    
    • response_type=code:这将通知认证中心,客户端正在启动授权代码流程。
    • client_id:客户端的标识符,在开发人员首次注册应用程序时获得。
    • redirect_uri:告诉认证中心在用户批准请求后将用户发送回何处。
    • scope:一个或多个空格分隔的字符串,指示客户端请求的权限。(可以不传)
    • state:客户端生成一个随机字符串并将其包含在请求中。然后应该检查在用户授权客户端之后是否返回相同的值。用于防止CSRF攻击。
  2. 在3.1登录流程中的第5步,url要符合标准,如下:

     https://example-app.com/redirect
      ?code=g0ZGZmNjVmOWIjNTk2NTk4ZTYyZGI3
      &state=xcoiv98y2kd22vusuye3kch
    
    • state值将与客户端在请求中最初设置的值相同。客户端需要检查重定向中的状态是否与最初设置的状态匹配。这可以防止CSRF和其他相关攻击。
    • code是由认证中心生成的授权代码。此代码相对较短,通常持续1到10分钟,具体取决于OAuth服务。
  3. 在3.1登录流程中的第6步,获取token的请求中传递的菜蔬要符合标准,如下:

    • grant_type=authorization_code:这将通知认证中心,客户端正在使用授权代码授予类型。
    • code:客户端授权代码,在第5步中给出。
    • redirect_uri:与第2步中redirect_uri相同。(可以不传)
    • client_id:客户端的标识符
    • client_secret:客户端的秘钥,与client_id搭配使用,表示请求不可能是截获授权代码的攻击。
  4. 在3.1登录流程中的第7步,返回的token信息格式要符合标准,不能返回多层对象,如下:

     {
       "access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
       "token_type":"bearer",
       "expires_in":3600,
       "refresh_token":"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk",
       "scope":"create delete"
     }
    

3.2.2.1 标准OAuth2.0 需要实现的接口

  如果项目中的OAuth是完全标准的OAuth2.0,没有经过任何定制,可以实现我们预留的OAuth2ResourceProvider接口:

package com.neusoft.saca.dataviz.authentication.springsecurity.oauth2.servie.extenal;

import java.util.Map;

import com.neusoft.saca.dataviz.authentication.springsecurity.oauth2.model.OAuth2UserAvatar;

/**
 * OAuth2 资源管理接口
 * 
 * @author ch-zhuo
 * @since 2019年3月21日
 */
public interface OAuth2ResourceProvider {
    /**
     * 根据获取的token信息,获取当前登录用户信息
     * @param token
     * @return
     */
    public OAuth2UserAvatar getOAuth2UserAvatar(Map<String, String> token);
}

  接口中目前只有一个方法,用来获取当前登录用户信息,入参是OAuth登录流程中第7步获取的token信息,返回是一个用户实体:

package com.neusoft.saca.dataviz.authentication.springsecurity.oauth2.model;

import java.io.Serializable;


public class OAuth2UserAvatar implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 692665913085005941L;
    /**
     * 用户ID
     */
    private String id;
    /**
     * 用户名称,显示在页面右上角
     */
    private String name;
    /**
     * 是否管理员
     */
    private boolean admin;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public boolean isAdmin() {
        return admin;
    }

    public void setAdmin(boolean admin) {
        this.admin = admin;
    }
}

3.2.2.1 非标准OAuth2.0 需要实现的接口

  如果项目中的OAuth不是完全标准的OAuth2.0,除了要实现上边的接口外,还需要实现我们预留的OAuth2AuthProvider接口:

package com.neusoft.saca.dataviz.authentication.springsecurity.oauth2.servie.extenal;

import java.util.Map;

/**
 * OAuth2 授权管理接口
 * 
 * @author ch-zhuo
 * @since 2019年4月1日
 */
public interface OAuth2AuthProvider {

    /**
     * 构建获取授权码地址
     * 
     * @param clientID
     * @param redirectUri
     * @param state
     * @return
     */
    public String buildAuthorizeCodeUrl(String clientID, String redirectUri,
            String state);

    /**
     * 根据根据授权码获取Token信息。若合法则返回Token信息,非法则抛出异常。<br>
     * 
     * @param code
     * @return
     * @throws Exception
     */
    public Map<String, String> getAccessToken(String clientID,
            String clientSecret, String code) throws Exception;
}
  1. buildAuthorizeCodeUrl方法返回的是获取code的跳转地址。
  2. getAccessToken方法则是根据上一步中的code获取token信息,并以Map格式返回。

3.2.3 第三步 修改后台的配置  

  对应不同的接口也有不同的配置方法。

3.2.3.1 标准OAuth2.0 的配置方法

  1. 修改dataviz-service\WEB-INF\conf\oauth2.properties配置文件,清空配置文件,然后把下面的内容拷贝到配置文件中:

     oauth2.client_id=sp1
     oauth2.client_secret=2713f22b601d42dfb8a2082c0e363f1d
     oauth2.authorize_url=https://auth.creditchina.com/idp/oauth2/authorize
     oauth2.token_url=https://auth.creditchina.com/idp/oauth2/getToken
     oauth2.redirect_uri=http://122.56.43.89:8080/dataviz-web/src/index.html#/access/oauth2
     oauth2.checkState=true
    
    • 其中前4项配置需要根据实际情况进行修改,不能为空。
    • oauth2.redirect_uri:IP和端口需要根据部署环境进行设置。
    • oauth2.checkState:客户端是否需要检查state与最初设置的状态匹配,配置成true可以防止CSRF和其他相关攻击;如果认证中心在第5步中不能返回state,则需要配置成false。
  2. 修改dataviz-service\WEB-INF\conf\spring\applicationContext-security.xml文件 ,找到如下配置:

     <beans:bean id="oauth2ProviderFactory" class="com.neusoft.saca.dataviz.authentication.springsecurity.oauth2.util.OAuth2ProviderFactory">
     </beans:bean>
    

      把OAuth2ResourceProvider接口的实现类注入到一个bean里,然后把这个bean赋值给oauth2AuthProviderFactory的oauth2ResourceProvider,如下:

     <beans:bean id="oauth2ProviderFactory" class="com.neusoft.saca.dataviz.authentication.springsecurity.oauth2.util.OAuth2ProviderFactory">
         <beans:property name="oauth2ResourceProvider" ref="实现类的实例名称"></beans:property>
     </beans:bean>
    
     <beans:bean id="实现类的实例名称" class="OAuth2ResourceProvider的实现类完整的访问路径(包名+类型)">
     </beans:bean>
    

3.2.3.2 非标准OAuth2.0 的配置方法

  1. 修改dataviz-service\WEB-INF\conf\oauth2.properties配置文件,清空配置文件,然后把下面的内容拷贝到配置文件中:

     oauth2.client_id=sp1
     oauth2.client_secret=2713f22b601d42dfb8a2082c0e363f1d
     oauth2.redirect_uri=http://122.56.43.89:8080/dataviz-web/src/index.html#/access/oauth2
     oauth2.checkState=true
    
    • 其中前2项配置需要根据实际情况进行修改,不能为空。
    • oauth2.redirect_uri:IP和端口需要根据部署环境进行设置。
    • oauth2.checkState:客户端是否需要检查state与最初设置的状态匹配,配置成true可以防止CSRF和其他相关攻击;如果认证中心在第5步中不能返回state,则需要配置成false。
  2. 修改dataviz-service\WEB-INF\conf\spring\applicationContext-security.xml文件 ,找到如下配置:

     <beans:bean id="oauth2ProviderFactory" class="com.neusoft.saca.dataviz.authentication.springsecurity.oauth2.util.OAuth2ProviderFactory">
     </beans:bean>
    
     <beans:bean id="oauth2AuthProvider" class="com.neusoft.saca.dataviz.authentication.springsecurity.oauth2.servie.DatavizOAuth2AuthProvider">
     </beans:bean>
    

      把OAuth2ResourceProvider接口的实现类注入到一个bean里,然后把这个bean赋值给oauth2AuthProviderFactory的oauth2ResourceProvider, 并且把com.neusoft.saca.dataviz.authentication.springsecurity.oauth2.servie.DatavizOAuth2AuthProvider修改为实际的实现类,如下:

     <beans:bean id="oauth2ProviderFactory" class="com.neusoft.saca.dataviz.authentication.springsecurity.oauth2.util.OAuth2ProviderFactory">
         <beans:property name="oauth2ResourceProvider" ref="实现类的实例名称"></beans:property>
     </beans:bean>
    
     <beans:bean id="实现类的实例名称" class="OAuth2ResourceProvider的实现类完整的访问路径(包名+类型)">
     </beans:bean>
    
     <beans:bean id="oauth2AuthProvider" class="OAuth2AuthProvider的实现类完整的访问路径(包名+类型)">
     </beans:bean>
    

results matching ""

    No results matching ""