Spring Boot 快速集成第三方登錄功能


Spring Boot 快速集成第三方登錄功能

此 demo 主要演示 Spring Boot 項目如何使用 史上最全的第三方登錄工具 - JustAuth 實現第三方登錄,包括 QQ 登錄、GitHub 登錄、微信登錄、谷歌登錄、微軟登錄、小米登錄、企業微信登錄。

通過 justauth-spring-boot-starter 快速集成,好嗨喲~

JustAuth,如你所見,它僅僅是一個第三方授權登錄工具類庫,它可以讓我們脫離繁瑣的第三方登錄 SDK,讓登錄變得So easy!

  1. :已集成十多家第三方平台(國內外常用的基本都已包含),后續依然還有擴展計划!
  2. :API 就是奔着最簡單去設計的(見后面快速開始),盡量讓您用起來沒有障礙感!

PS: 本人十分幸運的參與到了這個 SDK 的開發,主要開發了 QQ 登錄、微信登錄、小米登錄、微軟登錄、谷歌登錄5 個第三方登錄,以及一些 BUG 的修復工作。再次感謝 @母狼 開源這個又好用又全面的第三方登錄 SDK。

1. Demo

完整版 demo:https://github.com/justauth/justauth-spring-boot-starter-demo


2. 更新日志

CHANGELOG


3. 快速開始

3.1. 基礎配置

  • 引用依賴
<dependency>
  <groupId>com.xkcoding.justauth</groupId>
  <artifactId>justauth-spring-boot-starter</artifactId>
  <version>1.3.4</version>
</dependency>
  • 添加配置,在 application.yml 中添加配置配置信息

注意:

  • justauth.type節點的配置,請根據項目實際情況選擇,多余的可以刪除
  • 如果使用 QQ 登錄,並且需要獲取unionId,則必須傳union-id配置,並置為true
  • 如果使用支付寶登錄,必傳alipay-public-key
  • 如果使用 Stack Overflow 登錄,必傳stack-overflow-key
  • 如果使用企業微信登錄,必傳agent-id
  • 如果使用 CODING 登錄,必傳coding-group-name
justauth:
  enabled: true
  type:
    QQ:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/qq/callback
      union-id: false
    WEIBO:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/weibo/callback
    GITEE:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/gitee/callback
    DINGTALK:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/dingtalk/callback
    BAIDU:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/baidu/callback
    CSDN:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/csdn/callback
    CODING:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/coding/callback
      coding-group-name: xx
    OSCHINA:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/oschina/callback
    ALIPAY:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/alipay/callback
      alipay-public-key: MIIB**************DAQAB
    WECHAT_OPEN:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/wechat_open/callback
    WECHAT_MP:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/wechat_mp/callback
    WECHAT_ENTERPRISE:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/wechat_enterprise/callback
      agent-id: 1000002
    TAOBAO:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/taobao/callback
    GOOGLE:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/google/callback
    FACEBOOK:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/facebook/callback
    DOUYIN:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/douyin/callback
    LINKEDIN:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/linkedin/callback
    MICROSOFT:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/microsoft/callback
    MI:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/mi/callback
    TOUTIAO:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/toutiao/callback
    TEAMBITION:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/teambition/callback
    RENREN:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/renren/callback
    PINTEREST:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/pinterest/callback
    STACK_OVERFLOW:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/stack_overflow/callback
      stack-overflow-key: asd*********asd
    HUAWEI:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/huawei/callback
    KUJIALE:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/kujiale/callback
    GITLAB:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/gitlab/callback
    MEITUAN:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/meituan/callback
    ELEME:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/eleme/callback
    TWITTER:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/twitter/callback
  cache:
    type: default
  • 然后就開始玩耍吧~
@Slf4j
@RestController
@RequestMapping("/oauth")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class TestController {
    private final AuthRequestFactory factory;

    @GetMapping
    public List<String> list() {
        return factory.oauthList();
    }

    @GetMapping("/login/{type}")
    public void login(@PathVariable String type, HttpServletResponse response) throws IOException {
        AuthRequest authRequest = factory.get(type);
        response.sendRedirect(authRequest.authorize(AuthStateUtils.createState()));
    }

    @RequestMapping("/{type}/callback")
    public AuthResponse login(@PathVariable String type, AuthCallback callback) {
        AuthRequest authRequest = factory.get(type);
        AuthResponse response = authRequest.login(callback);
        log.info("【response】= {}", JSONUtil.toJsonStr(response));
        return response;
    }

}
/**
 * <p>
 * 第三方登錄 Controller
 * </p>
 *
 * @package: com.xkcoding.oauth.controller
 * @description: 第三方登錄 Controller
 * @author: yangkai.shen
 * @date: Created in 2019-05-17 10:07
 * @copyright: Copyright (c) 2019
 * @version: V1.0
 * @modified: yangkai.shen
 */
@Slf4j
@RestController
@RequestMapping("/oauth")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class OauthController {
    private final AuthRequestFactory factory;

    /**
     * 登錄類型
     */
    @GetMapping
    public Map<String, String> loginType() {
        List<String> oauthList = factory.oauthList();
        return oauthList.stream().collect(Collectors.toMap(oauth -> oauth.toLowerCase() + "登錄", oauth -> "http://oauth.xkcoding.com/demo/oauth/login/" + oauth.toLowerCase()));
    }

    /**
     * 登錄
     *
     * @param oauthType 第三方登錄類型
     * @param response  response
     * @throws IOException
     */
    @RequestMapping("/login/{oauthType}")
    public void renderAuth(@PathVariable String oauthType, HttpServletResponse response) throws IOException {
        AuthRequest authRequest = factory.get(getAuthSource(oauthType));
        response.sendRedirect(authRequest.authorize(oauthType + "::" + AuthStateUtils.createState()));
    }

    /**
     * 登錄成功后的回調
     *
     * @param oauthType 第三方登錄類型
     * @param callback  攜帶返回的信息
     * @return 登錄成功后的信息
     */
    @RequestMapping("/{oauthType}/callback")
    public AuthResponse login(@PathVariable String oauthType, AuthCallback callback) {
        AuthRequest authRequest = factory.get(getAuthSource(oauthType));
        AuthResponse response = authRequest.login(callback);
        log.info("【response】= {}", JSONUtil.toJsonStr(response));
        return response;
    }

    private AuthSource getAuthSource(String type) {
        if (StrUtil.isNotBlank(type)) {
            return AuthSource.valueOf(type.toUpperCase());
        } else {
            throw new RuntimeException("不支持的類型");
        }
    }
}

3.2. 緩存配置

starter 內置了2種緩存實現,一種是上面的默認實現,另一種是基於 Redis 的緩存實現。

當然了,你也可以自定義實現你自己的緩存。

3.2.1. 默認緩存實現

在配置文件配置如下內容即可

justauth:
  cache:
    type: default

3.2.2. Redis 緩存實現

1.添加 Redis 相關依賴

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!-- 對象池,使用redis時必須引入 -->
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-pool2</artifactId>
</dependency>
2.配置文件配置如下內容即可
justauth:
  cache:
    type: redis
    # 緩存前綴,目前只對redis緩存生效,默認 JUSTAUTH::STATE::
    prefix: ''
    # 超時時長,目前只對redis緩存生效,默認3分鍾
    timeout: 1h
spring:
  redis:
    host: localhost
    # 連接超時時間(記得添加單位,Duration)
    timeout: 10000ms
    # Redis默認情況下有16個分片,這里配置具體使用的分片
    # database: 0
    lettuce:
      pool:
        # 連接池最大連接數(使用負值表示沒有限制) 默認 8
        max-active: 8
        # 連接池最大阻塞等待時間(使用負值表示沒有限制) 默認 -1
        max-wait: -1ms
        # 連接池中的最大空閑連接 默認 8
        max-idle: 8
        # 連接池中的最小空閑連接 默認 0
        min-idle: 0

3.2.3. 自定義緩存實現

1.配置文件配置如下內容

justauth:
  cache:
    type: custom
2.自定義緩存實現 AuthStateCache 接口
/**
 * <p>
 * 自定義緩存實現
 * </p>
 *
 * @author yangkai.shen
 * @date Created in 2019/8/31 12:53
 */
public class MyAuthStateCache implements AuthStateCache {
    /**
     * 存入緩存
     *
     * @param key   緩存key
     * @param value 緩存內容
     */
    @Override
    public void cache(String key, String value) {
        // TODO: 自定義存入緩存
    }

    /**
     * 存入緩存
     *
     * @param key     緩存key
     * @param value   緩存內容
     * @param timeout 指定緩存過期時間(毫秒)
     */
    @Override
    public void cache(String key, String value, long timeout) {
        // TODO: 自定義存入緩存
    }

    /**
     * 獲取緩存內容
     *
     * @param key 緩存key
     * @return 緩存內容
     */
    @Override
    public String get(String key) {
        // TODO: 自定義獲取緩存內容
        return null;
    }

    /**
     * 是否存在key,如果對應key的value值已過期,也返回false
     *
     * @param key 緩存key
     * @return true:存在key,並且value沒過期;false:key不存在或者已過期
     */
    @Override
    public boolean containsKey(String key) {
        // TODO: 自定義判斷key是否存在
        return false;
    }
}
3.自動裝配 JustAuthConfig
/**
 * <p>
 * 自定義緩存裝配
 * </p>
 *
 * @author yangkai.shen
 * @date Created in 2019/8/31 12:29
 */
@Configuration
public class AuthStateConfiguration {
    @Bean
    public AuthStateCache authStateCache() {
        return new MyAuthStateCache();
    }
}

3.3. 自定義第三方平台配置

1.創建自定義的平台枚舉類

/**
 * <p>
 * 擴展的自定義 source
 * </p>
 *
 * @author yangkai.shen
 * @date Created in 2019/10/9 14:14
 */
public enum ExtendSource implements AuthSource {

    /**
     * 測試
     */
    TEST {
        /**
         * 授權的api
         *
         * @return url
         */
        @Override
        public String authorize() {
            return "http://authorize";
        }

        /**
         * 獲取accessToken的api
         *
         * @return url
         */
        @Override
        public String accessToken() {
            return "http://accessToken";
        }

        /**
         * 獲取用戶信息的api
         *
         * @return url
         */
        @Override
        public String userInfo() {
            return null;
        }

        /**
         * 取消授權的api
         *
         * @return url
         */
        @Override
        public String revoke() {
            return null;
        }

        /**
         * 刷新授權的api
         *
         * @return url
         */
        @Override
        public String refresh() {
            return null;
        }
    }
}
2.創建自定義的請求處理
/**
 * <p>
 * 測試用自定義擴展的第三方request
 * </p>
 *
 * @author yangkai.shen
 * @date Created in 2019/10/9 14:19
 */
public class ExtendTestRequest extends AuthDefaultRequest {

    public ExtendTestRequest(AuthConfig config) {
        super(config, ExtendSource.TEST);
    }

    public ExtendTestRequest(AuthConfig config, AuthStateCache authStateCache) {
        super(config, ExtendSource.TEST, authStateCache);
    }

    /**
     * 獲取access token
     *
     * @param authCallback 授權成功后的回調參數
     * @return token
     * @see AuthDefaultRequest#authorize()
     * @see AuthDefaultRequest#authorize(String)
     */
    @Override
    protected AuthToken getAccessToken(AuthCallback authCallback) {
        return AuthToken.builder().openId("openId").expireIn(1000).idToken("idToken").scope("scope").refreshToken("refreshToken").accessToken("accessToken").code("code").build();
    }

    /**
     * 使用token換取用戶信息
     *
     * @param authToken token信息
     * @return 用戶信息
     * @see AuthDefaultRequest#getAccessToken(AuthCallback)
     */
    @Override
    protected AuthUser getUserInfo(AuthToken authToken) {
        return AuthUser.builder().username("test").nickname("test").gender(AuthUserGender.MALE).token(authToken).source(this.source.toString()).build();
    }

    /**
     * 撤銷授權
     *
     * @param authToken 登錄成功后返回的Token信息
     * @return AuthResponse
     */
    @Override
    public AuthResponse revoke(AuthToken authToken) {
        return AuthResponse.builder().code(AuthResponseStatus.SUCCESS.getCode()).msg(AuthResponseStatus.SUCCESS.getMsg()).build();
    }

    /**
     * 刷新access token (續期)
     *
     * @param authToken 登錄成功后返回的Token信息
     * @return AuthResponse
     */
    @Override
    public AuthResponse refresh(AuthToken authToken) {
        return AuthResponse.builder().code(AuthResponseStatus.SUCCESS.getCode()).data(AuthToken.builder().openId("openId").expireIn(1000).idToken("idToken").scope("scope").refreshToken("refreshToken").accessToken("accessToken").code("code").build()).build();
    }
}
3.在配置文件配置相關信息
justauth:
  enabled: true
  extend:
    enum-class: com.xkcoding.justauthspringbootstarterdemo.extend.ExtendSource
    config:
      TEST:
        request-class: com.xkcoding.justauthspringbootstarterdemo.extend.ExtendTestRequest
        client-id: xxxxxx
        client-secret: xxxxxxxx
        redirect-uri: http://oauth.xkcoding.com/demo/oauth/test/callback

4. http 代理配置

修改配置文件,增加如下配置:

justauth:
  http-config:
    timeout: 30000
    proxy:
      GOOGLE:
        type: HTTP
        hostname: 127.0.0.1
        port: 10080
注:當項目中使用了自定義的第三方登錄,並且需要使用代理時,也要在 http-config 節點下添加相關配置,格式參考上面示例

5. 自定義 Scopes

修改配置文件,增加如下配置:

justauth:
  enabled: true
  type:
    QQ:
      client-id: 10**********6
      client-secret: 1f7d08**********5b7**********29e
      redirect-uri: http://oauth.xkcoding.com/demo/oauth/qq/callback
      union-id: false
      scopes:
       - get_user_info
       - xxxx
注:你可以前往 me.zhyd.oauth.enums.scope 包下查看各個渠道所支持的 scopes,當然你可以不配置該項,JustAuth 會默認添加上一些基礎 scope


6. 附錄

6.1. justauth 配置列表

java.util.Map<me.zhyd.oauth.config.AuthSource,com.xkcoding.justauth.autoconfigure.JustAuthProperties.JustAuthHttpConfig>

com.xkcoding.justauth.autoconfigure.CacheProperties

com.xkcoding.justauth.autoconfigure.ExtendProperties

屬性名 類型 默認值 可選項 描述

justauth.enabled

boolean

true

true/false

是否啟用 JustAuth

justauth.type

java.util.Map<me.zhyd.oauth.config.AuthSource,me.zhyd.oauth.config.AuthConfig>

JustAuth 配置

justauth.httpConfig

http 相關配置

justauth.cache

JustAuth緩存配置

justauth.extend

JustAuth第三方平台配置

justauth.type 配置列表

屬性名 描述
justauth.type.keys justauth.typeMap 格式的,key 的取值請參考AuthDefaultSource
justauth.type.keys.values justauth.typeMap 格式的,value 的取值請參考 AuthConfig

justauth.type.keys.values 所有可選配置如下:

屬性名

描述

備注

client-id

客戶端id,對應各平台的appKey

必填

client-secret

客戶端Secret,對應各平台的appSecret

必填

redirect-uri

登錄成功后的回調地址

必填

alipay-public-key

支付寶公鑰

當使用支付寶登錄時, 該值必填,對應“RSA2(SHA256)密鑰”中的“支付寶公鑰”

union-id

是否需要申請unionid

當使用QQ登錄時,該值選填,如果置為true則qq開發者應用必須具備相應權限,參考鏈接:查看詳情

stack-overflow-key

Stack Overflow Key

當使用Stack Overflow登錄時, 該值必填

agent-id

企業微信,授權方的網頁應用ID

當使用企業微信登錄時, 該值必填

coding-group-name

團隊域名前綴

使用 Coding 登錄時, 該值必填

justauth.httpConfig 配置列表

屬性名

描述

justauth.httpConfig.keys

justauth.type 是 Map 格式的,key 的取值請參考 AuthDefaultSource

justauth.httpConfig.keys.values

justauth.type 是 Map 格式的,value 的取值請參考 JustAuthProperties.JustAuthHttpConfig

justauth.httpConfig.keys.values 所有可選配置如下:

屬性名

描述

備注

timeout

請求超時時間

proxy

代理的相關配置,針對國外平台,需要配置代理

必填

justauth.httpConfig.proxy 所有可選配置如下:

屬性名

描述

備注

type

代理類型,可選值:HTTP、DIRECT、SOCKS,默認為 HTTP

hostname

代理 IP 地址

port

代理端口

justauth.cache 配置列表

屬性名

類型

默認值

可選項

描述

justauth.cache.type

com.xkcoding.justauth.autoconfigure.CacheProperties.CacheType

default

default/redis/custom

緩存類型,default使用JustAuth默認的緩存實現,redis使用默認的redis緩存實現,custom用戶自定義緩存實現

justauth.cache.prefix

java.lang.String

JUSTAUTH::STATE::

緩存前綴,目前只對redis緩存生效,默認 JUSTAUTH::STATE::

justauth.cache.timeout

java.time.Duration

3分鍾

超時時長,目前只對redis緩存生效,默認3分鍾

justauth.extend 配置列表

屬性名

類型

默認值

可選項

描述

justauth.extend.enum-class

Class<? extends AuthSource>

枚舉類全路徑

justauth.extend.config

java.util.Map<String, ExtendRequestConfig>

對應配置信息

justauth.extend.config 配置列表

屬性名

類型

默認值

可選項

描述

justauth.extend.config.keys

java.lang.String

key 必須在 justauth.extend.enum-class 配置的枚舉類中聲明

justauth.extend.config.values

com.xkcoding.justauth.autoconfigure.ExtendProperties.ExtendRequestConfig

value 就是 AuthConfig 的子類,增加了一個 request-class 屬性配置請求的全類名,具體參考類ExtendProperties.ExtendRequestConfig

2. SNAPSHOT版本

如果需要體驗快照版本,可以在你的 pom.xml進行如下配置:

<repositories>
    <!--阿里雲私服-->
    <repository>
      <id>aliyun</id>
      <name>aliyun</name>
      <url>http://maven.aliyun.com/nexus/content/groups/public</url>
    </repository>
    <!--中央倉庫-->
    <repository>
      <id>oss</id>
      <name>oss</name>
      <url>http://oss.sonatype.org/content/repositories/snapshots</url>
      <releases>
        <enabled>true</enabled>
      </releases>
      <snapshots>
        <enabled>true</enabled>
      </snapshots>
    </repository>
</repositories>



參考:

https://blog.csdn.net/andyliulin/article/details/100008643

https://github.com/justauth/justauth-spring-boot-starter

https://github.com/justauth/justauth-spring-boot-starter-demo


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM