Java SpringBoot + Vue + Uniapp 集成JustAuth 最快实现多端三方登录!(QQ ...

打印 上一主题 下一主题

主题 1053|帖子 1053|积分 3163

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
注:本文基于 若依 集成just-auth实现第三方授权登录 修改美满,全部步调仅代表本人如下环境亲测可用,其他环境需自辩或联系查看缘故原由!
  体系环境

   运行体系:Windows10专业版、Linux Centos7.6
Java 版本:1.8.0_371
node 版本:14.21.3
Mysql版本:5.5.39、5.7.44
  一、后台设置

1、添加依赖

  1. <!-- JustAuth第三方授权登录 -->
  2. <dependency>
  3.         <groupId>me.zhyd.oauth</groupId>
  4.         <artifactId>JustAuth</artifactId>
  5.         <version>1.15.6</version>
  6. </dependency>
  7. <!-- HttpClient -->
  8. <dependency>
  9.         <groupId>org.apache.httpcomponents</groupId>
  10.         <artifactId>httpclient</artifactId>
  11. </dependency>
复制代码
2、添加认证授权工具类

  1. package top.chengrongyu.common.utils;
  2. import me.zhyd.oauth.cache.AuthStateCache;
  3. import me.zhyd.oauth.config.AuthConfig;
  4. import me.zhyd.oauth.exception.AuthException;
  5. import me.zhyd.oauth.request.*;
  6. /**
  7. * 认证授权工具类
  8. *
  9. * @author ruoyi
  10. */
  11. public class AuthUtils
  12. {
  13.     @SuppressWarnings("deprecation")
  14.     public static AuthRequest getAuthRequest(String source, String clientId, String clientSecret, String redirectUri,
  15.             AuthStateCache authStateCache)
  16.     {
  17.         AuthRequest authRequest = null;
  18.         switch (source.toLowerCase())
  19.         {
  20.             case "dingtalk":
  21.                 authRequest = new AuthDingTalkRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  22.                         .redirectUri(redirectUri).build(), authStateCache);
  23.                 break;
  24.             case "baidu":
  25.                 authRequest = new AuthBaiduRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  26.                         .redirectUri(redirectUri).build(), authStateCache);
  27.                 break;
  28.             case "github":
  29.                 authRequest = new AuthGithubRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  30.                         .redirectUri(redirectUri).build(), authStateCache);
  31.                 break;
  32.             case "gitee":
  33.                 authRequest = new AuthGiteeRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  34.                         .redirectUri(redirectUri).build(), authStateCache);
  35.                 break;
  36.             case "weibo":
  37.                 authRequest = new AuthWeiboRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  38.                         .redirectUri(redirectUri).build(), authStateCache);
  39.                 break;
  40.             case "coding":
  41.                 authRequest = new AuthCodingRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  42.                         .redirectUri(redirectUri).codingGroupName("").build(), authStateCache);
  43.                 break;
  44.             case "oschina":
  45.                 authRequest = new AuthOschinaRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  46.                         .redirectUri(redirectUri).build(), authStateCache);
  47.                 break;
  48.             case "alipay":
  49.                 // 支付宝在创建回调地址时,不允许使用localhost或者127.0.0.1,所以这儿的回调地址使用的局域网内的ip
  50.                 authRequest = new AuthAlipayRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  51.                         .alipayPublicKey("").redirectUri(redirectUri).build(), authStateCache);
  52.                 break;
  53.             case "qq":
  54.                 authRequest = new AuthQqRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  55.                         .redirectUri(redirectUri).build(), authStateCache);
  56.                 break;
  57.             case "wechat_open":
  58.                 authRequest = new AuthWeChatOpenRequest(AuthConfig.builder().clientId(clientId)
  59.                         .clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);
  60.                 break;
  61.             case "csdn":
  62.                 authRequest = new AuthCsdnRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  63.                         .redirectUri(redirectUri).build(), authStateCache);
  64.                 break;
  65.             case "taobao":
  66.                 authRequest = new AuthTaobaoRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  67.                         .redirectUri(redirectUri).build(), authStateCache);
  68.                 break;
  69.             case "douyin":
  70.                 authRequest = new AuthDouyinRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  71.                         .redirectUri(redirectUri).build(), authStateCache);
  72.                 break;
  73.             case "linkedin":
  74.                 authRequest = new AuthLinkedinRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  75.                         .redirectUri(redirectUri).build(), authStateCache);
  76.                 break;
  77.             case "microsoft":
  78.                 authRequest = new AuthMicrosoftRequest(AuthConfig.builder().clientId(clientId)
  79.                         .clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);
  80.                 break;
  81.             case "mi":
  82.                 authRequest = new AuthMiRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  83.                         .redirectUri(redirectUri).build(), authStateCache);
  84.                 break;
  85.             case "toutiao":
  86.                 authRequest = new AuthToutiaoRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  87.                         .redirectUri(redirectUri).build(), authStateCache);
  88.                 break;
  89.             case "teambition":
  90.                 authRequest = new AuthTeambitionRequest(AuthConfig.builder().clientId(clientId)
  91.                         .clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);
  92.                 break;
  93.             case "pinterest":
  94.                 authRequest = new AuthPinterestRequest(AuthConfig.builder().clientId(clientId)
  95.                         .clientSecret(clientSecret).redirectUri(redirectUri).build(), authStateCache);
  96.                 break;
  97.             case "renren":
  98.                 authRequest = new AuthRenrenRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  99.                         .redirectUri(redirectUri).build(), authStateCache);
  100.                 break;
  101.             case "stack_overflow":
  102.                 authRequest = new AuthStackOverflowRequest(AuthConfig.builder().clientId(clientId)
  103.                         .clientSecret(clientSecret).redirectUri(redirectUri).stackOverflowKey("").build(),
  104.                         authStateCache);
  105.                 break;
  106.             case "huawei":
  107.                 authRequest = new AuthHuaweiRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  108.                         .redirectUri(redirectUri).build(), authStateCache);
  109.                 break;
  110.             case "wechat_enterprise":
  111.                 authRequest = new AuthWeChatEnterpriseRequest(AuthConfig.builder().clientId(clientId)
  112.                         .clientSecret(clientSecret).redirectUri(redirectUri).agentId("").build(), authStateCache);
  113.                 break;
  114.             case "kujiale":
  115.                 authRequest = new AuthKujialeRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  116.                         .redirectUri(redirectUri).build(), authStateCache);
  117.                 break;
  118.             case "gitlab":
  119.                 authRequest = new AuthGitlabRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  120.                         .redirectUri(redirectUri).build(), authStateCache);
  121.                 break;
  122.             case "meituan":
  123.                 authRequest = new AuthMeituanRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  124.                         .redirectUri(redirectUri).build(), authStateCache);
  125.                 break;
  126.             case "eleme":
  127.                 authRequest = new AuthElemeRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  128.                         .redirectUri(redirectUri).build());
  129.                 break;
  130.             case "wechat_mp":
  131.                 authRequest = new AuthWeChatMpRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  132.                         .redirectUri(redirectUri).build(), authStateCache);
  133.                 break;
  134.             case "aliyun":
  135.                 authRequest = new AuthAliyunRequest(AuthConfig.builder().clientId(clientId).clientSecret(clientSecret)
  136.                         .redirectUri(redirectUri).build(), authStateCache);
  137.                 break;
  138.             default:
  139.                 break;
  140.         }
  141.         if (null == authRequest)
  142.         {
  143.             throw new AuthException("未获取到有效的Auth配置");
  144.         }
  145.         return authRequest;
  146.     }
  147. }
复制代码
3、新建第三方登录授权表

  1. -- ----------------------------
  2. -- 第三方授权表
  3. -- ----------------------------
  4. create table sys_auth_user (
  5.   auth_id           bigint(20)      not null auto_increment    comment '授权ID',
  6.   uuid              varchar(500)    not null                   comment '第三方平台用户唯一ID',
  7.   user_id           bigint(20)      not null                   comment '系统用户ID',
  8.   login_name        varchar(30)     not null                   comment '登录账号',
  9.   user_name         varchar(30)     default ''                 comment '用户昵称',
  10.   avatar            varchar(500)    default ''                 comment '头像地址',
  11.   email             varchar(255)    default ''                 comment '用户邮箱',
  12.   source            varchar(255)    default ''                 comment '用户来源',
  13.   create_time       datetime                                   comment '创建时间',
  14.   primary key (auth_id)
  15. ) engine=innodb auto_increment=100 comment = '第三方授权表';
复制代码
4、添加实体表、Mapper、Service接口类

(1)实体

  1. package top.chengrongyu.system.domain;
  2. import lombok.Data;
  3. import top.chengrongyu.common.core.domain.BaseEntity;
  4. /**
  5. * 第三方授权表 sys_auth_user
  6. *
  7. * @author ruoyi
  8. */
  9. @Data
  10. public class SysAuthUser extends BaseEntity
  11. {
  12.     private static final long serialVersionUID = 1L;
  13.     /** 授权ID */
  14.     private Long authId;
  15.     /** 第三方平台用户唯一ID */
  16.     private String uuid;
  17.     /** 系统用户ID */
  18.     private Long userId;
  19.     /** 登录账号 */
  20.     private String userName;
  21.     /** 用户昵称 */
  22.     private String nickName;
  23.     /** 头像地址 */
  24.     private String avatar;
  25.     /** 用户邮箱 */
  26.     private String email;
  27.     /** 用户来源 */
  28.     private String source;
  29. }
复制代码
(2)在原user的Mapper下添加如下接口

  1.     /**
  2.      * 根据用户编号查询授权列表
  3.      *
  4.      * @param userId 用户编号
  5.      * @return 授权列表
  6.      */
  7.     public List<SysAuthUser> selectAuthUserListByUserId(Long userId);
  8.    
  9.     /**
  10.      * 根据uuid查询用户信息
  11.      *
  12.      * @param uuid 唯一信息
  13.      * @return 结果
  14.      */
  15.     public SysUser selectAuthUserByUuid(String uuid);
  16.    
  17.     /**
  18.      * 校验source平台是否绑定
  19.      *
  20.      * @param userId 用户编号
  21.      * @param source 绑定平台
  22.      * @return 结果
  23.      */
  24.     public int checkAuthUser(@Param("userId") Long userId, @Param("source") String source);
  25.     /**
  26.      * 新增第三方授权信息
  27.      *
  28.      * @param authUser 用户信息
  29.      * @return 结果
  30.      */
  31.     public int insertAuthUser(SysAuthUser authUser);
  32.     /**
  33.      * 根据编号删除第三方授权信息
  34.      *
  35.      * @param authId 授权编号
  36.      * @return 结果
  37.      */
  38.     public int deleteAuthUser(Long authId);
复制代码
(3)在原user的Service下添加如下接口

  1.     /**
  2.      * 根据用户编号查询授权列表
  3.      *
  4.      * @param userId 用户编号
  5.      * @return 授权列表
  6.      */
  7.     public List<SysAuthUser> selectAuthUserListByUserId(Long userId);
复制代码
(4)在原user的ServiceImpl下添加如下接口

  1.      /**
  2.      * 根据用户编号查询授权列表
  3.      *
  4.      * @param userId 用户编号
  5.      * @return 授权列表
  6.      */
  7.     public List<SysAuthUser> selectAuthUserListByUserId(Long userId)
  8.     {
  9.         return userMapper.selectAuthUserListByUserId(userId);
  10.     }
复制代码
(5)在原user的Mapper.xml下添加如下sql

  1.         <resultMap id="SysAuthUserResult" type="SysAuthUser">
  2.                 <id     property="authId"       column="auth_id"        />
  3.                 <result property="uuid"         column="uuid"           />
  4.                 <result property="userId"       column="user_id"        />
  5.                 <result property="userName"     column="user_name"      />
  6.                 <result property="nickName"     column="nick_name"      />
  7.                 <result property="avatar"       column="avatar"         />
  8.                 <result property="email"        column="email"          />
  9.                 <result property="source"       column="source"         />
  10.                 <result property="createTime"   column="create_time"    />
  11.         </resultMap>
  12.         <select id="selectAuthUserByUuid" parameterType="String" resultMap="SysUserResult">
  13.             select b.user_id as user_id, b.user_name as user_name, b.password as password
  14.             from sys_auth_user a left join sys_user b on a.user_id = b.user_id
  15.                 where a.uuid = #{uuid} and b.del_flag = '0'
  16.         </select>
  17.        
  18.         <select id="selectAuthUserListByUserId" parameterType="Long" resultMap="SysAuthUserResult">
  19.             select auth_id, uuid, user_id, user_name, nick_name, avatar, email, source, create_time
  20.             from sys_auth_user where user_id = #{userId}
  21.         </select>
  22.        
  23.         <select id="checkAuthUser" parameterType="SysAuthUser" resultType="int">
  24.                 select count(1) from sys_auth_user where user_id=#{userId} and source=#{source} limit 1
  25.         </select>
  26.        
  27.         <insert id="insertAuthUser" parameterType="SysAuthUser">
  28.                 insert into sys_auth_user(
  29.                     <if test="uuid != null and uuid != ''">uuid,</if>
  30.                         <if test="userId != null and userId != 0">user_id,</if>
  31.                         <if test="userName != null and userName != ''">user_name,</if>
  32.                         <if test="nickName != null and nickName != ''">nick_name,</if>
  33.                         <if test="avatar != null and avatar != ''">avatar,</if>
  34.                         <if test="email != null and email != ''">email,</if>
  35.                         <if test="source != null and source != ''">source,</if>
  36.                         create_time
  37.                 )values(
  38.                     <if test="uuid != null and uuid != ''">#{uuid},</if>
  39.                         <if test="userId != null and userId != 0">#{userId},</if>
  40.                         <if test="userName != null and userName != ''">#{userName},</if>
  41.                         <if test="nickName != null and nickName != ''">#{nickName},</if>
  42.                         <if test="avatar != null and avatar != ''">#{avatar},</if>
  43.                         <if test="email != null and email != ''">#{email},</if>
  44.                         <if test="source != null and source != ''">#{source},</if>
  45.                         sysdate()
  46.                 )
  47.         </insert>
  48.        
  49.         <delete id="deleteAuthUser" parameterType="Long">
  50.                 delete from sys_auth_user where auth_id = #{authId}
  51.         </delete>
复制代码
5、添加SysAuthController

   注意:
①这里的auths下的clientId需要自己获取正式的个人网站客户端id、密钥、回调 等信息;
②回调地址需要写成前端页面的地址,不是后端的;
③此处更改了三方登录的方式,新增了无绑定账户自动创建账户并登录的代码逻辑,并修复了一些绑定三方账户的bug;
  参考JustAuth官网集成第三方步调
  1. package top.chengrongyu.web.controller.system;
  2. import java.io.IOException;
  3. import java.util.HashMap;
  4. import java.util.Map;
  5. import javax.servlet.http.HttpServletRequest;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.web.bind.annotation.DeleteMapping;
  8. import org.springframework.web.bind.annotation.GetMapping;
  9. import org.springframework.web.bind.annotation.PathVariable;
  10. import org.springframework.web.bind.annotation.RequestMapping;
  11. import org.springframework.web.bind.annotation.ResponseBody;
  12. import org.springframework.web.bind.annotation.RestController;
  13. import com.alibaba.fastjson2.JSONObject;
  14. import me.zhyd.oauth.cache.AuthDefaultStateCache;
  15. import me.zhyd.oauth.cache.AuthStateCache;
  16. import me.zhyd.oauth.model.AuthCallback;
  17. import me.zhyd.oauth.model.AuthResponse;
  18. import me.zhyd.oauth.model.AuthUser;
  19. import me.zhyd.oauth.request.AuthRequest;
  20. import me.zhyd.oauth.utils.AuthStateUtils;
  21. import org.springframework.web.multipart.MultipartFile;
  22. import top.chengrongyu.common.constant.Constants;
  23. import top.chengrongyu.common.core.controller.BaseController;
  24. import top.chengrongyu.common.core.domain.AjaxResult;
  25. import top.chengrongyu.common.core.domain.entity.SysUser;
  26. import top.chengrongyu.common.core.domain.model.LoginUser;
  27. import top.chengrongyu.common.enums.UserStatus;
  28. import top.chengrongyu.common.exception.ServiceException;
  29. import top.chengrongyu.common.utils.AuthUtils;
  30. import top.chengrongyu.common.utils.SecurityUtils;
  31. import top.chengrongyu.common.utils.StringUtils;
  32. import top.chengrongyu.framework.web.service.SysLoginService;
  33. import top.chengrongyu.framework.web.service.SysPermissionService;
  34. import top.chengrongyu.framework.web.service.TokenService;
  35. import top.chengrongyu.system.domain.SysAuthUser;
  36. import top.chengrongyu.system.mapper.SysUserMapper;
  37. import top.chengrongyu.system.service.ISysUserService;
  38. import static top.chengrongyu.common.utils.file.FileUploadUtils.fileUrlConvertToMultipartImage;
  39. import static top.chengrongyu.common.utils.file.FileUploadUtils.upload;
  40. /**
  41. * 第三方认证授权处理
  42. *
  43. * @author cry
  44. */
  45. @RestController
  46. @RequestMapping("/system/auth")
  47. public class SysAuthController extends BaseController {
  48.     private AuthStateCache authStateCache;
  49.     @Autowired
  50.     private ISysUserService userService;
  51.     @Autowired
  52.     private SysPermissionService permissionService;
  53.     @Autowired
  54.     private TokenService tokenService;
  55.     @Autowired
  56.     private SysUserMapper userMapper;
  57.     @Autowired
  58.     private SysLoginService loginService;
  59.     /**
  60.      * 三方应用登录回调地址
  61.      */
  62.     String redirectUri = "http://127.0.0.1:81/social-login?source=";// PC
  63.     String redirectUriMobile = "http://127.0.0.1:9090/pages/socialLogin?source=";// Mobile  注意:/# 哈希值不能携带!URL中的哈希值(#)部分可能不会被服务器处理
  64.     /**
  65.      * gitee 客户端ID
  66.      */
  67.     String giteeClientId = "xxxx";
  68.     /**
  69.      * gitee 客户端密钥
  70.      */
  71.     String giteeClientSecret = "xxxx";
  72.     private final static Map<String, String> auths = new HashMap<String, String>();
  73.     {
  74.         auths.put("gitee", "{"clientId":"" + giteeClientId + "","clientSecret":"" + giteeClientSecret + "","redirectUri":"" + redirectUri + "gitee"+"","redirectUriMobile":"" + redirectUriMobile + "gitee"}");
  75.         authStateCache = AuthDefaultStateCache.INSTANCE;
  76.     }
  77.     /**
  78.      * 认证授权
  79.      *
  80.      * @param source 三方平台
  81.      * @param type 请求端类型 PC、Mobile
  82.      * @throws IOException
  83.      */
  84.     @GetMapping("/binding/{source}/{type}")
  85.     @ResponseBody
  86.     public AjaxResult authBinding(@PathVariable("source") String source,@PathVariable("type")String type, HttpServletRequest request) throws IOException {
  87.         LoginUser tokenUser = tokenService.getLoginUser(request);
  88.         if (StringUtils.isNotNull(tokenUser) && userMapper.checkAuthUser(tokenUser.getUserId(), source) > 0) {
  89.             return error(source + "平台账号已经绑定");
  90.         }
  91.         String obj = auths.get(source);
  92.         if (StringUtils.isEmpty(obj)) {
  93.             return error(source + "平台账号暂不支持");
  94.         }
  95.         JSONObject json = JSONObject.parseObject(obj);
  96.         /**
  97.          * 校验是PC端还是Mobile端
  98.          */
  99.         String url = "PC".equals(type) ? json.getString("redirectUri") : json.getString("redirectUriMobile");
  100.         AuthRequest authRequest = AuthUtils.getAuthRequest(source, json.getString("clientId"), json.getString("clientSecret"), url, authStateCache);
  101.         String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
  102.         System.out.println(authorizeUrl);
  103.         return success(authorizeUrl);
  104.     }
  105.     @SuppressWarnings("unchecked")
  106.     @GetMapping("/social-login/{source}/{type}")
  107.     public AjaxResult socialLogin(@PathVariable("source") String source,@PathVariable("type") String type, AuthCallback callback, HttpServletRequest request) throws IOException {
  108.         String obj = auths.get(source);
  109.         if (StringUtils.isEmpty(obj)) {
  110.             return AjaxResult.error(10002, "第三方平台系统不支持或未提供来源");
  111.         }
  112.         JSONObject json = JSONObject.parseObject(obj);
  113.         /**
  114.          * 校验是PC端还是Mobile端
  115.          */
  116.         String url = "PC".equals(type) ? json.getString("redirectUri") : json.getString("redirectUriMobile");
  117.         AuthRequest authRequest = AuthUtils.getAuthRequest(source, json.getString("clientId"), json.getString("clientSecret"), url, authStateCache);
  118.         AuthResponse<AuthUser> response = authRequest.login(callback);
  119.         if (response.ok()) {
  120.             /**
  121.              * 获取当前请求下登录用户缓存信息
  122.              */
  123.             LoginUser tokenUser = null;
  124.             try {
  125.                 tokenUser = tokenService.getLoginUser(request);
  126.             } catch (ServiceException e) {
  127.                 /**
  128.                  * 提示获取用户信息异常时,抛出异常 不做处理
  129.                  */
  130.                 throw e;
  131.             }finally {
  132.                 /**
  133.                  * 根据三方登录平台的uuid查询用户三方绑定信息
  134.                  */
  135.                 SysUser authUserByUuid = userMapper.selectAuthUserByUuid(source + response.getData().getUuid());
  136.                 /**
  137.                  * 验证当前用户是否已经登录  并且验证当前登录的和绑定的是否是一个账户
  138.                  */
  139.                 if (StringUtils.isNotNull(tokenUser)) {
  140.                     if (StringUtils.isNotNull(authUserByUuid) && tokenUser.getUserId() == authUserByUuid.getUserId()) {
  141.                         String token = tokenService.createToken(SecurityUtils.getLoginUser());
  142.                         return success().put(Constants.TOKEN, token);
  143.                     }
  144.                     /**
  145.                      * 判断 当前登录的和绑定的不是一个账户时
  146.                      */
  147.                     if (authUserByUuid != null && authUserByUuid.getUserId() != null) {
  148.                         return AjaxResult.error(10002, "对不起,来自" + source + "的账户已有绑定账户,如有需要,请登录原账户解绑后重新绑定!");
  149.                     }else{
  150.                         /**
  151.                          * 若已经登录,但未绑定该三方授权信息
  152.                          * 则直接绑定当前登录的系统账号
  153.                          */
  154.                         SysAuthUser authUser = new SysAuthUser();
  155.                         authUser.setAvatar(response.getData().getAvatar());
  156.                         authUser.setUuid(source + response.getData().getUuid());
  157.                         authUser.setUserId(SecurityUtils.getUserId());
  158.                         authUser.setUserName(response.getData().getUsername());
  159.                         authUser.setNickName(response.getData().getNickname());
  160.                         authUser.setEmail(response.getData().getEmail());
  161.                         authUser.setSource(source);
  162.                         userMapper.insertAuthUser(authUser);
  163.                         String token = tokenService.createToken(SecurityUtils.getLoginUser());
  164.                         return success().put(Constants.TOKEN, token);
  165.                     }
  166.                 }
  167.                 /**
  168.                  * 当用户未登录
  169.                  * 判断 根据三方登录平台的uuid查询用户三方绑定信息 不为空时
  170.                  */
  171.                 if (StringUtils.isNotNull(authUserByUuid)) {
  172.                     SysUser user = userService.selectUserByUserName(authUserByUuid.getUserName());
  173.                     if (StringUtils.isNull(user)) {
  174.                         throw new ServiceException("登录用户:" + user.getUserName() + " 不存在");
  175.                     } else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
  176.                         throw new ServiceException("对不起,您的账号:" + user.getUserName() + " 已被删除");
  177.                     } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
  178.                         throw new ServiceException("对不起,您的账号:" + user.getUserName() + " 已停用");
  179.                     }
  180.                     LoginUser loginUser = new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
  181.                     String token = tokenService.createToken(loginUser);
  182.                     return success().put(Constants.TOKEN, token);
  183.                 } else {
  184.                     /**
  185.                      * 当用户未登录 且
  186.                      * 该三方登录信息也未绑定用户时
  187.                      * 创建一个新用户进行绑定
  188.                      */
  189.                     SysUser user = new SysUser();
  190.                     /**
  191.                      * 默认用户名为 uuid + _三方平台名称
  192.                      */
  193.                     user.setUserName(response.getData().getUuid()+"_"+source);
  194.                     /**
  195.                      * 默认密码为 123456
  196.                      */
  197.                     user.setPassword(SecurityUtils.encryptPassword("123456"));
  198.                     user.setNickName(response.getData().getNickname());
  199.                     /**
  200.                      * 由于存储文件路径以用户为单位
  201.                      * 所以需要登录后跟俊网络地址修改用户头像
  202.                      */
  203.                     MultipartFile multipartFile = fileUrlConvertToMultipartImage(response.getData().getAvatar(),user.getUserName()+"_avatar.png");
  204.                     String avatarUrl = upload(multipartFile);
  205.                     user.setAvatar(avatarUrl);
  206.                     user.setEmail(response.getData().getEmail());
  207.                     user.setRemark(response.getData().getRemark());
  208.                     /**
  209.                      * 新增用户信息
  210.                      */
  211.                     int rows = userService.insertUser(user);
  212.                     if(rows>0){
  213.                         /**
  214.                          * 用户添加成功后 绑定该三方授权信息
  215.                          */
  216.                         SysAuthUser authUser = new SysAuthUser();
  217.                         authUser.setUuid(source + response.getData().getUuid());
  218.                         authUser.setUserId(user.getUserId());
  219.                         authUser.setAvatar(response.getData().getAvatar());
  220.                         authUser.setUserName(response.getData().getUsername());
  221.                         authUser.setNickName(response.getData().getNickname());
  222.                         authUser.setEmail(response.getData().getEmail());
  223.                         authUser.setSource(source);
  224.                         userMapper.insertAuthUser(authUser);
  225.                         // 登录并生成令牌
  226.                         String token = loginService.login(user.getUserName(), "123456", "","");
  227.                         return success().put(Constants.TOKEN, token);
  228.                     }
  229.                 }
  230.             }
  231.         }
  232.         return AjaxResult.error(10002, "对不起,授权信息验证不通过,请联系管理员");
  233.     }
  234.     /**
  235.      * 取消授权
  236.      */
  237.     @DeleteMapping(value = "/unlock/{authId}")
  238.     public AjaxResult unlockAuth(@PathVariable Long authId) {
  239.         return toAjax(userMapper.deleteAuthUser(authId));
  240.     }
  241. }
复制代码
6、在SysProfileController获取用户个人信息的profile方法中添加如下行

使在查询的同时携带用户的三方登录授权信息
  1. ajax.put("auths", userService.selectAuthUserListByUserId(user.getUserId()));
复制代码
二、前台设置(Vue、Uniapp 设置方法一致)

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

  1. '/social-login',
复制代码
2、在/api/system 中添加授权绑定、解除账号接口文件auth.js

auth.js
  1. import request from '@/utils/request'
  2. // 绑定账号
  3. export function authBinding(source) {
  4.   return request({
  5.     url: '/system/auth/binding/' + source + '/PC', //PC、Mobile 写死即可
  6.     method: 'get'
  7.   })
  8. }
  9. // 解绑账号
  10. export function authUnlock(authId) {
  11.   return request({
  12.     url: '/system/auth/unlock/' + authId,
  13.     method: 'delete'
  14.   })
  15. }
复制代码
3、在login.js中添加三方登录接口

  1. // 第三方平台登录
  2. export function socialLogin(source, code, state) {
  3.   const data = {
  4.     code,
  5.     state
  6.   }
  7.   return request({
  8.     url: '/system/auth/social-login/' + source + '/PC', //PC、Mobile 写死即可
  9.     method: 'get',
  10.     params: data
  11.   })
  12. }
复制代码
4、设置route文件夹下的index.js路由信息(Uniapp无该步调)

在公共路由 constantRoutes 中添加三方登录的页面路径,使其在未登录时可以正常跳转页面
  1.   {    path: '/social-login',
  2.     component: () => import('@/views/socialLogin'),    hidden: true  },
复制代码
5、设置store/modules文件夹下的user.js用户存储信息

添加action下的函数
  1.     // 第三方平台登录
  2.     SocialLogin({ commit }, userInfo) {
  3.       const code = userInfo.code
  4.       const state = userInfo.state
  5.       const source = userInfo.source
  6.       return new Promise((resolve, reject) => {
  7.         socialLogin(source, code, state).then(res => {
  8.           setToken(res.token)
  9.           commit('SET_TOKEN', res.token)
  10.           resolve()
  11.         }).catch(error => {
  12.           reject(error)
  13.         })
  14.       })
  15.     },
复制代码
6、设置utils文件夹下的request.js请求文件处理信息

添加第三方登录失败时的报错信息处理,夹在401和500之间即可
  1. else if (code === 10002) {
  2.     // 第三方登录错误提示
  3.     MessageBox.confirm(msg, '系统提示', {
  4.       confirmButtonText: '重新登录',
  5.       cancelButtonText: '取消',
  6.       type: 'warning'
  7.     }
  8.     ).then(() => {
  9.       store.dispatch('LogOut').then(() => {
  10.         location.href = '/index';// Uniapp 写 '/pages/login'
  11.       })
  12.     }).catch(() => { });
  13.     return Promise.reject(new Error(msg))
  14.   }
复制代码
7、添加三方登录页面socialLogin.vue

socialLogin.vue
  1. <template>
  2.   <div></div>
  3. </template>
  4. <script>
  5. import { Loading } from 'element-ui'
  6. let loadingInstance;
  7. export default {
  8.   data() {
  9.     return {
  10.       redirect: undefined,
  11.     };
  12.   },
  13.   created() {
  14.     loadingInstance = Loading.service({
  15.       lock: true,
  16.       text: "正在验证第三方应用账户数据,请稍候",
  17.       spinner: "el-icon-loading",
  18.       background: "rgba(0, 0, 0, 0.7)",
  19.     })
  20.      // 第三方登录回调参数
  21.     this.source = this.$route.query.source;
  22.     this.code = this.$route.query.code;
  23.     this.state = this.$route.query.state;
  24.     this.$store.dispatch("SocialLogin", {
  25.       code: this.code,
  26.       state: this.state,
  27.       source: this.source
  28.     }).then(() => {
  29.       loadingInstance.close();
  30.       this.$router.push({ path: this.redirect || "/" }).catch(()=>{});
  31.     }).catch(() => {
  32.       loadingInstance.close();
  33.     });
  34.   },
  35.   methods: {
  36.   },
  37. };
  38. </script>
  39. <style rel="stylesheet/scss" lang="scss">
  40. </style>
复制代码
8、登录页面添加三方登录跳转信息链接

vue
  1.       <!--  第三方应用登录 -->
  2.       <el-form-item style="width:100%;">
  3.         <div class="oauth-login" style="display:flex">
  4.           <div class="oauth-login-item" @click="doSocialLogin('gitee')">
  5.             <svg-icon icon-class="gitee" style="height:1.2em" />
  6.             <span>Gitee</span>
  7.           </div>
  8.           <div class="oauth-login-item" @click="doSocialLogin('github')">
  9.             <svg-icon icon-class="github" style="height:1.2em" />
  10.             <span>Github</span>
  11.           </div>
  12.           <div class="oauth-login-item">
  13.             <svg-icon icon-class="weixin" style="height:1.2em" />
  14.             <span>Weixin</span>
  15.           </div>
  16.           <div class="oauth-login-item">
  17.             <svg-icon icon-class="qq" style="height:1.2em" />
  18.             <span>QQ</span>
  19.           </div>
  20.         </div>
  21.       </el-form-item>
复制代码
js函数
  1.         import { authBinding } from "@/api/system/auth";
  2.        
  3.         ……
  4.        
  5.     // 三方登录
  6.     doSocialLogin(source) {
  7.       authBinding(source).then(res => {
  8.         top.location.href = res.msg;
  9.       });
  10.     }
  11.         ……
复制代码
css
  1. .oauth-login {
  2.   display: flex;
  3.   align-items: cen;
  4.   cursor:pointer;
  5. }
  6. .oauth-login-item {
  7.   display: flex;
  8.   align-items: center;
  9.   margin-right: 10px;
  10. }
  11. .oauth-login-item img {
  12.   height: 25px;
  13.   width: 25px;
  14. }
  15. .oauth-login-item span:hover {
  16.   text-decoration: underline red;
  17.   color: red;
  18. }
复制代码
9、添加个人中心三方登录信息展示(Uniapp需根据需要自界说)

views\system\user\profile\index.vue添加如下
vue
  1.             <el-tab-pane label="第三方应用" name="thirdParty">
  2.               <thirdParty :auths="auths" />
  3.             </el-tab-pane>
复制代码
js
  1. import thirdParty from "./thirdParty";
  2. export default {
  3.   name: "Profile",
  4.   components: { userAvatar, userInfo, resetPwd, thirdParty },
  5.   ……
  6.   auths: {},
  7.   ……
  8.   /**
  9.    * 赋值 用户授权三方登录信息 用于回显socialLogin页面
  10.    */
  11.    this.auths = response.auths;
复制代码
添加thirdParty.vue页面
  1. <template>
  2.   <div>
  3.     <el-table :data="auths" style="width: 100%; height: 100%; font-size: 10px">
  4.       <el-table-column label="序号" width="50" type="index"></el-table-column>
  5.       <el-table-column
  6.         label="绑定账号平台"
  7.         width="140"
  8.         align="center"
  9.         prop="source"
  10.         :show-overflow-tooltip="true"
  11.       />
  12.       <el-table-column label="头像" width="120" align="center" prop="avatar">
  13.         <template slot-scope="scope">
  14.           <image-preview :src="scope.row.avatar" style="width: 45px; height: 45px" />
  15.         </template>
  16.       </el-table-column>
  17.       <el-table-column
  18.         label="系统账号"
  19.         width="180"
  20.         align="center"
  21.         prop="userName"
  22.         :show-overflow-tooltip="true"
  23.       />
  24.       <el-table-column
  25.         label="绑定时间"
  26.         width="180"
  27.         align="center"
  28.         prop="createTime"
  29.       />
  30.       <el-table-column
  31.         label="操作"
  32.         width="80"
  33.         align="center"
  34.         class-name="small-padding fixed-width"
  35.       >
  36.         <template slot-scope="scope">
  37.           <el-button
  38.             size="mini"
  39.             type="text"
  40.             icon="el-icon-delete"
  41.             @click="unlockAuth(scope.$index, scope.row)"
  42.           >解绑</el-button>
  43.         </template>
  44.       </el-table-column>
  45.     </el-table>
  46.     <div id="git-user-binding">
  47.       <h4 class="provider-desc">你可以绑定以下第三方帐号用于CyberSpace系统</h4>
  48.       <div id="authlist" class="user-bind">
  49.         <a
  50.           class="third-app"
  51.           href="#"
  52.           @click="authUrl('gitee');"
  53.           title="使用 Gitee 账号授权登录"
  54.         >
  55.           <div class="git-other-login-icon">
  56.             <svg-icon icon-class="gitee" />
  57.           </div>
  58.           <span class="app-name">Gitee</span></a
  59.         >
  60.         <a
  61.           class="third-app"
  62.           href="#"
  63.           @click="authUrl('github');"
  64.           title="使用 GitHub 账号授权登录"
  65.         >
  66.           <div class="git-other-login-icon">
  67.             <svg-icon icon-class="github" />
  68.           </div>
  69.           <span class="app-name">Github</span></a
  70.         >
  71.         <a class="third-app" href="#" title="功能开发中...">
  72.           <div class="git-other-login-icon">
  73.             <svg-icon icon-class="weixin" />
  74.           </div>
  75.           <span class="app-name">WeiXin</span></a
  76.         >
  77.         <a class="third-app" href="#" title="功能开发中...">
  78.           <div class="git-other-login-icon">
  79.             <svg-icon icon-class="qq" />
  80.           </div>
  81.           <span class="app-name">QQ</span></a
  82.         >
  83.       </div>
  84.     </div>
  85.   </div>
  86. </template>
  87. <script>
  88. import { authUnlock, authBinding } from "@/api/system/auth";
  89. export default {
  90.   props: {
  91.     auths: {
  92.       type: Array,
  93.     },
  94.   },
  95.   data() {
  96.     return {};
  97.   },
  98.   methods: {
  99.     unlockAuth(index, row) {
  100.       var _this = this;
  101.       this.$modal
  102.         .confirm('您确定要解除"' + row.source + '"的账号绑定吗?')
  103.         .then(function () {
  104.           return authUnlock(row.authId);
  105.         })
  106.         .then(() => {
  107.           _this.auths.splice(index, 1);
  108.           this.$modal.msgSuccess("解绑成功");
  109.         })
  110.         .catch(() => {});
  111.     },
  112.     authUrl(source) {
  113.        authBinding(source).then(res => {
  114.                       top.location.href = res.msg;
  115.         });
  116.     }
  117.   },
  118. };
  119. </script>
  120. <style type="text/css">
  121. .user-bind .third-app {
  122.   display: -webkit-box;
  123.   display: -ms-flexbox;
  124.   display: flex;
  125.   -webkit-box-orient: vertical;
  126.   -webkit-box-direction: normal;
  127.   -ms-flex-direction: column;
  128.   flex-direction: column;
  129.   -webkit-box-align: center;
  130.   -ms-flex-align: center;
  131.   align-items: center;
  132.   min-width: 80px;
  133.   float: left;
  134. }
  135. .user-bind {
  136.   font-size: 1rem;
  137.   text-align: start;
  138.   height: 50px;
  139.   margin-top: 10px;
  140. }
  141. .git-other-login-icon > img {
  142.   height: 32px;
  143. }
  144. a {
  145.   text-decoration: none;
  146.   cursor: pointer;
  147.   color: #005980;
  148. }
  149. .provider-desc {
  150.   font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial,
  151.     "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Liberation Sans",
  152.     "PingFang SC", "Microsoft YaHei", "Hiragino Sans GB", "Wenquanyi Micro Hei",
  153.     "WenQuanYi Zen Hei", "ST Heiti", SimHei, SimSun, "WenQuanYi Zen Hei Sharp",
  154.     sans-serif;
  155.   font-size: 1.071rem;
  156. }
  157. td > img {
  158.   height: 20px;
  159.   width: 20px;
  160.   display: inline-block;
  161.   border-radius: 50%;
  162.   margin-right: 5px;
  163. }
  164. </style>
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

王國慶

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表