Java SpringBoot + Vue + Uniapp 集成JustAuth 最快实现多端三方登录!(QQ登录、微信登录、支付宝登录……)

注:本文基于 若依 集成just-auth实现第三方授权登录 修改完善,所有步骤仅代表本人如下环境亲测可用,其他环境需自辩或联系查看原因!

系统环境

运行系统:Windows10专业版、Linux Centos7.6
Java 版本:1.8.0_371
node 版本:14.21.3
Mysql版本:5.5.39、5.7.44

一、后台配置

1、添加依赖

<!-- JustAuth第三方授权登录 -->
<dependency><groupId>me.zhyd.oauth</groupId><artifactId>JustAuth</artifactId><version>1.15.6</version>
</dependency>
<!-- HttpClient -->
<dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId>
</dependency>

2、添加认证授权工具类

package top.chengrongyu.common.utils;import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.exception.AuthException;
import me.zhyd.oauth.request.*;
/*** 认证授权工具类* * @author ruoyi*/
public class AuthUtils
{@SuppressWarnings("deprecation")public static AuthRequest getAuthRequest(String source, String clientId, String clientSecret, String redirectUri,AuthStateCache authStateCache){AuthRequest authRequest = null;switch (source.toLowerCase()){case "dingtalk":authRequest = new AuthDingTalkRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "baidu":authRequest = new AuthBaiduRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "github":authRequest = new AuthGithubRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "gitee":authRequest = new AuthGiteeRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "weibo":authRequest = new AuthWeiboRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "coding":authRequest = new AuthCodingRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).codingGroupName("").build(), authStateCache);break;case "oschina":authRequest = new AuthOschinaRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "alipay":// 支付宝在创建回调地址时,不允许使用localhost或者127.0.0.1,所以这儿的回调地址使用的局域网内的ipauthRequest = new AuthAlipayRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).alipayPublicKey("").redirectUri(redirectUri).build(), authStateCache);break;case "qq":authRequest = new AuthQqRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "wechat_open":authRequest = new AuthWeChatOpenRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "csdn":authRequest = new AuthCsdnRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "taobao":authRequest = new AuthTaobaoRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "douyin":authRequest = new AuthDouyinRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "linkedin":authRequest = new AuthLinkedinRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "microsoft":authRequest = new AuthMicrosoftRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "mi":authRequest = new AuthMiRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "toutiao":authRequest = new AuthToutiaoRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "teambition":authRequest = new AuthTeambitionRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "pinterest":authRequest = new AuthPinterestRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "renren":authRequest = new AuthRenrenRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "stack_overflow":authRequest = new AuthStackOverflowRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).stackOverflowKey("").build(),authStateCache);break;case "huawei":authRequest = new AuthHuaweiRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "wechat_enterprise":authRequest = new AuthWeChatEnterpriseRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).agentId("").build(), authStateCache);break;case "kujiale":authRequest = new AuthKujialeRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "gitlab":authRequest = new AuthGitlabRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "meituan":authRequest = new AuthMeituanRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "eleme":authRequest = new AuthElemeRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build());break;case "wechat_mp":authRequest = new AuthWeChatMpRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;case "aliyun":authRequest = new AuthAliyunRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);break;default:break;}if (null == authRequest){throw new AuthException("未获取到有效的Auth配置");}return authRequest;}
}

3、新建第三方登录授权表

-- ----------------------------
-- 第三方授权表
-- ----------------------------
create table sys_auth_user (auth_id           bigint(20)      not null auto_increment    comment '授权ID',uuid              varchar(500)    not null                   comment '第三方平台用户唯一ID',user_id           bigint(20)      not null                   comment '系统用户ID',login_name        varchar(30)     not null                   comment '登录账号',user_name         varchar(30)     default ''                 comment '用户昵称',avatar            varchar(500)    default ''                 comment '头像地址',email             varchar(255)    default ''                 comment '用户邮箱',source            varchar(255)    default ''                 comment '用户来源',create_time       datetime                                   comment '创建时间',primary key (auth_id)
) engine=innodb auto_increment=100 comment = '第三方授权表';

4、添加实体表、Mapper、Service接口类

(1)实体

package top.chengrongyu.system.domain;import lombok.Data;
import top.chengrongyu.common.core.domain.BaseEntity;/*** 第三方授权表 sys_auth_user* * @author ruoyi*/
@Data
public class SysAuthUser extends BaseEntity
{private static final long serialVersionUID = 1L;/** 授权ID */private Long authId;/** 第三方平台用户唯一ID */private String uuid;/** 系统用户ID */private Long userId;/** 登录账号 */private String userName;/** 用户昵称 */private String nickName;/** 头像地址 */private String avatar;/** 用户邮箱 */private String email;/** 用户来源 */private String source;
}

(2)在原user的Mapper下添加如下接口

    /*** 根据用户编号查询授权列表* * @param userId 用户编号* @return 授权列表*/public List<SysAuthUser> selectAuthUserListByUserId(Long userId);/*** 根据uuid查询用户信息** @param uuid 唯一信息* @return 结果*/public SysUser selectAuthUserByUuid(String uuid);/*** 校验source平台是否绑定** @param userId 用户编号* @param source 绑定平台* @return 结果*/public int checkAuthUser(@Param("userId") Long userId, @Param("source") String source);/*** 新增第三方授权信息* * @param authUser 用户信息* @return 结果*/public int insertAuthUser(SysAuthUser authUser);/*** 根据编号删除第三方授权信息* * @param authId 授权编号* @return 结果*/public int deleteAuthUser(Long authId);

(3)在原user的Service下添加如下接口

    /*** 根据用户编号查询授权列表** @param userId 用户编号* @return 授权列表*/public List<SysAuthUser> selectAuthUserListByUserId(Long userId);

(4)在原user的ServiceImpl下添加如下接口

     /*** 根据用户编号查询授权列表* * @param userId 用户编号* @return 授权列表*/public List<SysAuthUser> selectAuthUserListByUserId(Long userId){return userMapper.selectAuthUserListByUserId(userId);}

(5)在原user的Mapper.xml下添加如下sql

	<resultMap id="SysAuthUserResult" type="SysAuthUser"><id     property="authId"       column="auth_id"        /><result property="uuid"         column="uuid"           /><result property="userId"       column="user_id"        /><result property="userName"     column="user_name"      /><result property="nickName"     column="nick_name"      /><result property="avatar"       column="avatar"         /><result property="email"        column="email"          /><result property="source"       column="source"         /><result property="createTime"   column="create_time"    /></resultMap><select id="selectAuthUserByUuid" parameterType="String" resultMap="SysUserResult">select b.user_id as user_id, b.user_name as user_name, b.password as passwordfrom sys_auth_user a left join sys_user b on a.user_id = b.user_idwhere a.uuid = #{uuid} and b.del_flag = '0'</select><select id="selectAuthUserListByUserId" parameterType="Long" resultMap="SysAuthUserResult">select auth_id, uuid, user_id, user_name, nick_name, avatar, email, source, create_timefrom sys_auth_user where user_id = #{userId} </select><select id="checkAuthUser" parameterType="SysAuthUser" resultType="int">select count(1) from sys_auth_user where user_id=#{userId} and source=#{source} limit 1</select><insert id="insertAuthUser" parameterType="SysAuthUser">insert into sys_auth_user(<if test="uuid != null and uuid != ''">uuid,</if><if test="userId != null and userId != 0">user_id,</if><if test="userName != null and userName != ''">user_name,</if><if test="nickName != null and nickName != ''">nick_name,</if><if test="avatar != null and avatar != ''">avatar,</if><if test="email != null and email != ''">email,</if><if test="source != null and source != ''">source,</if>create_time)values(<if test="uuid != null and uuid != ''">#{uuid},</if><if test="userId != null and userId != 0">#{userId},</if><if test="userName != null and userName != ''">#{userName},</if><if test="nickName != null and nickName != ''">#{nickName},</if><if test="avatar != null and avatar != ''">#{avatar},</if><if test="email != null and email != ''">#{email},</if><if test="source != null and source != ''">#{source},</if>sysdate())</insert><delete id="deleteAuthUser" parameterType="Long">delete from sys_auth_user where auth_id = #{authId}</delete>

5、添加SysAuthController

注意:
①这里的auths下的clientId需要自己获取正式的个人网站客户端id、密钥、回调 等信息;
②回调地址需要写成前端页面的地址,不是后端的;
③此处更改了三方登录的方式,新增了无绑定账户自动创建账户并登录的代码逻辑,并修复了一些绑定三方账户的bug;

参考JustAuth官网集成第三方步骤

package top.chengrongyu.web.controller.system;import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
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.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.fastjson2.JSONObject;
import me.zhyd.oauth.cache.AuthDefaultStateCache;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.springframework.web.multipart.MultipartFile;
import top.chengrongyu.common.constant.Constants;
import top.chengrongyu.common.core.controller.BaseController;
import top.chengrongyu.common.core.domain.AjaxResult;
import top.chengrongyu.common.core.domain.entity.SysUser;
import top.chengrongyu.common.core.domain.model.LoginUser;
import top.chengrongyu.common.enums.UserStatus;
import top.chengrongyu.common.exception.ServiceException;
import top.chengrongyu.common.utils.AuthUtils;
import top.chengrongyu.common.utils.SecurityUtils;
import top.chengrongyu.common.utils.StringUtils;
import top.chengrongyu.framework.web.service.SysLoginService;
import top.chengrongyu.framework.web.service.SysPermissionService;
import top.chengrongyu.framework.web.service.TokenService;
import top.chengrongyu.system.domain.SysAuthUser;
import top.chengrongyu.system.mapper.SysUserMapper;
import top.chengrongyu.system.service.ISysUserService;import static top.chengrongyu.common.utils.file.FileUploadUtils.fileUrlConvertToMultipartImage;
import static top.chengrongyu.common.utils.file.FileUploadUtils.upload;/*** 第三方认证授权处理** @author cry*/
@RestController
@RequestMapping("/system/auth")
public class SysAuthController extends BaseController {private AuthStateCache authStateCache;@Autowiredprivate ISysUserService userService;@Autowiredprivate SysPermissionService permissionService;@Autowiredprivate TokenService tokenService;@Autowiredprivate SysUserMapper userMapper;@Autowiredprivate SysLoginService loginService;/*** 三方应用登录回调地址*/String redirectUri = "http://127.0.0.1:81/social-login?source=";// PCString redirectUriMobile = "http://127.0.0.1:9090/pages/socialLogin?source=";// Mobile  注意:/# 哈希值不能携带!URL中的哈希值(#)部分可能不会被服务器处理/*** gitee 客户端ID*/String giteeClientId = "xxxx";/*** gitee 客户端密钥*/String giteeClientSecret = "xxxx";private final static Map<String, String> auths = new HashMap<String, String>();{auths.put("gitee", "{\"clientId\":\"" + giteeClientId + "\",\"clientSecret\":\"" + giteeClientSecret + "\",\"redirectUri\":\"" + redirectUri + "gitee"+"\",\"redirectUriMobile\":\"" + redirectUriMobile + "gitee\"}");authStateCache = AuthDefaultStateCache.INSTANCE;}/*** 认证授权** @param source 三方平台* @param type 请求端类型 PC、Mobile* @throws IOException*/@GetMapping("/binding/{source}/{type}")@ResponseBodypublic AjaxResult authBinding(@PathVariable("source") String source,@PathVariable("type")String type, HttpServletRequest request) throws IOException {LoginUser tokenUser = tokenService.getLoginUser(request);if (StringUtils.isNotNull(tokenUser) && userMapper.checkAuthUser(tokenUser.getUserId(), source) > 0) {return error(source + "平台账号已经绑定");}String obj = auths.get(source);if (StringUtils.isEmpty(obj)) {return error(source + "平台账号暂不支持");}JSONObject json = JSONObject.parseObject(obj);/*** 校验是PC端还是Mobile端*/String url = "PC".equals(type) ? json.getString("redirectUri") : json.getString("redirectUriMobile");AuthRequest authRequest = AuthUtils.getAuthRequest(source, json.getString("clientId"), json.getString("clientSecret"), url, authStateCache);String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());System.out.println(authorizeUrl);return success(authorizeUrl);}@SuppressWarnings("unchecked")@GetMapping("/social-login/{source}/{type}")public AjaxResult socialLogin(@PathVariable("source") String source,@PathVariable("type") String type, AuthCallback callback, HttpServletRequest request) throws IOException {String obj = auths.get(source);if (StringUtils.isEmpty(obj)) {return AjaxResult.error(10002, "第三方平台系统不支持或未提供来源");}JSONObject json = JSONObject.parseObject(obj);/*** 校验是PC端还是Mobile端*/String url = "PC".equals(type) ? json.getString("redirectUri") : json.getString("redirectUriMobile");AuthRequest authRequest = AuthUtils.getAuthRequest(source, json.getString("clientId"), json.getString("clientSecret"), url, authStateCache);AuthResponse<AuthUser> response = authRequest.login(callback);if (response.ok()) {/*** 获取当前请求下登录用户缓存信息*/LoginUser tokenUser = null;try {tokenUser = tokenService.getLoginUser(request);} catch (ServiceException e) {/*** 提示获取用户信息异常时,抛出异常 不做处理*/throw e;}finally {/*** 根据三方登录平台的uuid查询用户三方绑定信息*/SysUser authUserByUuid = userMapper.selectAuthUserByUuid(source + response.getData().getUuid());/*** 验证当前用户是否已经登录  并且验证当前登录的和绑定的是否是一个账户*/if (StringUtils.isNotNull(tokenUser)) {if (StringUtils.isNotNull(authUserByUuid) && tokenUser.getUserId() == authUserByUuid.getUserId()) {String token = tokenService.createToken(SecurityUtils.getLoginUser());return success().put(Constants.TOKEN, token);}/*** 判断 当前登录的和绑定的不是一个账户时*/if (authUserByUuid != null && authUserByUuid.getUserId() != null) {return AjaxResult.error(10002, "对不起,来自" + source + "的账户已有绑定账户,如有需要,请登录原账户解绑后重新绑定!");}else{/*** 若已经登录,但未绑定该三方授权信息* 则直接绑定当前登录的系统账号*/SysAuthUser authUser = new SysAuthUser();authUser.setAvatar(response.getData().getAvatar());authUser.setUuid(source + response.getData().getUuid());authUser.setUserId(SecurityUtils.getUserId());authUser.setUserName(response.getData().getUsername());authUser.setNickName(response.getData().getNickname());authUser.setEmail(response.getData().getEmail());authUser.setSource(source);userMapper.insertAuthUser(authUser);String token = tokenService.createToken(SecurityUtils.getLoginUser());return success().put(Constants.TOKEN, token);}}/*** 当用户未登录* 判断 根据三方登录平台的uuid查询用户三方绑定信息 不为空时*/if (StringUtils.isNotNull(authUserByUuid)) {SysUser user = userService.selectUserByUserName(authUserByUuid.getUserName());if (StringUtils.isNull(user)) {throw new ServiceException("登录用户:" + user.getUserName() + " 不存在");} else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {throw new ServiceException("对不起,您的账号:" + user.getUserName() + " 已被删除");} else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {throw new ServiceException("对不起,您的账号:" + user.getUserName() + " 已停用");}LoginUser loginUser = new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));String token = tokenService.createToken(loginUser);return success().put(Constants.TOKEN, token);} else {/*** 当用户未登录 且* 该三方登录信息也未绑定用户时* 创建一个新用户进行绑定*/SysUser user = new SysUser();/*** 默认用户名为 uuid + _三方平台名称*/user.setUserName(response.getData().getUuid()+"_"+source);/*** 默认密码为 123456*/user.setPassword(SecurityUtils.encryptPassword("123456"));user.setNickName(response.getData().getNickname());/*** 由于存储文件路径以用户为单位* 所以需要登录后跟俊网络地址修改用户头像*/MultipartFile multipartFile = fileUrlConvertToMultipartImage(response.getData().getAvatar(),user.getUserName()+"_avatar.png");String avatarUrl = upload(multipartFile);user.setAvatar(avatarUrl);user.setEmail(response.getData().getEmail());user.setRemark(response.getData().getRemark());/*** 新增用户信息*/int rows = userService.insertUser(user);if(rows>0){/*** 用户添加成功后 绑定该三方授权信息*/SysAuthUser authUser = new SysAuthUser();authUser.setUuid(source + response.getData().getUuid());authUser.setUserId(user.getUserId());authUser.setAvatar(response.getData().getAvatar());authUser.setUserName(response.getData().getUsername());authUser.setNickName(response.getData().getNickname());authUser.setEmail(response.getData().getEmail());authUser.setSource(source);userMapper.insertAuthUser(authUser);// 登录并生成令牌String token = loginService.login(user.getUserName(), "123456", "","");return success().put(Constants.TOKEN, token);}}}}return AjaxResult.error(10002, "对不起,授权信息验证不通过,请联系管理员");}/*** 取消授权*/@DeleteMapping(value = "/unlock/{authId}")public AjaxResult unlockAuth(@PathVariable Long authId) {return toAjax(userMapper.deleteAuthUser(authId));}
}

6、在SysProfileController获取用户个人信息的profile方法中添加如下行

使在查询的同时携带用户的三方登录授权信息

ajax.put("auths", userService.selectAuthUserListByUserId(user.getUserId()));

二、前台配置(Vue、Uniapp 配置方法一致)

1、在校验文件permission.js中添加白名单

'/social-login',

2、在/api/system 中添加授权绑定、解除账号接口文件auth.js

auth.js

import request from '@/utils/request'// 绑定账号
export function authBinding(source) {return request({url: '/system/auth/binding/' + source + '/PC', //PC、Mobile 写死即可method: 'get'})
}// 解绑账号
export function authUnlock(authId) {return request({url: '/system/auth/unlock/' + authId,method: 'delete'})
}

3、在login.js中添加三方登录接口

// 第三方平台登录
export function socialLogin(source, code, state) {const data = {code,state}return request({url: '/system/auth/social-login/' + source + '/PC', //PC、Mobile 写死即可method: 'get',params: data})
}

4、设置route文件夹下的index.js路由信息(Uniapp无该步骤)

公共路由 constantRoutes 中添加三方登录的页面路径,使其在未登录时可以正常跳转页面

  {path: '/social-login',component: () => import('@/views/socialLogin'),hidden: true},

5、设置store/modules文件夹下的user.js用户存储信息

添加action下的函数

    // 第三方平台登录SocialLogin({ commit }, userInfo) {const code = userInfo.codeconst state = userInfo.stateconst source = userInfo.sourcereturn new Promise((resolve, reject) => {socialLogin(source, code, state).then(res => {setToken(res.token)commit('SET_TOKEN', res.token)resolve()}).catch(error => {reject(error)})})},

6、设置utils文件夹下的request.js请求文件处理信息

添加第三方登录失败时的报错信息处理,夹在401和500之间即可

else if (code === 10002) {// 第三方登录错误提示MessageBox.confirm(msg, '系统提示', {confirmButtonText: '重新登录',cancelButtonText: '取消',type: 'warning'}).then(() => {store.dispatch('LogOut').then(() => {location.href = '/index';// Uniapp 写 '/pages/login'})}).catch(() => { });return Promise.reject(new Error(msg))}

7、添加三方登录页面socialLogin.vue

socialLogin.vue

<template><div></div>
</template><script>
import { Loading } from 'element-ui'let loadingInstance;
export default {data() {return {redirect: undefined,};},created() {loadingInstance = Loading.service({lock: true,text: "正在验证第三方应用账户数据,请稍候",spinner: "el-icon-loading",background: "rgba(0, 0, 0, 0.7)",})// 第三方登录回调参数this.source = this.$route.query.source;this.code = this.$route.query.code;this.state = this.$route.query.state;this.$store.dispatch("SocialLogin", {code: this.code,state: this.state,source: this.source}).then(() => {loadingInstance.close();this.$router.push({ path: this.redirect || "/" }).catch(()=>{});}).catch(() => {loadingInstance.close();});},methods: {},
};
</script><style rel="stylesheet/scss" lang="scss">
</style>

8、登录页面添加三方登录跳转信息链接

vue

      <!--  第三方应用登录 --><el-form-item style="width:100%;"><div class="oauth-login" style="display:flex"><div class="oauth-login-item" @click="doSocialLogin('gitee')"><svg-icon icon-class="gitee" style="height:1.2em" /><span>Gitee</span></div><div class="oauth-login-item" @click="doSocialLogin('github')"><svg-icon icon-class="github" style="height:1.2em" /><span>Github</span></div><div class="oauth-login-item"><svg-icon icon-class="weixin" style="height:1.2em" /><span>Weixin</span></div><div class="oauth-login-item"><svg-icon icon-class="qq" style="height:1.2em" /><span>QQ</span></div></div></el-form-item>

js函数

	import { authBinding } from "@/api/system/auth";……// 三方登录doSocialLogin(source) {authBinding(source).then(res => {top.location.href = res.msg;});}……

css

.oauth-login {display: flex;align-items: cen;cursor:pointer;
}
.oauth-login-item {display: flex;align-items: center;margin-right: 10px;
}
.oauth-login-item img {height: 25px;width: 25px;
}
.oauth-login-item span:hover {text-decoration: underline red;color: red;
}

9、添加个人中心三方登录信息展示(Uniapp需根据需要自定义)

views\system\user\profile\index.vue添加如下
vue

            <el-tab-pane label="第三方应用" name="thirdParty"><thirdParty :auths="auths" /></el-tab-pane>

js

import thirdParty from "./thirdParty";
export default {name: "Profile",components: { userAvatar, userInfo, resetPwd, thirdParty },……auths: {},……/*** 赋值 用户授权三方登录信息 用于回显socialLogin页面*/this.auths = response.auths;

添加thirdParty.vue页面

<template><div><el-table :data="auths" style="width: 100%; height: 100%; font-size: 10px"><el-table-column label="序号" width="50" type="index"></el-table-column><el-table-columnlabel="绑定账号平台"width="140"align="center"prop="source":show-overflow-tooltip="true"/><el-table-column label="头像" width="120" align="center" prop="avatar"><template slot-scope="scope"><image-preview :src="scope.row.avatar" style="width: 45px; height: 45px" /></template></el-table-column><el-table-columnlabel="系统账号"width="180"align="center"prop="userName":show-overflow-tooltip="true"/><el-table-columnlabel="绑定时间"width="180"align="center"prop="createTime"/><el-table-columnlabel="操作"width="80"align="center"class-name="small-padding fixed-width"><template slot-scope="scope"><el-buttonsize="mini"type="text"icon="el-icon-delete"@click="unlockAuth(scope.$index, scope.row)">解绑</el-button></template></el-table-column></el-table><div id="git-user-binding"><h4 class="provider-desc">你可以绑定以下第三方帐号用于CyberSpace系统</h4><div id="authlist" class="user-bind"><aclass="third-app"href="#"@click="authUrl('gitee');"title="使用 Gitee 账号授权登录"><div class="git-other-login-icon"><svg-icon icon-class="gitee" /></div><span class="app-name">Gitee</span></a><aclass="third-app"href="#"@click="authUrl('github');"title="使用 GitHub 账号授权登录"><div class="git-other-login-icon"><svg-icon icon-class="github" /></div><span class="app-name">Github</span></a><a class="third-app" href="#" title="功能开发中..."><div class="git-other-login-icon"><svg-icon icon-class="weixin" /></div><span class="app-name">WeiXin</span></a><a class="third-app" href="#" title="功能开发中..."><div class="git-other-login-icon"><svg-icon icon-class="qq" /></div><span class="app-name">QQ</span></a></div></div></div>
</template><script>
import { authUnlock, authBinding } from "@/api/system/auth";export default {props: {auths: {type: Array,},},data() {return {};},methods: {unlockAuth(index, row) {var _this = this;this.$modal.confirm('您确定要解除"' + row.source + '"的账号绑定吗?').then(function () {return authUnlock(row.authId);}).then(() => {_this.auths.splice(index, 1);this.$modal.msgSuccess("解绑成功");}).catch(() => {});},authUrl(source) {authBinding(source).then(res => {top.location.href = res.msg;});}},
};
</script><style type="text/css">
.user-bind .third-app {display: -webkit-box;display: -ms-flexbox;display: flex;-webkit-box-orient: vertical;-webkit-box-direction: normal;-ms-flex-direction: column;flex-direction: column;-webkit-box-align: center;-ms-flex-align: center;align-items: center;min-width: 80px;float: left;
}
.user-bind {font-size: 1rem;text-align: start;height: 50px;margin-top: 10px;
}
.git-other-login-icon > img {height: 32px;
}
a {text-decoration: none;cursor: pointer;color: #005980;
}
.provider-desc {font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial,"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Liberation Sans","PingFang SC", "Microsoft YaHei", "Hiragino Sans GB", "Wenquanyi Micro Hei","WenQuanYi Zen Hei", "ST Heiti", SimHei, SimSun, "WenQuanYi Zen Hei Sharp",sans-serif;font-size: 1.071rem;
}
td > img {height: 20px;width: 20px;display: inline-block;border-radius: 50%;margin-right: 5px;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/2472.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android 高德地图API(新版)

新版高德地图 前言正文一、创建应用① 获取PackageName② 获取调试版安全码SHA1③ 获取发布版安全码SHA1 二、配置项目① 导入SDK② 配置AndroidManifest.xml 三、获取当前定位信息① ViewBinding使用和导包② 隐私合规设置③ 权限请求④ 初始化定位⑤ 获取定位信息 四、显示地…

springCloudGateway+nacos自定义负载均衡-通过IP隔离开发环境

先说一下想法&#xff0c;小公司开发项目&#xff0c;参考若依框架使用的spring-cloud-starter-gateway和spring-cloud-starter-alibaba-nacos, 用到了nacos的配置中心和注册中心&#xff0c;有多个模块&#xff08;每个模块都是一个服务&#xff09;。 想本地开发&#xff0c;…

【NLP】语言模型的发展历程 (1)

语言模型的发展历程系列博客主要包含以下文章&#xff1a; 【NLP】语言模型的发展历程 (1)【NLP】大语言模型的发展历程 (2) 本篇博客是该系列的第一篇&#xff0c;主要讲讲 语言模型&#xff08;LM&#xff0c;Language Model&#xff09; 的发展历程。 文章目录 一、统计语…

【Compose multiplatform教程】05 IOS环境编译

了解如何使现有的 Android 应用程序跨平台&#xff0c;以便它在 Android 和 iOS 上都能运行。您将能够在一个位置编写代码并针对 Android 和 iOS 进行测试一次。 本教程使用一个示例 Android 应用程序&#xff0c;其中包含用于输入用户名和密码的单个屏幕。凭证经过验证并保存…

Redis哨兵(Sentinel)

Redis哨兵 ‌[Redis哨兵]&#xff08;Sentinel&#xff09;是Redis的一个高可用性解决方案&#xff0c;主要用于监控和管理多个Redis服务器&#xff0c;确保Redis系统的高可用性‌。哨兵通过实时监测主节点和从节点的状态&#xff0c;及时发现并自动处理故障&#xff0c;保证系…

WEB 攻防-通用漏-XSS 跨站脚本攻击-反射型/存储型/DOMBEEF-XSS

XSS跨站脚本攻击技术&#xff08;一&#xff09; XSS的定义 XSS攻击&#xff0c;全称为跨站脚本攻击&#xff0c;是指攻击者通过在网页中插入恶意脚本代码&#xff0c;当用户浏览该网页时&#xff0c;恶意脚本会被执行&#xff0c;从而达到攻击目的的一种安全漏洞。这些恶意脚…

【C++】B2112 石头剪子布

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 &#x1f4af;前言&#x1f4af;题目描述游戏规则&#xff1a;输入格式&#xff1a;输出格式&#xff1a;输入输出样例&#xff1a;解题分析与实现 &#x1f4af;我的做法实现逻辑优点与不足 &#x1f4af…

2025 年前端开发学习路线图完整指南

如果您想成为前端开发人员&#xff0c;本指南适合您。无论您是从零开始还是已经了解基础知识&#xff0c;它都会帮助您专注于真正重要的事情并学习让您脱颖而出的技能。 刚开始的时候&#xff0c;我浪费了几个月的时间在不相关的教程上&#xff0c;因为我不知道从哪里开始&…

【蓝牙】win11 笔记本电脑连接 hc-06

文章目录 前言步骤 前言 使用电脑通过蓝牙添加串口 步骤 设置 -> 蓝牙和其他设备 点击 显示更多设备 更多蓝牙设置 COM 端口 -> 添加 有可能出现卡顿&#xff0c;等待一会 传出 -> 浏览 点击添加 hc-06&#xff0c;如果没有则点击 再次搜索 确定 添加成…

Docker--Docker Compose(容器编排)

什么是 Docker Compose Docker Compose是Docker官方的开源项目&#xff0c;是一个用于定义和运行多容器Docker应用程序的工具。 服务&#xff08;Service&#xff09;&#xff1a;在Docker Compose中&#xff0c;一个服务实际上可以包括若干运行相同镜像的容器实例&#xff0…

【Linux】11.Linux基础开发工具使用(4)

文章目录 3. Linux调试器-gdb使用3.1 背景3.2 下载安装3.3 使用gdb查询3.4 开始使用 3. Linux调试器-gdb使用 3.1 背景 程序的发布方式有两种&#xff0c;debug模式和release模式 Linux gcc/g出来的二进制程序&#xff0c;默认是release模式 要使用gdb调试&#xff0c;必须…

【Linux 36】多路转接 - epoll

文章目录 &#x1f308; 一、epoll 初步认识&#x1f308; 二、epoll 相关接口⭐ 1. 创建 epoll -- epoll_create⭐ 2. 控制 epoll -- epoll_ctr⭐ 3. 等待 epoll -- epoll_wait &#x1f308; 三、epoll 工作原理⭐ 1. 红黑树和就绪队列⭐ 2. 回调机制⭐ 3. epoll 的使用过程 …

微信小程序订阅消息提醒-云函数

微信小程序消息订阅分2种&#xff1a; 1.一次性订阅&#xff1a;用户订阅一次就可以推送一次&#xff0c;如果需要多次提醒需要多次订阅。 2.长期订阅&#xff1a;只有公共服务领域&#xff0c;如政务、医疗、交通、金融和教育等。‌在用户订阅后&#xff0c;在很长一段时间内…

使用 Charles 调试 Flutter 应用中的 Dio 网络请求

为了成功使用 Charles 抓取并调试 Flutter 应用程序通过 Dio 发起的网络请求&#xff0c;需遵循特定配置步骤来确保应用程序能够识别 Charles 的 SSL 证书&#xff0c;并正确设置代理服务器。 配置 Charles 以支持 HTTPS 请求捕获 Charles 默认会拦截 HTTP 流量&#xff1b;…

《HTML在网络安全中的多面应用:从防范攻击到安全审查》

Html基础 Html简介 HTML&#xff08;HyperText Markup Language&#xff0c;超文本标记语言&#xff09;是用于描述网页内容和结构的标准语言。以下是对HTML的简要介绍&#xff1a; 基本概念 定义&#xff1a; HTML不是一种编程语言&#xff0c;而是一种标记语言。 它使用标…

算法每日双题精讲 —— 二分查找(二分查找,在排序数组中查找元素的第一个和最后一个位置)

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; 别再犹豫了&#xff01;快来订阅我们的算法每日双题精讲专栏&#xff0c;一起踏上算法学习的精彩之旅吧&#xff01;&#x1f4aa…

《C++11》深入剖析正则表达式库:解锁文本处理的高效之道

在现代编程领域&#xff0c;文本处理是一项不可或缺的任务&#xff0c;而正则表达式无疑是这一领域的强大利器。C11标准库的引入&#xff0c;为C开发者带来了正则表达式库&#xff0c;极大地丰富了C在文本处理方面的能力。本文将全方位、多角度地深入探讨C11正则表达式库&#…

Cosmos:英伟达发布世界基础模型,为机器人及自动驾驶开发加速!

1. 简介 在2025年消费电子展&#xff08;CES&#xff09;上&#xff0c;NVIDIA发布了全新的Cosmos平台&#xff0c;旨在加速物理人工智能&#xff08;AI&#xff09;系统的开发&#xff0c;尤其是自主驾驶车辆和机器人。该平台集成了生成式世界基础模型&#xff08;WFM&#x…

Hive集群的安装准备

Hive的安装与集群部署详细指南 一、环境与软件准备 在开始Hive的安装与集群部署之前&#xff0c;确保您准备好以下环境和软件&#xff1a; 虚拟机软件&#xff1a; VMware Workstation 17.5&#xff1a;用于创建和管理虚拟机&#xff0c;确保可以在其上安装Linux操作系统。 …

SpringBoot集成Mongodb

SpringBoot集成Mongodb 本文简要介绍SpringBoot集成mongodb&#xff0c;并实现增删改查 1. 引入依赖 spring-boot-starter-data-mongodb 提供了mongoTemplate供底层操作及mongodb驱动等 <dependency><groupId>org.springframework.boot</groupId><arti…