(十五)ATP应用测试平台——使用JustAuth快速集成前后端分离的第三方扫码授权登录功能
Posted 北溟溟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(十五)ATP应用测试平台——使用JustAuth快速集成前后端分离的第三方扫码授权登录功能相关的知识,希望对你有一定的参考价值。
前言
扫码登录已经是很多官方网站的标配,为了快速登录一个网站,避免繁琐的注册、登录流程,很多网站都会选择跳过自身的注册登录功能,授权用户第三方登录,如微信扫码登录、百度扫码登录等等。本节内容我们以百度扫码登录为例,便于演示。(微信扫码需要公司账号注册,这里就果断放弃了,有账号的小伙伴可自行配置验证)其它登录只需要加入相应的配置即可集成,作者这里使用java反射机制实例化对应的扫码登录实例,所以代码层面不需要任何修改,加入相关账号配置即可。
正文
- 引入JustAuth第三方扫码集成依赖pom
<!-- https://mvnrepository.com/artifact/me.zhyd.oauth/JustAuth -->
<dependency>
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
<version>1.16.5</version>
</dependency>
- 注册百度开发者账号,申请应用
(1)百度开发者账号注册
注册地址:注册百度帐号
(2)百度开发者登录地址
登录地址:百度开发者中心-汇聚、开放、助力、共赢
(3)应用oauth授权配置
配置地址:管理控制台 - 百度开放云平台
- 后端代码
①application.yml配置扫码登录参数,可配置不同方式的扫码登录,这里以百度为例
oauth: list: - appName: BAIDU clientId: ar46mCkZ77v03pfUkGhZGogD clientSecret: ulQPHyrbisRCSQcD2nXMx3ygOcO2GNU5 redirectUri: http://4qfn3q.natappfree.cc/oauthUser/callback?appName=BAIDU
②OauthDataProperties.java加载扫码登录的配置参数
package com.yundi.atp.platform.util.oauth; import lombok.Data; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import java.util.List; /** * @Author: 北溟溟 * @Description: 第三方登录授权配置 * @Date: 2022/1/5 18:45 * @Version: 1.0.0 */ @Data @Component @ConfigurationProperties(prefix = "oauth") public class OauthDataProperties private List<OauthData> list; public static class OauthData /** * 应用名称:微信、QQ、DingDing */ private String appName; /** * 秘钥key */ private String clientId; /** * 秘钥secret */ private String clientSecret; /** * 回调地址 */ private String redirectUri; public String getAppName() return appName; public void setAppName(String appName) this.appName = appName; public String getClientId() return clientId; public void setClientId(String clientId) this.clientId = clientId; public String getClientSecret() return clientSecret; public void setClientSecret(String clientSecret) this.clientSecret = clientSecret; public String getRedirectUri() return redirectUri; public void setRedirectUri(String redirectUri) this.redirectUri = redirectUri;
③封装扫码接口工具类OauthUtil.java
package com.yundi.atp.platform.util.oauth; import lombok.extern.slf4j.Slf4j; import me.zhyd.oauth.config.AuthConfig; import me.zhyd.oauth.config.AuthDefaultSource; import me.zhyd.oauth.request.AuthDefaultRequest; import me.zhyd.oauth.request.AuthRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.lang.reflect.Constructor; import java.util.List; import java.util.stream.Collectors; /** * @Author: 北溟溟 * @Description: 第三方登录工具类 * @Date: 2022/1/5 18:25 * @Version: 1.0.0 */ @Slf4j @Component public class OauthUtil @Autowired private OauthDataProperties oauthDataProperties; public AuthRequest getAuthRequest(String appName) try List<OauthDataProperties.OauthData> collect = oauthDataProperties.getList().stream().filter(item -> item.getAppName().equals(appName)).collect(Collectors.toList()); if (!collect.isEmpty()) OauthDataProperties.OauthData oauthData = collect.get(0); AuthConfig authConfig = AuthConfig.builder() .clientId(oauthData.getClientId()) .clientSecret(oauthData.getClientSecret()) .redirectUri(oauthData.getRedirectUri()) .build(); AuthDefaultSource authDefaultSource = AuthDefaultSource.valueOf(oauthData.getAppName()); Class<? extends AuthDefaultRequest> targetClass = authDefaultSource.getTargetClass(); String className = targetClass.getName(); Class<?> clazz = Class.forName(className); Constructor constructor = clazz.getConstructor(AuthConfig.class); AuthRequest authRequest = (AuthRequest) constructor.newInstance(authConfig); return authRequest; catch (Exception e) log.info("登录参数初始化异常!"); return null;
④实现扫码登录的三个接口OauthUserController.java
package com.yundi.atp.platform.module.sys.controller; import com.yundi.atp.platform.common.Result; import com.yundi.atp.platform.util.oauth.OauthUtil; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import me.zhyd.oauth.model.AuthCallback; import me.zhyd.oauth.model.AuthResponse; import me.zhyd.oauth.request.AuthRequest; import me.zhyd.oauth.utils.AuthStateUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.HashMap; import java.util.Map; /** * @Author: 北溟溟 * @Description: 第三方授权登录 * @Date: 2022/1/5 19:23 * @Version: 1.0.0 */ @Api(tags = "第三方登录") @RestController @RequestMapping(value = "/oauthUser") public class OauthUserController private static Map<String, AuthResponse> map = new HashMap<>(10000); @Autowired private OauthUtil oauthUtil; @ApiOperation(value = "第三方登录") @GetMapping(value = "/login/appName") public Result login(@PathVariable(value = "appName") String appName) AuthRequest authRequest = oauthUtil.getAuthRequest(appName); String authorize = authRequest.authorize(AuthStateUtils.createState()); return Result.success(authorize); @ApiOperation(value = "第三方登录回调地址,根据回调结果处理登录的后续流程") @GetMapping(value = "/callback") public String callback(@RequestParam(value = "appName") String appName, AuthCallback callback) AuthRequest authRequest = oauthUtil.getAuthRequest(appName); AuthResponse authResponse = authRequest.login(callback); if (authResponse.getCode() == 2000) map.put(callback.getState(), authResponse); return "登录成功!"; return "登录失败!"; @ApiOperation(value = "获取登录结果") @GetMapping(value = "/getLoginResult") public Result getLoginResult(@RequestParam(value = "state") String state) AuthResponse authResponse = map.get(state); if (authResponse != null) map.remove(state); return Result.success(); return Result.fail("登录授权失败,请重新扫码登录!");
- 前端代码
①安装vue-qr二维码组件
命令:npm install vue-qr --save
②前端代码
<template> <div class="container"> <el-form ref="form" :model="form" :rules="rules" label-width="70px" class="login"> <h3>ATP应用测试平台</h3> <el-form-item label="用户名" prop="name"> <el-input v-model="form.name"></el-input> </el-form-item> <el-form-item label="密码" prop="pass"> <el-input v-model="form.pass" type="password" show-password></el-input> </el-form-item> <el-form-item label="验证" prop="isLock"> <slider-verify-code v-model="form.isLock" @change="handlerLock"></slider-verify-code> </el-form-item> <el-button type="primary" @click="login" style="width: 100%;margin: 0;">立即登录</el-button> <div style="margin-top: 20px;text-align: left;"> <img alt="百度" src="@/assets/baidu.png" style="width:30px;height:30px;margin: 0 0 0 10px;cursor: pointer;" @click="oauthLogin('BAIDU')"/> </div> <el-dialog @close='closeQrCodeDialog' :visible.sync="show" :fullscreen=true :modal=true width="100%"> <h5 style="margin: 0 0 10px 0;font-size: 20px;letter-spacing: 1px; color: white; font-weight: normal;"> qrCodeName 扫码认证中心</h5> <vue-qr :text="qrCode" :size="300" :logoSrc="logo"></vue-qr> </el-dialog> </el-form> </div> </template> <script> import sliderVerifyCode from '@/components/slider-verify-code.vue'; export default name: "Login", data() const checkStatus = (rule, value, callback) => if (!value) return callback(new Error("请拖动滑块完成验证")); else if (this.form.name == '' || this.form.pass == '' || !this.form.name || !this.form.pass) setTimeout(() => this.form.isLock = false; this.$refs.form.validateField('name'); this.$refs.form.validateField('pass'); return callback(new Error("验证未通过")); , 1); callback(); ; return form: name: 'super_admin', pass: 'super_admin', , rules: name: [ required: true, message: '用户名称不得为空!', trigger: 'blur', min: 6, max: 18, message: '长度在 6 到 18 个字符', trigger: 'blur' ], pass: [ required: true, message: '密码不得为空!', trigger: 'blur', min: 6, max: 18, message: '长度在 6 到 18 个字符', trigger: 'blur' ], isLock: [ validator: checkStatus, trigger: 'blur', ], , qrCode: '', show: false, qrCodeName: '', logo: require('../assets/logo.png'), timer: '', refreshTimer: '', , components: 'slider-verify-code': sliderVerifyCode , methods: //关闭扫码框 closeQrCodeDialog() this.show = false; clearInterval(this.timer); clearInterval(this.refreshTimer); , //登录 login() this.$refs.form.validate((valid) => if (valid) this.$http.post('/sys/user/login', this.$qs.stringify(this.form)).then(res => if (res.data.code === 1) sessionStorage.setItem("username", this.form.name); this.$router.push('/home'); else this.$refs.form.resetFields(); this.$message.warning(res.data.msg); ).catch(error => this.$message.error(error); ); else return false; ); , //第三方登录 oauthLogin(data) this.qrCodeName = data; this.oauthLoginCommit(this.qrCodeName); this.refreshTimer = setInterval(() => this.oauthLoginCommit(this.qrCodeName); , 1000*60*3); , //登录接口 oauthLoginCommit(data) this.$http.get('/oauthUser/login/' + data).then(res => if (res.data.code === 1) this.qrCode = res.data.data; this.show = true; this.checkOauthStatus(this.qrCode); else this.$message.warning(res.data.msg); ).catch(error => this.$message.error(error); ); , //检测登录状态 checkOauthStatus(data) const state = this.getQueryString(data, "state"); clearInterval(this.timer); this.timer = setInterval(() => this.$http.get('/oauthUser/getLoginResult?state=' + state).then(res => if (res.data.code === 1) this.$router.push('/home'); clearInterval(this.timer); clearInterval(this.refreshTimer); ).catch(error => this.$message.error(error); ); , 2000); , //获取访问路径中的参数 getQueryString(url, key) const reg = new RegExp("(^|&)" + key + "=([^&]*)(&|$)", "i"); const r = url.substr(1).match(reg); if (r != null) return unescape(r[2]); return null; , handlerLock(data) if (data) this.$refs.form.validateField('isLock'); , </script> <style scoped lang="scss"> .container width: 100%; height: 100%; overflow: auto; background: rgb(84, 92, 100); ::v-deep .el-dialog, .el-pager li background: #6d6d6d !important; .login text-align: center; padding: 20px 30px 30px 30px; margin: 10% auto; width: 320px; background: white; border-radius: 10px; h3 margin: 30px 0px; .el-form-item margin-bottom: 35px; </style>
- 测试效果
结语
OK,本节内容到这里就结束了。通过使用JustAuth我们可以快速的集成我们第三方的一些扫码登录功能,其本质是对于各种第三方扫码功能的封装,我们也可以按照自己的需求自行封装,原则上都是调用第三方认证中心的授权接口,完成授权功能,获取到第三方的用户信息。本节我们通过java反射机制获取我们的第三方授权实例对象,并通过前端定时器定时更新我们的二维码,并实时检测扫码登录的回调结果,从而实现前后端分离的扫码登录功能。
以上是关于(十五)ATP应用测试平台——使用JustAuth快速集成前后端分离的第三方扫码授权登录功能的主要内容,如果未能解决你的问题,请参考以下文章
(十四)ATP应用测试平台——使用docker-compose一键式安装ATP应用测试平台的依赖服务
ATP应用测试平台——关于vue-router前端路由的配置使用案例
(十九)ATP应用测试平台——springboot集成RocketMQ案例实战
ATP应用测试平台——关于vue中Vue-Quill-EditorMavon-EditorTinymce等多种富文本编辑器的集成使用