SpringBoot+Vue如何集成第三方登錄JustAuth

前言

這兩天打算給蘑菇博客增加第三方登錄模塊,所有對目前的第三方登錄的Github和Gitee中的Demo進行的調查,發現在gitee有個做的非常不錯的項目:史上最全的整合第三方登錄的開源庫。目前已支持Github、Gitee、微博、釘釘、百度、Coding、騰訊雲開發者平臺、OSChina、支付寶、QQ、微信、淘寶、Google、Facebook、抖音、領英、小米、微軟、今日頭條、Teambition、StackOverflow、Pinterest、人人、華為、企業微信、酷家樂、Gitlab、美團、餓了麼和推特等第三方平臺的授權登錄。 Login, so easy!

JustAuth倉庫:https://gitee.com/yadong.zhang/JustAuth

JustAuth文檔:https://docs.justauth.whnb.wang/#/

編寫登錄頁面Vue樣式和代碼

首先需要編寫一個登錄框代碼,下面是使用vue創建了一個組件 LoginBox,同時裡面還引入了阿里矢量庫中的幾個圖標,感興趣的小夥伴可以查看這篇博客:Vue項目使用阿里巴巴矢量圖標庫

<code><template>  
登錄
X
<el-divider> <el-form> <el-form-item> <el-input> /<el-form-item> <el-form-item> <el-input> /<el-form-item> <el-row> <el-button>登錄/<el-button> <el-button>註冊/<el-button> /<el-row> <el-row> <el-tooltip> <el-button>  /<el-button> /<el-tooltip> <el-tooltip> <el-button>  /<el-button> /<el-tooltip> <el-tooltip> <el-button>  /<el-button> /<el-tooltip> <el-tooltip> <el-button>  /<el-button> /<el-tooltip> /<el-row>
登錄過的用戶請沿用之前的登錄方式
/<el-form>
登錄
X
<el-divider> <el-form> <el-form-item> <el-input> /<el-form-item> <el-form-item> <el-input> /<el-form-item> <el-form-item> <el-input> /<el-form-item> <el-form-item> <el-input> /<el-form-item> <el-row> <el-button>註冊/<el-button> <el-button>返回登錄/<el-button> /<el-row>
註冊後,需要到郵箱進行郵件認證~
/<el-form>
/<template>/<code>

下面是運行後的結果如下所示

SpringBoot+Vue如何集成第三方登錄JustAuth

因為目前沒打算自己製作登錄和註冊功能,所以用戶名、密碼、以及登錄和註冊都被設置成disabled了,下面是引入的接口:login

<code>import request from '@/utils/request'export function login(params) {  return request({    url: process.env.WEB_API + '/oauth/render',    method: 'post',    params  })}/<code>

引入第三方登錄

完成了前端的頁面後,我們就需要撰寫後端代碼了

首先需要引入JustAuth的Maven依賴,我們在pom文件中添加對應依賴

<code><dependency>    <groupid>me.zhyd.oauth/<groupid>    <artifactid>JustAuth/<artifactid>    <version>1.13.1/<version>/<dependency>/<code>

然後在編寫定義一個Controller,這裡我創建了一個AuthRestApi.java文件

<code>package com.moxi.mogublog.web.restapi;import com.alibaba.fastjson.JSONObject;import com.moxi.mogublog.utils.JsonUtils;import com.moxi.mogublog.utils.ResultUtil;import com.moxi.mogublog.utils.StringUtils;import com.moxi.mogublog.web.global.MessageConf;import com.moxi.mogublog.web.global.SQLConf;import com.moxi.mogublog.web.global.SysConf;import com.moxi.mogublog.xo.entity.User;import com.moxi.mogublog.xo.service.UserService;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import me.zhyd.oauth.config.AuthConfig;import me.zhyd.oauth.exception.AuthException;import me.zhyd.oauth.model.AuthCallback;import me.zhyd.oauth.model.AuthResponse;import me.zhyd.oauth.model.AuthToken;import me.zhyd.oauth.request.AuthGiteeRequest;import me.zhyd.oauth.request.AuthGithubRequest;import me.zhyd.oauth.request.AuthRequest;import me.zhyd.oauth.utils.AuthStateUtils;import org.apache.log4j.LogManager;import org.apache.log4j.Logger;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.web.bind.annotation.GetMapping;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.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;import java.util.HashMap;import java.util.Map;import java.util.concurrent.TimeUnit;/** * 第三方登錄認證 */@RestController@RequestMapping("/oauth")@Api(value = "認證RestApi", tags = {"AuthRestApi"})public class AuthRestApi {    private static Logger log = LogManager.getLogger(IndexRestApi.class);    @Autowired    private UserService userService;    @Value(value = "${justAuth.clientId.gitee}")    private String giteeClienId;    @Value(value = "${justAuth.clientSecret.gitee}")    private String giteeClientSecret;    @Value(value = "${justAuth.clientId.github}")    private String githubClienId;    @Value(value = "${justAuth.clientSecret.github}")    private String githubClientSecret;    @Value(value = "${data.webSite.url}")    private String webSiteUrl;    @Value(value = "${data.web.url}")    private String moguWebUrl;    @Value(value = "${BLOG.USER_TOKEN_SURVIVAL_TIME}")    private Long userTokenSurvivalTime;    @Autowired    private StringRedisTemplate stringRedisTemplate;    @ApiOperation(value = "獲取認證", notes = "獲取認證")    @RequestMapping("/render")    public String renderAuth(String source, HttpServletResponse response) throws IOException {        log.info("進入render:" + source);        AuthRequest authRequest = getAuthRequest(source);        String token = AuthStateUtils.createState();        String authorizeUrl = authRequest.authorize(token);        Map<string> map = new HashMap<>();        map.put(SQLConf.URL, authorizeUrl);        return ResultUtil.result(SysConf.SUCCESS, map);    }    /**     * oauth平臺中配置的授權回調地址,以本項目為例,在創建gitee授權應用時的回調地址應為:http://127.0.0.1:8603/oauth/callback/gitee     */    @RequestMapping("/callback/{source}")    public void login(@PathVariable("source") String source, AuthCallback callback, HttpServletRequest request, HttpServletResponse httpServletResponse) throws IOException {        log.info("進入callback:" + source + " callback params:" + JSONObject.toJSONString(callback));        AuthRequest authRequest = getAuthRequest(source);        AuthResponse response = authRequest.login(callback);        String result = JSONObject.toJSONString(response);        System.out.println(JSONObject.toJSONString(response));        Map<string> map = JsonUtils.jsonToMap(result);        Map<string> data = JsonUtils.jsonToMap(JsonUtils.objectToJson(map.get(SysConf.DATA)));        Map<string> token = JsonUtils.jsonToMap(JsonUtils.objectToJson(data.get(SysConf.TOKEN)));        String accessToken = token.get(SysConf.ACCESS_TOKEN).toString();        User user = userService.insertUserInfo(request, result);        if (user != null) {            //將從數據庫查詢的數據緩存到redis中            stringRedisTemplate.opsForValue().set(SysConf.USER_TOEKN + SysConf.REDIS_SEGMENTATION + accessToken, JsonUtils.objectToJson(user), userTokenSurvivalTime, TimeUnit.SECONDS);        }        httpServletResponse.sendRedirect(webSiteUrl + "?token=" + accessToken);    }    @RequestMapping("/revoke/{source}/{token}")    public Object revokeAuth(@PathVariable("source") String source, @PathVariable("token") String token) throws IOException {        AuthRequest authRequest = getAuthRequest(source);        return authRequest.revoke(AuthToken.builder().accessToken(token).build());    }    @RequestMapping("/refresh/{source}")    public Object refreshAuth(@PathVariable("source") String source, String token) {        AuthRequest authRequest = getAuthRequest(source);        return authRequest.refresh(AuthToken.builder().refreshToken(token).build());    }    @ApiOperation(value = "獲取用戶信息", notes = "獲取用戶信息")    @GetMapping("/verify/{accessToken}")    public String verifyUser(@PathVariable("accessToken") String accessToken) {        String userInfo = stringRedisTemplate.opsForValue().get("TOKEN:" + accessToken);        if (StringUtils.isEmpty(userInfo)) {            return ResultUtil.result(SysConf.ERROR, MessageConf.INVALID_TOKEN);        } else {            Map<string> map = JsonUtils.jsonToMap(userInfo);            return ResultUtil.result(SysConf.SUCCESS, map);        }    }    @ApiOperation(value = "刪除accessToken", notes = "刪除accessToken")    @RequestMapping("/delete/{accessToken}")    public String deleteUserAccessToken(@PathVariable("accessToken") String accessToken) {        stringRedisTemplate.delete(SysConf.USER_TOEKN + SysConf.REDIS_SEGMENTATION + accessToken);        return ResultUtil.result(SysConf.SUCCESS, MessageConf.DELETE_SUCCESS);    }    private AuthRequest getAuthRequest(String source) {        AuthRequest authRequest = null;        switch (source) {            case SysConf.GITHUB:                authRequest = new AuthGithubRequest(AuthConfig.builder()                        .clientId(githubClienId)                        .clientSecret(githubClientSecret)                        .redirectUri(moguWebUrl + "/oauth/callback/github")                        .build());                break;            case SysConf.GITEE:                authRequest = new AuthGiteeRequest(AuthConfig.builder()                        .clientId(giteeClienId)                        .clientSecret(giteeClientSecret)                        .redirectUri(moguWebUrl + "/oauth/callback/gitee")                        .build());                break;            default:                break;        }        if (null == authRequest) {            throw new AuthException(MessageConf.OPERATION_FAIL);        }        return authRequest;    }}/<string>/<string>/<string>/<string>/<string>/<code>

application.yml部分配置文件如下所示:

<code>data:  # 門戶頁面  webSite:    url: http://localhost:9527/#/  # mogu_web網址,用於第三方登錄回調  web:    url: http://127.0.0.1:8603    # 第三方登錄justAuth:  clientId:    gitee: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX    github: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX  clientSecret:    gitee: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX    github: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX    /<code>

關於clientId和clientSecret獲取

需要到各自的碼雲和github設置上進行獲取:在碼雲中:我們首先進入設置頁面,然後選擇第三方應用,然後創建應用

SpringBoot+Vue如何集成第三方登錄JustAuth

然後開始填寫對應的內容

SpringBoot+Vue如何集成第三方登錄JustAuth

重新點擊第三方應用,獲取到對應的ClientID和Client Secret替換即可

SpringBoot+Vue如何集成第三方登錄JustAuth

Github上的操作同理,我們需要設置setting,然後選擇Developer settings,OAuth Apps:創建一個新的

SpringBoot+Vue如何集成第三方登錄JustAuth

這裡填寫的信息和剛剛碼雲上差不多

SpringBoot+Vue如何集成第三方登錄JustAuth

然後最後在創建成功後複製對應的ClientID和Client Secret即可:

SpringBoot+Vue如何集成第三方登錄JustAuth

關於AuthRestApi中方法的作用

在AuthRestApi中,下面幾個方法的主要作用是:

  • renderAuth:獲取認證,前端通過login方法,即訪問的是該接口,然後會創建一個認證請求,裡面調用了getAuthRequest方法
  • getAuthRequest:該方法需要傳入一個source參數,該參數主要是失敗用戶請求的接口,然後封裝一個URL,最後通過renderAuth返回到前臺頁面中,該方法前端接受後,最終會生成一個URL,然後跳轉到對應的頁面進行授權即可

例如下面的vue代碼:

<code>    goAuth: function (source) {        var params = new URLSearchParams();        params.append("source", source);        login(params).then(response => {          if (response.code == "success") {            console.log(response.data.url);            var token = response.data.token;            console.log(response);            window.location.href = response.data.url          }        });      },/<code>

vue代碼,就是通過source判斷我點擊的按鈕,如果是github,那麼source為 ”github“,然後調用後臺的登錄方法,通過傳遞的source,生成一個授權頁面url,最後我們通過window.location.href 跳轉到授權頁面:

SpringBoot+Vue如何集成第三方登錄JustAuth

回調的接口如下所示:

<code> /**     * oauth平臺中配置的授權回調地址,以本項目為例,在創建gitee授權應用時的回調地址應為:http://127.0.0.1:8603/oauth/callback/gitee     */    @RequestMapping("/callback/{source}")    public void login(@PathVariable("source") String source, AuthCallback callback, HttpServletRequest request, HttpServletResponse httpServletResponse) throws IOException {        log.info("進入callback:" + source + " callback params:" + JSONObject.toJSONString(callback));        AuthRequest authRequest = getAuthRequest(source);        AuthResponse response = authRequest.login(callback);        String result = JSONObject.toJSONString(response);        System.out.println(JSONObject.toJSONString(response));        Map<string> map = JsonUtils.jsonToMap(result);        Map<string> data = JsonUtils.jsonToMap(JsonUtils.objectToJson(map.get(SysConf.DATA)));        Map<string> token = JsonUtils.jsonToMap(JsonUtils.objectToJson(data.get(SysConf.TOKEN)));        String accessToken = token.get(SysConf.ACCESS_TOKEN).toString();        User user = userService.insertUserInfo(request, result);        if (user != null) {            //將從數據庫查詢的數據緩存到redis中            stringRedisTemplate.opsForValue().set(SysConf.USER_TOEKN + SysConf.REDIS_SEGMENTATION + accessToken, JsonUtils.objectToJson(user), userTokenSurvivalTime, TimeUnit.SECONDS);        }        httpServletResponse.sendRedirect(webSiteUrl + "?token=" + accessToken);    }/<string>/<string>/<string>/<code> 

我們需要將得到的用戶信息,存儲到數據庫,同時生成一個token,通過url的方式,傳遞到前臺,然後前臺得到token後,通過token獲取用戶信息:

<code>    @ApiOperation(value = "獲取用戶信息", notes = "獲取用戶信息")    @GetMapping("/verify/{accessToken}")    public String verifyUser(@PathVariable("accessToken") String accessToken) {        String userInfo = stringRedisTemplate.opsForValue().get("TOKEN:" + accessToken);        if (StringUtils.isEmpty(userInfo)) {            return ResultUtil.result(SysConf.ERROR, MessageConf.INVALID_TOKEN);        } else {            Map<string> map = JsonUtils.jsonToMap(userInfo);            return ResultUtil.result(SysConf.SUCCESS, map);        }    }/<string>/<code>

然後在vue項目中,我們只需要判斷是否有token通過url傳遞過來

<code> let token = this.getUrlVars()["token"];      // 判斷url中是否含有token      if (token != undefined) {        setCookie("token", token, 1)      }      // 從cookie中獲取token      token = getCookie("token")      if (token != undefined) {        authVerify(token).then(response => {          if (response.code == "success") {            this.isLogin = true;            this.userInfo = response.data;          } else {            this.isLogin = false;            delCookie("token");          }        });      } else {        this.isLogin = false; }/<code>

如果有,那麼就通過token獲取用戶信息,登錄完成後,就能夠看到頭像回顯了:

SpringBoot+Vue如何集成第三方登錄JustAuth


分享到:


相關文章: