在我們的專案開發中,使用
第三方登錄(如QQ登錄、微信登錄等)可以更加方便、輕松地實作用戶登錄,
在以往的開發程序中,如果要使專案實作第三方登錄功能,一般程序是閱讀官網的開發檔案,并下載其JDK(或者依賴pom),然后進行開發實作,
但是,如果網站要實作多個第三方平臺的登錄功能,則需要很高的學習成本,
所以,就有開發者實作了一款基于Spring Boot的開箱即用的整合第三方登錄的開源組件:JustAuth
該插件的網址:https://justauth.wiki
本文將基于Spring Boot,使用JustAuth組件實作第三方快捷登錄,并獲取用戶的uid,
1. 插件簡介
首先給出幾個鏈接:
- 組件的幫助檔案:https://justauth.wiki
- 組件的GitHub:https://github.com/justauth/JustAuth
- 組件的Gitee組織:https://gitee.com/justauth/
在組件的各個網址,都可以看到關于該組件的自述:
小而全而美的第三方登錄開源組件,目前已支持Github、Gitee、微博、釘釘、百度、Coding、騰訊云開發者平臺、OSChina、支付寶、QQ、微信、淘寶、Google、Facebook、抖音、領英、小米、微軟、今日頭條、Teambition、StackOverflow、Pinterest、人人、華為、企業微信、酷家樂、Gitlab、美團、餓了么和推特等第三方平臺的授權登錄, Login, so easy!
可以看出,此組件支持的第三方登錄平臺,是非常全的,
下面,以QQ和微博為例,測驗Spring Boot上使用該組件完成第三方登錄快速開發,
- 建議參考組件的幫助檔案,均有詳細說明,
- 或者直接參考官方的demo:https://github.com/justauth/JustAuth-demo
- 開發之前,需要前往
QQ開放平臺和微博開放平臺申請應用,并獲取appid、APP secret,設定callback url,參考:
- https://blog.csdn.net/cxh_1231/article/details/114984731
- https://blog.csdn.net/cxh_1231/article/details/115068413
2. 專案創建與導包
關于Spring Boot專案如何創建,可參考以下幾篇文章:
- Idea創建Spring Boot專案
- Spring Boot 常用配置
- Spring Boot整合Thymeleaf
只看前兩個就可以了,
創建完成專案之后,在pom.xml檔案中,匯入依賴:
<!--JustAuth-->
<dependency>
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
<version>1.15.9</version>
</dependency>
<!--http請求相關-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
<version>5.3.9</version>
</dependency>
<!--匯入lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
<scope>provided</scope>
</dependency>
<!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
這里匯入了4個依賴,說明如下:
第一個是
JustAuth組件必須的,版本就默認使用幫助檔案中的最新版,如下圖所示,

第二個是
http請求的實作組件,這是因為JustAuth從 v1.14.0開始不會默認集成hutool-http,需要單獨添加;
第三個是
lombok,即自動生成模型的set和get,因為專案中授權登錄成功后,回傳的用戶資訊模型,使用了@Getter和@Setter注解,添加此組件,方便獲取用戶的單個資訊(如uuid、nickname等),

第四個是阿里巴巴的
fastjson組件,因為在回傳的結果中,有些資訊是封裝成JSON格式的,需要使用該組件來轉換成map鍵值對,從而獲取對我們有用的資訊,

3. QQ登錄實作
1、 新建一個名為 PluginController 的控制類,用來實作第三方插件的登錄回呼功能,
package com.demo.controller;
import org.springframework.web.bind.annotation.*;
/**
* Info:登錄組件測驗
*
* @author: 拾年之璐
* @date: 2021-03-15 0015 19:27
*/
@RestController
@RequestMapping(value = "/plugin")
public class PluginController {
}
2、創建一個AuthRequest介面的實作類,用于生成登錄鏈接、登錄并獲取用戶資訊等
/**
* 授權介面類
*
* @return 各種請求的結果
*/
private AuthRequest getQQAuthRequest() {
return new AuthQqRequest(AuthConfig.builder()
.clientId("APPID")
.clientSecret("Your APP Secret")
.redirectUri("http://XXX.com/plugin/qqlogin/callback")
.unionId(true) //如果獲取用戶的UnionID,則設定為true
.build());
}
3、生成登錄鏈接并跳轉至登錄頁面
/**
* 跳轉至登錄頁面
*
* @param response 頁面跳轉
* @throws IOException
*/
@RequestMapping("/qqlogin")
public void qqlogin(HttpServletResponse response) throws IOException {
//獲取物件
AuthRequest authRequest = getQQAuthRequest();
//列印生成的鏈接
System.out.println("生成登錄鏈接:" + authRequest.authorize("yourState"));
//頁面跳轉,其中state引數可自定義
response.sendRedirect(authRequest.authorize(AuthStateUtils.createState()));
}
這時,控制臺可以列印出生成的登錄URL

瀏覽器訪問http://XXX.com/plugin/qqlogin,即可跳轉至此登錄頁面

4、回呼頁面plugin/qqlogin/callback獲取回傳的code,并通過回傳的code獲取當前登錄用戶的資訊
如下:
/**
* QQ登錄成功后回傳到此頁
*
* @param callback 登錄用戶的資訊
* @return
*/
@RequestMapping("/qqlogin/callback")
public Object qqloginCallback(AuthCallback callback) {
AuthRequest authRequest = getQQAuthRequest();
// 列印回傳的授權資訊(QQ登錄為code,通過code獲取用戶資訊)
System.out.println(callback.getCode());
//根據回傳的引數,執行登錄請求(獲取用戶資訊)
AuthResponse<AuthUser> authResponse = authRequest.login(callback);
// 將JSON包回傳到前端頁面顯示
return authResponse;
}
上面的圖,點擊登錄后,即可跳轉至回呼頁面,顯示出所有的JSON資料,如下圖所示:

我們對該JSON資料進行分析:
- 回傳的
code是2000,表示獲取資料成功(其他代碼,可以在https://justauth.wiki/quickstart/error_code.html查看); - 回傳的
data資料,包含所有有用的資訊,如用戶IDuuid、用戶昵稱username、頭像avatar、性別gender等等; data下的token,包含所有的獲取token、重繪token和過期時間等資訊;data下的rawUserInfo,是第三方平臺回傳的原始用戶資訊;- 關于回傳的JSON資料的每個子段的
詳細含義,都可以在模型AuthUser中查看,
5、后臺獲取指定資訊
上面可以獲取所有的用戶資訊,但這些資訊,我們并不能這樣使用,而是篩選有用的資訊,然后保存到自己的資料庫,
所以下面這個完整示例,演示如何獲取上述JSON中的指定資訊,
/**
* QQ登錄成功后回傳到此頁
*
* @param callback 登錄用戶的資訊
* @return
*/
@RequestMapping("/qqlogin/callback")
public Object qqloginCallback(AuthCallback callback) {
//獲取實體
AuthRequest authRequest = getQQAuthRequest();
// 列印回傳的授權資訊(QQ登錄為code,通過code獲取用戶資訊)
System.out.println(callback.getCode());
//根據回傳的引數,執行登錄請求(獲取用戶資訊)
AuthResponse<AuthUser> authResponse = authRequest.login(callback);
//列印授權回傳代碼(2000 表示成功,可以用來判斷用戶登錄成功與否)
System.out.println("狀態碼:"+authResponse.getCode());
//列印用戶的昵稱、ID、頭像等基本資訊
System.out.println("用戶的UnionID:" + authResponse.getData().getUuid());
System.out.println("用戶的昵稱:" + authResponse.getData().getNickname());
System.out.println("用戶的頭像:" + authResponse.getData().getAvatar());
//列印用戶的Token中的資訊
System.out.println("access_token:" + authResponse.getData().getToken().getAccessToken());
System.out.println("用戶的OpenId:" + authResponse.getData().getToken().getOpenId());
// 列印更加詳細的資訊(第三方平臺回傳的原始用戶資訊)
//getInnerMap():將JSONObject轉換成Map鍵值對
System.out.println("用戶的城市:" + authResponse.getData().getRawUserInfo().getInnerMap().get("city"));
System.out.println("用戶的年份:" + authResponse.getData().getRawUserInfo().getInnerMap().get("year"));
// 將JSON包回傳到前端頁面顯示
return authResponse;
}
其實這段代碼,和JSON資料,是一一對應的,如下圖所示:

列印結果:

4. 微博登錄實作
有了上面QQ登錄的詳細分析,微博登錄也是類似的,這里速戰速決,
1、創建授權請求類
/**
* 生成微博授權登錄的類getWbAuthRequest
*
* @return
*/
private AuthRequest getWbAuthRequest() {
return new AuthWeiboRequest(AuthConfig.builder()
.clientId("appid")
.clientSecret("app secret")
.redirectUri("http://xxx.com/plugin/sinalogin/callback")
.build());
}
2、生成并跳轉登錄鏈接
/**
* 微博登錄頁面,生成登錄鏈接
*
* @param response 頁面跳轉
* @throws IOException
*/
@RequestMapping("/wblogin")
public void wblogin(HttpServletResponse response) throws IOException {
//生成物件
AuthRequest authRequest = getWbAuthRequest();
//生成鏈接并回傳,其中state可以自定義,可以用來實作第四方登錄
response.sendRedirect(authRequest.authorize(AuthStateUtils.createState()));
}
結果:

3、回呼頁面獲取資訊,以及回傳JSON資料
/**
* 回呼頁面,獲取登錄用戶新
*
* @param callback 詳細JSON資訊
* @return
*/
@RequestMapping("/sinalogin/callback")
public Object wbloginCallback(AuthCallback callback) {
//生成物件
AuthRequest authRequest = getWbAuthRequest();
//獲取登錄后回傳的用戶資訊結果
AuthResponse<AuthUser> authResponse = authRequest.login(callback);
//列印授權回傳代碼(2000 表示成功,可以用來判斷用戶登錄成功與否)
System.out.println("狀態碼:" + authResponse.getCode());
//列印用戶的昵稱、ID、頭像等基本資訊
System.out.println("用戶的UnionID:" + authResponse.getData().getUuid());
System.out.println("用戶的昵稱:" + authResponse.getData().getNickname());
System.out.println("用戶的頭像:" + authResponse.getData().getAvatar());
//列印用戶的Token中的資訊
System.out.println("access_token:" + authResponse.getData().getToken().getAccessToken());
System.out.println("用戶的OpenId:" + authResponse.getData().getToken().getOpenId());
// 列印更加詳細的資訊(第三方平臺回傳的原始用戶資訊)
System.out.println("用戶的城市:" + authResponse.getData().getRawUserInfo().getInnerMap().get("city"));
System.out.println("用戶的年份:" + authResponse.getData().getRawUserInfo().getInnerMap().get("year"));
//回傳JSON資訊
return authResponse;
}
結果:

5. 完整Controller原始碼
package com.demo.controller;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthQqRequest;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.request.AuthWeiboRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Info:登錄組件測驗
*
* @author: 拾年之璐
* @date: 2021-03-22 0022 19:31
*/
@RestController
@RequestMapping(value = "/plugin")
public class PluginController {
/**
* QQ登錄request類
*
* @return 鏈接
*/
private AuthRequest getQQAuthRequest() {
return new AuthQqRequest(AuthConfig.builder()
.clientId("appid")
.clientSecret("appsecret")
.redirectUri("http://xxx.com/plugin/qqlogin/callback")
.unionId(true)
.build());
}
/**
* 跳轉至登錄頁面
*
* @param response 頁面跳轉
* @throws IOException
*/
@RequestMapping("/qqlogin")
public void qqlogin(HttpServletResponse response) throws IOException {
//獲取實體
AuthRequest authRequest = getQQAuthRequest();
//列印生成的鏈接
System.out.println("生成登錄鏈接:" + authRequest.authorize("yourState"));
System.out.println();
//頁面跳轉,其中state引數可自定義
response.sendRedirect(authRequest.authorize(AuthStateUtils.createState()));
}
/**
* QQ登錄成功后回傳到此頁
*
* @param callback 登錄用戶的資訊
* @return
*/
@RequestMapping("/qqlogin/callback")
public Object qqloginCallback(AuthCallback callback) {
//獲取實體
AuthRequest authRequest = getQQAuthRequest();
// 列印回傳的授權資訊(QQ登錄為code,通過code獲取用戶資訊)
System.out.println(callback.getCode());
//根據回傳的引數,執行登錄請求(獲取用戶資訊)
AuthResponse<AuthUser> authResponse = authRequest.login(callback);
//列印授權回傳代碼(2000 表示成功,可以用來判斷用戶登錄成功與否)
System.out.println("狀態碼:" + authResponse.getCode());
//列印用戶的昵稱、ID、頭像等基本資訊
System.out.println("用戶的UnionID:" + authResponse.getData().getUuid());
System.out.println("用戶的昵稱:" + authResponse.getData().getNickname());
System.out.println("用戶的頭像:" + authResponse.getData().getAvatar());
//列印用戶的Token中的資訊
System.out.println("access_token:" + authResponse.getData().getToken().getAccessToken());
System.out.println("用戶的OpenId:" + authResponse.getData().getToken().getOpenId());
// 列印更加詳細的資訊(第三方平臺回傳的原始用戶資訊)
System.out.println("用戶的城市:" + authResponse.getData().getRawUserInfo().getInnerMap().get("city"));
System.out.println("用戶的年份:" + authResponse.getData().getRawUserInfo().getInnerMap().get("year"));
// 將JSON包回傳到前端頁面顯示
return authResponse;
}
/**
* 生成微博授權登錄的類getWbAuthRequest
*
* @return
*/
private AuthRequest getWbAuthRequest() {
return new AuthWeiboRequest(AuthConfig.builder()
.clientId("appid")
.clientSecret("appsecret")
.redirectUri("http://xxx.com/plugin/sinalogin/callback")
.build());
}
/**
* 微博登錄頁面,生成登錄鏈接
*
* @param response 頁面跳轉
* @throws IOException
*/
@RequestMapping("/wblogin")
public void wblogin(HttpServletResponse response) throws IOException {
//生成物件
AuthRequest authRequest = getWbAuthRequest();
//生成鏈接并回傳,其中state可以自定義,可以用來實作第四方登錄
response.sendRedirect(authRequest.authorize(AuthStateUtils.createState()));
}
/**
* 回呼頁面,獲取登錄用戶新
*
* @param callback 詳細JSON資訊
* @return
*/
@RequestMapping("/sinalogin/callback")
public Object wbloginCallback(AuthCallback callback) {
//生成物件
AuthRequest authRequest = getWbAuthRequest();
//獲取登錄后回傳的用戶資訊結果
AuthResponse<AuthUser> authResponse = authRequest.login(callback);
//列印授權回傳代碼(2000 表示成功,可以用來判斷用戶登錄成功與否)
System.out.println("狀態碼:" + authResponse.getCode());
//列印用戶的昵稱、ID、頭像等基本資訊
System.out.println("用戶的UnionID:" + authResponse.getData().getUuid());
System.out.println("用戶的昵稱:" + authResponse.getData().getNickname());
System.out.println("用戶的頭像:" + authResponse.getData().getAvatar());
//列印用戶的Token中的資訊
System.out.println("access_token:" + authResponse.getData().getToken().getAccessToken());
System.out.println("用戶的OpenId:" + authResponse.getData().getToken().getOpenId());
// 列印更加詳細的資訊(第三方平臺回傳的原始用戶資訊)
System.out.println("用戶的城市:" + authResponse.getData().getRawUserInfo().getInnerMap().get("city"));
System.out.println("用戶的年份:" + authResponse.getData().getRawUserInfo().getInnerMap().get("year"));
//回傳JSON資訊
return authResponse;
}
/**
* 銷毀
*/
@RequestMapping("/revoke/{token}")
public Object revokeAuth(@PathVariable("token") String token) throws IOException {
AuthRequest authRequest = getWbAuthRequest();
return authRequest.revoke(AuthToken.builder().accessToken(token).build());
}
}
當然,還有其他各個平臺,如:

每個平臺的授權登錄實作方式大同小異,此處不再贅述,
參考資料:
- https://justauth.wiki/quickstart/explain.html
- https://justauth.wiki/oauth/qq.html
- https://justauth.wiki/oauth/weibo.html
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/271605.html
標籤:其他
上一篇:記:2020.3.31
