iServer扩展实现Oauth2第三方登录

作者:lly

一、授权服务器搭建

这一部分可基于Oauth2协议自由变动,不做详细介绍,可参考网上相应博客,如下链接

二、SuperMap iServer扩展和配置流程

本文基于iServer帮助文档“扩展使用 OAuth2协议的账户”示例修改,主要改动为获取token请求方式改为post,如需使用get请求,可直接在帮助文档示例代码基础上修改,流程为以下几步:1.获取code 2.通过code获取token 3.拿到token获取用户信息 4.在iServer中绑定iServer账户

注:iServer目前只支持授权码方式

2.1 自定义登录方式实现类

package com.supermap.services.rest.resources.impl;

import java.io.*;
import java.net.URI;
import java.net.URL;
import java.net.URLEncoder;

import com.supermap.services.security.OAuth2Client;
import com.supermap.services.security.OAuthUserInfo;
import org.apache.commons.io.IOUtils;

import java.net.URISyntaxException;

import org.apache.http.HttpEntity;
import org.apache.http.ParseException;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.json.JSONException;
import org.json.JSONObject;

import java.net.HttpURLConnection;

public class RenRenLoginExtended implements OAuth2Client {
    // 人人的 <FONT style="BACKGROUND-COLOR: #0078d7" color=#ffffff>OAuth2</FONT>认证根地址
    public static final String OAUTH_URL_RENREN = System.getProperty("OAUTH_RENREN", "http://192.168.15.23:8080");
    private static final String GET_CODE_URI_RENREN = OAUTH_URL_RENREN
            + "/oauth/authorize?client_id=%s&response_type=code&redirect_uri=%s&state=%s&display=page";
    private static final String GET_TOKEN_BY_CODE_RENREN = OAUTH_URL_RENREN + "/oauth/token?client_id=%s&client_secret=%s&grant_type=authorization_code&code=%s&redirect_uri=%s";
    private static final String useridUrl = "http://192.168.15.23:8080/oauth/check_token?token=%s";
    private static final String userInfoUrl = "http://192.168.15.23:8080/oauth/check_token?token=%s&client_id=%s&userID=%s";

    //获取 <FONT style="BACKGROUND-COLOR: #0078d7" color=#ffffff>OAuth2</FONT>跳转 URI
    public String getRedirectURI(String clientID, String state, String redirectUri) {
        return String.format(GET_CODE_URI_RENREN, clientID, redirectUri, state);
    }

    //获取访问 Token
    public String getAccesstoken(String clientID, String clientSecret, String code, String redirectUri) throws IOException {
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        // 参数
        StringBuffer params = new StringBuffer();
        try {
            // 字符数据最好encoding以下;这样一来,某些特殊字符才能传过去(如:某人的名字就是“&”,不encoding的话,传不过去)
            params.append("client_id=" + URLEncoder.encode(clientID, "utf-8"));
            params.append("&");
            params.append("client_secret=" + URLEncoder.encode(clientSecret, "utf-8"));
            params.append("&");
            params.append("code=" + URLEncoder.encode(code, "utf-8"));
            params.append("&");
            params.append("grant_type=authorization_code");
            params.append("&");
            params.append("redirect_uri=" + URLEncoder.encode(redirectUri, "utf-8"));
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        }
        // 创建Post请求
        HttpPost httpPost = new HttpPost("http://192.168.15.23:8080/oauth/token" + "?" + params);
        System.out.println("http://192.168.15.23:8080/oauth/token" + "?" + params);
        // 设置ContentType(注:如果只是传普通参数的话,ContentType不一定非要用application/json)
        httpPost.setHeader("Content-Type", "application/json;charset=utf8");
        // 响应模型
        CloseableHttpResponse response = null;
        try {
            // 由客户端执行(发送)Post请求
            response = httpClient.execute(httpPost);
            // 从响应模型中获取响应实体
            HttpEntity responseEntity = response.getEntity();
            System.out.println("响应状态为:" + response.getStatusLine());
            if (responseEntity != null) {
                System.out.println("响应内容长度为:" + responseEntity.getContentLength());
                //System.out.println("响应内容为:" + EntityUtils.toString(responseEntity));
                JSONObject tokenObj = new JSONObject(EntityUtils.toString(responseEntity));
                System.out.println(tokenObj);
                return tokenObj.getString("access_token");
            }
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (ParseException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                // 释放资源
                if (httpClient != null) {
                    httpClient.close();
                }
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }


    // 获取用户 ID,本文示例此方法并没有调用
    public String getUserID(String accesstoken) throws IOException {
        String useridfourl = String.format(useridUrl, URLEncoder.encode(accesstoken, "utf-8"));
        try {
            String useridresult = IOUtils.toString(new URI(useridfourl), "utf-8");
            JSONObject useridObj = new JSONObject(useridresult);
            System.out.println(useridObj);
            return useridObj.getString("user_name");
        } catch (JSONException e) {
            throw new IOException(e);
        } catch (URISyntaxException e) {
            throw new IOException(e);
        }
    }

    //获取用户信息
    public OAuthUserInfo getUserInfo(String token, String clientID, String userID) throws IOException {
        String userinfourl = String.format(userInfoUrl, URLEncoder.encode(token, "utf-8"), clientID, userID);
        OAuthUserInfo userinforesult = new OAuthUserInfo();
        String content = null;
        try {
            content = IOUtils.toString(new URI(userinfourl), "utf-8");
            JSONObject userinfoJson = new JSONObject(content);
            //获取图标的url
            userinforesult.figureurl = "https://img.alicdn.com/tps/TB1h9xxIFXXXXbKXXXXXXXXXXXX.jpg";
            userinforesult.nickName = userinfoJson.getString("user_name");
            return userinforesult;
        } catch (JSONException e) {
            throw new IOException(e);
        } catch (URISyntaxException e) {
            throw new IOException(e);
        }
    }

}

将编译后包含 RenRenLoginExtended.class 文件的整个 com 目录拷贝到 SuperMap iServer Web 应用下,即 %SuperMap iServer_HOME%\webapps\iserver\WEB-INF\classes 下(先在该目录下新建 classes 文件夹)或者将打包好的jar包直接解压到当前目录.

在这里插入图片描述

2.2 自定义方式的配置extendedOAuth.xml

在产品包根目录 %SuperMap iServer_HOME%webapps/iserver/WEB-INF 下新建一个 extendedOAuth.xml 文件,里面的内容如下所示:

<?xml version="1.0" encoding="UTF-8"?> 
<extendedOAuthSettings> 
     <extendedOAuthSetting> 
           <loginType>RENREN</loginType>   
           <oAuth2ClientClass>com.supermap.services.rest.resources.impl.RenRenLoginExtended</oAuth2ClientClass> 
      </extendedOAuthSetting> 
</extendedOAuthSettings>

其中为遵循 OAuth2 协议的第三方登录方式扩展实现配置集合,可以包含多个标签。每个标签对应一种遵循 OAuth2 协议的第三方登陆方式扩展实现配置,标签中的内容对应于 ExtendedOAuthSetting 中的配置项:

:扩展后支持的登录类型,这里是“RENREN”,可自定义。

:扩展后登录类型的具体实现类,这里为“人人网账号登陆”方式对应的实现类。

2.3 配置 iserver-system.xml

在产品包根目录 %SuperMap iServer_HOME%webapps/iserver/WEB-INF 下的 iserver-system.xml 文件的根节点中添加如下内容:

 <oAuthConfigs> 
    <oAuthConfig> 
      <id>1</id>  
      <enabled>true</enabled>  
      <loginType>RENREN</loginType>  
      <buttonText>自己账号登陆</buttonText>  
      <clientSecret>secret</clientSecret>  
      <clientID>client</clientID>  
      <redirectDomain>192.168.15.23</redirectDomain>  
      <loginIcon>renren.png</loginIcon> 
    </oAuthConfig> 
  </oAuthConfigs>  

其中为遵循 OAuth2 协议的第三方登陆方式 配置项集合,可以包含多个标签。每个标签对应一种登陆方式的配置,中的内容对应于 OAuthConfig 中的配置项:

:遵循 OAuth2 协议的第三方登陆方式对应的配置 ID 。

:是否启用遵循 OAuth2 协议的第三方登陆方式。

:遵循 OAuth2 协议的第三方登陆方式,这里为“RENREN”。

:在登录界面显示的登录按钮名称,这里为“自己账号登陆”。

:申请应用时分配的 AppSecret ,这里为自己建的库中oauth_client_details表中的client_secret字段记录值。

:申请应用时分配的 Appkey ,这里为自己建的库中oauth_client_details表中的client_id字段记录值。

:申请应用时填写的回调域名,这里为客户端ip“192.168.15.23”。

:在登录界面显示的登录图片标识,这里为“renren.png”。该图片必须放于 %SuperMap iServer_HOME%webapps/iserver/WEB-INF/lib 目录下的 iserver-all.jar 的 ./staticFiles/img 文件夹下,也可使用在线图片,无图片不影响正常使用。
如果值为 QQ 或 Weibo ,则此标签可省略。

三、验证

配置完成后重启iServer,在登录页面点击三方登录
在这里插入图片描述
输入Oauth2账号
在这里插入图片描述
勾选允许访问资源
在这里插入图片描述首次登录会要求绑定iServer账户
在这里插入图片描述
在这里插入图片描述
绑定成功后会自动跳转到服务列表页面
在这里插入图片描述
后续该账户再进行登录时,就会直接登录跳转了,无需再做操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以使用Spring Security OAuth2来实现第三方登录,具体步骤如下: 1. 添加依赖 在pom.xml中添加以下依赖: ``` <dependency> <groupId>org.springframework.security.oauth</groupId> <artifactId>spring-security-oauth2</artifactId> <version>2.3.4.RELEASE</version> </dependency> ``` 2. 配置OAuth2客户端 在application.yml中添加以下配置: ``` spring: security: oauth2: client: registration: github: client-id: <your-client-id> client-secret: <your-client-secret> scope: read:user redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}" provider: github: authorization-uri: https://github.com/login/oauth/authorize token-uri: https://github.com/login/oauth/access_token user-info-uri: https://api.github.com/user user-name-attribute: login ``` 其中,`client-id`和`client-secret`是你在GitHub上注册OAuth2应用时获得的。 3. 创建登录页面 创建一个登录页面,让用户选择使用哪个第三方登录。 4. 创建回调页面 创建一个回调页面,用于接收第三方登录成功后的回调请求。 5. 创建用户信息服务 创建一个用户信息服务,用于将第三方登录成功后获取到的用户信息保存到数据库中。 6. 配置Spring Security 在SecurityConfig中配置OAuth2登录和授权的相关信息: ``` @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private OAuth2UserService<OAuth2UserRequest, OAuth2User> oAuth2UserService; @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/login/**", "/oauth2/**").permitAll() .anyRequest().authenticated() .and() .oauth2Login() .loginPage("/login") .userInfoEndpoint() .userService(oAuth2UserService) .and() .defaultSuccessURL("/home") .and() .logout() .logoutSuccessUrl("/") .permitAll(); } } ``` 其中,`oAuth2UserService`是一个实现了`OAuth2UserService`接口的类,用于将第三方登录成功后获取到的用户信息保存到数据库中。 7. 测试 启动应用程序并访问登录页面,选择使用GitHub登录,然后输入你的GitHub用户名和密码,如果一切正常,你将被重定向到回调页面,并看到你的GitHub用户名。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值