Commit 8cead0869eb3b29afd6f57ba660abe394d12e342

Authored by 芋道源码
Committed by Gitee
2 parents b336655a 8dbd6143

!51 用户前台的社交登陆的部分实现

Merge pull request !51 from 芋道源码/feature/user-social
Showing 55 changed files with 859 additions and 160 deletions
mini-program-test/.eslintrc.js 0 → 100755
  1 +/*
  2 + * Eslint config file
  3 + * Documentation: https://eslint.org/docs/user-guide/configuring/
  4 + * Install the Eslint extension before using this feature.
  5 + */
  6 +module.exports = {
  7 + env: {
  8 + es6: true,
  9 + browser: true,
  10 + node: true,
  11 + },
  12 + ecmaFeatures: {
  13 + modules: true,
  14 + },
  15 + parserOptions: {
  16 + ecmaVersion: 2018,
  17 + sourceType: 'module',
  18 + },
  19 + globals: {
  20 + wx: true,
  21 + App: true,
  22 + Page: true,
  23 + getCurrentPages: true,
  24 + getApp: true,
  25 + Component: true,
  26 + requirePlugin: true,
  27 + requireMiniProgram: true,
  28 + },
  29 + // extends: 'eslint:recommended',
  30 + rules: {},
  31 +}
... ...
mini-program-test/README.md 0 → 100644
  1 +临时项目,作为测试微信小程序登陆之用
... ...
mini-program-test/app.js 0 → 100755
  1 +// app.js
  2 +App({
  3 + onLaunch() {
  4 + // 展示本地存储能力
  5 + const logs = wx.getStorageSync('logs') || []
  6 + logs.unshift(Date.now())
  7 + wx.setStorageSync('logs', logs)
  8 +
  9 + // 登录
  10 + wx.login({
  11 + success: res => {
  12 + // 发送 res.code 到后台换取 openId, sessionKey, unionId
  13 + }
  14 + })
  15 + },
  16 + globalData: {
  17 + userInfo: null
  18 + }
  19 +})
... ...
mini-program-test/app.json 0 → 100755
  1 +{
  2 + "pages":[
  3 + "pages/index/index",
  4 + "pages/logs/logs"
  5 + ],
  6 + "window":{
  7 + "backgroundTextStyle":"light",
  8 + "navigationBarBackgroundColor": "#fff",
  9 + "navigationBarTitleText": "Weixin",
  10 + "navigationBarTextStyle":"black"
  11 + },
  12 + "style": "v2",
  13 + "sitemapLocation": "sitemap.json"
  14 +}
... ...
mini-program-test/app.wxss 0 → 100755
  1 +/**app.wxss**/
  2 +.container {
  3 + height: 100%;
  4 + display: flex;
  5 + flex-direction: column;
  6 + align-items: center;
  7 + justify-content: space-between;
  8 + padding: 200rpx 0;
  9 + box-sizing: border-box;
  10 +}
... ...
mini-program-test/pages/index/index.js 0 → 100755
  1 +// index.js
  2 +
  3 +const common=require('../../utils/common.js')
  4 +// 获取应用实例
  5 +const app = getApp()
  6 +
  7 +Page({
  8 + data: {
  9 + motto: 'Hello World',
  10 + userInfo: {},
  11 + hasUserInfo: false,
  12 + canIUse: wx.canIUse('button.open-type.getUserInfo'),
  13 + canIUseGetUserProfile: false,
  14 + canIUseOpenData: wx.canIUse('open-data.type.userAvatarUrl') && wx.canIUse('open-data.type.userNickName'), // 如需尝试获取用户信息可改为false
  15 + holderText: 'to be auth'
  16 + },
  17 + // 事件处理函数
  18 + bindViewTap() {
  19 + wx.navigateTo({
  20 + url: '../logs/logs'
  21 + })
  22 + },
  23 + onLoad() {
  24 + if (wx.getUserProfile) {
  25 + this.setData({
  26 + canIUseGetUserProfile: true
  27 + })
  28 + }
  29 + },
  30 + getUserProfile(e) {
  31 + // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认,开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
  32 + wx.getUserProfile({
  33 + desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
  34 + success: (res) => {
  35 + console.log(res)
  36 + this.setData({
  37 + userInfo: res.userInfo,
  38 + hasUserInfo: true
  39 + })
  40 + }
  41 + })
  42 + },
  43 + getUserInfo(e) {
  44 + // 不推荐使用getUserInfo获取用户信息,预计自2021年4月13日起,getUserInfo将不再弹出弹窗,并直接返回匿名的用户个人信息
  45 + console.log(e)
  46 + this.setData({
  47 + userInfo: e.detail.userInfo,
  48 + hasUserInfo: true
  49 + })
  50 + },
  51 + // 小程序登录 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
  52 + wxLogin(e){
  53 + let page=this;
  54 + wx.login({
  55 + success (res) {
  56 + console.log("res:")
  57 + console.log(res)
  58 + if (res.code) {
  59 + //发起网络请求
  60 + console.log('发起网络请求'+common.baseurl)
  61 + wx.request({
  62 + url: common.baseurl+'/api/social-login2',
  63 + method: "POST",
  64 + data: {
  65 + code: res.code,
  66 + state: 'empty',
  67 + type: 33,
  68 + username: '15601691300',
  69 + password: 'admin123'
  70 + },
  71 + header: {
  72 + 'content-type': 'application/json' // 默认值
  73 + },
  74 + success: function(res) {
  75 + console.log(res.data)
  76 + let holder="auth success, token:"+res.data.data.token
  77 + page.setData({holderText: holder})
  78 + },
  79 + fail: function(data){
  80 + console.error("请求出错");
  81 + console.error(data)
  82 + }
  83 +
  84 + })
  85 + } else {
  86 + console.log('登录失败!' + res.errMsg)
  87 + }
  88 + }
  89 + })
  90 + }
  91 +})
... ...
mini-program-test/pages/index/index.json 0 → 100755
  1 +{
  2 + "usingComponents": {}
  3 +}
0 4 \ No newline at end of file
... ...
mini-program-test/pages/index/index.wxml 0 → 100755
  1 +<!--index.wxml-->
  2 +<view class="container">
  3 + <view class="userinfo">
  4 + <block wx:if="{{canIUseOpenData}}">
  5 +
  6 +
  7 + </block>
  8 + <block wx:elif="{{!hasUserInfo}}">
  9 + <button wx:if="{{canIUseGetUserProfile}}" bindtap="getUserProfile"> 获取头像昵称 </button>
  10 + <button wx:elif="{{canIUse}}" open-type="getUserInfo" bindgetuserinfo="getUserInfo"> 获取头像昵称 </button>
  11 + <view wx:else> 请使用1.4.4及以上版本基础库 </view>
  12 + </block>
  13 + <block wx:else>
  14 + <image bindtap="bindViewTap" class="userinfo-avatar" src="{{userInfo.avatarUrl}}" mode="cover"></image>
  15 + <text class="userinfo-nickname">{{userInfo.nickName}}</text>
  16 + </block>
  17 + </view>
  18 + <view class="usermotto">
  19 +
  20 + </view>
  21 +
  22 +
  23 +
  24 + <text style="position: relative; left: 1rpx; top: -476rpx">授权登录测试1024</text>
  25 +
  26 + <button style="position: relative; left: 0rpx; top: -361rpx" type="primary" id="login-button" bindtap="wxLogin">点击授权登录</button>
  27 +
  28 + <text style="position: relative; left: 1rpx; top: -272rpx" id="login-user-id">{{holderText}}</text>
  29 +</view>
... ...
mini-program-test/pages/index/index.wxss 0 → 100755
  1 +/**index.wxss**/
  2 +.userinfo {
  3 + display: flex;
  4 + flex-direction: column;
  5 + align-items: center;
  6 + color: #aaa;
  7 +}
  8 +
  9 +.userinfo-avatar {
  10 + overflow: hidden;
  11 + width: 128rpx;
  12 + height: 128rpx;
  13 + margin: 20rpx;
  14 + border-radius: 50%;
  15 +}
  16 +
  17 +.usermotto {
  18 + margin-top: 200px;
  19 +}
0 20 \ No newline at end of file
... ...
mini-program-test/pages/logs/logs.js 0 → 100755
  1 +// logs.js
  2 +const util = require('../../utils/util.js')
  3 +
  4 +Page({
  5 + data: {
  6 + logs: []
  7 + },
  8 + onLoad() {
  9 + this.setData({
  10 + logs: (wx.getStorageSync('logs') || []).map(log => {
  11 + return {
  12 + date: util.formatTime(new Date(log)),
  13 + timeStamp: log
  14 + }
  15 + })
  16 + })
  17 + }
  18 +})
... ...
mini-program-test/pages/logs/logs.json 0 → 100755
  1 +{
  2 + "navigationBarTitleText": "查看启动日志",
  3 + "usingComponents": {}
  4 +}
0 5 \ No newline at end of file
... ...
mini-program-test/pages/logs/logs.wxml 0 → 100755
  1 +<!--logs.wxml-->
  2 +<view class="container log-list">
  3 + <block wx:for="{{logs}}" wx:key="timeStamp" wx:for-item="log">
  4 + <text class="log-item">{{index + 1}}. {{log.date}}</text>
  5 + </block>
  6 +</view>
... ...
mini-program-test/pages/logs/logs.wxss 0 → 100755
  1 +.log-list {
  2 + display: flex;
  3 + flex-direction: column;
  4 + padding: 40rpx;
  5 +}
  6 +.log-item {
  7 + margin: 10rpx;
  8 +}
... ...
mini-program-test/project.config.json 0 → 100755
  1 +{
  2 + "description": "项目配置文件",
  3 + "packOptions": {
  4 + "ignore": [
  5 + {
  6 + "type": "file",
  7 + "value": ".eslintrc.js"
  8 + }
  9 + ]
  10 + },
  11 + "setting": {
  12 + "bundle": false,
  13 + "userConfirmedBundleSwitch": false,
  14 + "urlCheck": true,
  15 + "scopeDataCheck": false,
  16 + "coverView": true,
  17 + "es6": true,
  18 + "postcss": true,
  19 + "compileHotReLoad": false,
  20 + "lazyloadPlaceholderEnable": false,
  21 + "preloadBackgroundData": false,
  22 + "minified": true,
  23 + "autoAudits": false,
  24 + "newFeature": false,
  25 + "uglifyFileName": false,
  26 + "uploadWithSourceMap": true,
  27 + "useIsolateContext": true,
  28 + "nodeModules": false,
  29 + "enhance": true,
  30 + "useMultiFrameRuntime": true,
  31 + "useApiHook": true,
  32 + "useApiHostProcess": true,
  33 + "showShadowRootInWxmlPanel": true,
  34 + "packNpmManually": false,
  35 + "enableEngineNative": false,
  36 + "packNpmRelationList": [],
  37 + "minifyWXSS": true,
  38 + "showES6CompileOption": false,
  39 + "minifyWXML": true
  40 + },
  41 + "compileType": "miniprogram",
  42 + "libVersion": "2.19.4",
  43 + "appid": "wx44d047d87e6284d8",
  44 + "appid1": "wx63c280fe3248a3e7",
  45 + "projectname": "mini-program-test",
  46 + "debugOptions": {
  47 + "hidedInDevtools": []
  48 + },
  49 + "scripts": {},
  50 + "staticServerOptions": {
  51 + "baseURL": "",
  52 + "servePath": ""
  53 + },
  54 + "isGameTourist": false,
  55 + "condition": {
  56 + "search": {
  57 + "list": []
  58 + },
  59 + "conversation": {
  60 + "list": []
  61 + },
  62 + "game": {
  63 + "list": []
  64 + },
  65 + "plugin": {
  66 + "list": []
  67 + },
  68 + "gamePlugin": {
  69 + "list": []
  70 + },
  71 + "miniprogram": {
  72 + "list": []
  73 + }
  74 + }
  75 +}
0 76 \ No newline at end of file
... ...
mini-program-test/sitemap.json 0 → 100755
  1 +{
  2 + "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html",
  3 + "rules": [{
  4 + "action": "allow",
  5 + "page": "*"
  6 + }]
  7 +}
0 8 \ No newline at end of file
... ...
mini-program-test/utils/common.js 0 → 100755
  1 +module.exports = {
  2 + baseurl: "http://127.0.0.1:28080"
  3 +}
... ...
mini-program-test/utils/util.js 0 → 100755
  1 +const formatTime = date => {
  2 + const year = date.getFullYear()
  3 + const month = date.getMonth() + 1
  4 + const day = date.getDate()
  5 + const hour = date.getHours()
  6 + const minute = date.getMinutes()
  7 + const second = date.getSeconds()
  8 +
  9 + return `${[year, month, day].map(formatNumber).join('/')} ${[hour, minute, second].map(formatNumber).join(':')}`
  10 +}
  11 +
  12 +const formatNumber = n => {
  13 + n = n.toString()
  14 + return n[1] ? n : `0${n}`
  15 +}
  16 +
  17 +module.exports = {
  18 + formatTime
  19 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/SysAuthController.java
... ... @@ -8,10 +8,11 @@ import cn.iocoder.yudao.adminserver.modules.system.enums.permission.MenuTypeEnum
8 8 import cn.iocoder.yudao.adminserver.modules.system.service.auth.SysAuthService;
9 9 import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
10 10 import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysRoleService;
11   -import cn.iocoder.yudao.adminserver.modules.system.service.social.SysSocialService;
12 11 import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
  12 +import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialService;
13 13 import cn.iocoder.yudao.coreservice.modules.system.service.user.SysUserCoreService;
14 14 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  15 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
15 16 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
16 17 import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
17 18 import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
... ... @@ -132,7 +133,7 @@ public class SysAuthController {
132 133 @DeleteMapping("/social-unbind")
133 134 @ApiOperation("取消社交绑定")
134 135 public CommonResult<Boolean> socialUnbind(@RequestBody SysAuthSocialUnbindReqVO reqVO) {
135   - socialService.unbindSocialUser(getLoginUserId(), reqVO.getType(), reqVO.getUnionId());
  136 + socialService.unbindSocialUser(getLoginUserId(), reqVO.getType(), reqVO.getUnionId(), UserTypeEnum.ADMIN);
136 137 return CommonResult.success(true);
137 138 }
138 139  
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/vo/auth/SysAuthSocialBindReqVO.java
1 1 package cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth;
2 2  
3   -import cn.iocoder.yudao.adminserver.modules.system.enums.social.SysSocialTypeEnum;
  3 +import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
4 4 import cn.iocoder.yudao.framework.common.validation.InEnum;
5 5 import io.swagger.annotations.ApiModel;
6 6 import io.swagger.annotations.ApiModelProperty;
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/vo/auth/SysAuthSocialLogin2ReqVO.java
1 1 package cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth;
2 2  
3   -import cn.iocoder.yudao.adminserver.modules.system.enums.social.SysSocialTypeEnum;
  3 +import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
4 4 import cn.iocoder.yudao.framework.common.validation.InEnum;
5 5 import io.swagger.annotations.ApiModel;
6 6 import io.swagger.annotations.ApiModelProperty;
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/vo/auth/SysAuthSocialLoginReqVO.java
1 1 package cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth;
2 2  
3   -import cn.iocoder.yudao.adminserver.modules.system.enums.social.SysSocialTypeEnum;
  3 +import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
4 4 import cn.iocoder.yudao.framework.common.validation.InEnum;
5 5 import io.swagger.annotations.ApiModel;
6 6 import io.swagger.annotations.ApiModelProperty;
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/auth/vo/auth/SysAuthSocialUnbindReqVO.java
1 1 package cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth;
2 2  
3   -import cn.iocoder.yudao.adminserver.modules.system.enums.social.SysSocialTypeEnum;
  3 +import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
4 4 import cn.iocoder.yudao.framework.common.validation.InEnum;
5 5 import io.swagger.annotations.ApiModel;
6 6 import io.swagger.annotations.ApiModelProperty;
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/controller/user/SysUserProfileController.java
... ... @@ -8,15 +8,16 @@ import cn.iocoder.yudao.adminserver.modules.system.convert.user.SysUserConvert;
8 8 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO;
9 9 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysPostDO;
10 10 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysRoleDO;
11   -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.social.SysSocialUserDO;
12 11 import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService;
13 12 import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysPostService;
14 13 import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
15 14 import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysRoleService;
16   -import cn.iocoder.yudao.adminserver.modules.system.service.social.SysSocialService;
17 15 import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
  16 +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social.SysSocialUserDO;
18 17 import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
  18 +import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialService;
19 19 import cn.iocoder.yudao.coreservice.modules.system.service.user.SysUserCoreService;
  20 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
20 21 import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
21 22 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
22 23 import io.swagger.annotations.Api;
... ... @@ -77,7 +78,7 @@ public class SysUserProfileController {
77 78 resp.setPosts(SysUserConvert.INSTANCE.convertList02(posts));
78 79 }
79 80 // 获得社交用户信息
80   - List<SysSocialUserDO> socialUsers = socialService.getSocialUserList(user.getId());
  81 + List<SysSocialUserDO> socialUsers = socialService.getSocialUserList(user.getId(), UserTypeEnum.ADMIN);
81 82 resp.setSocialUsers(SysUserConvert.INSTANCE.convertList03(socialUsers));
82 83 return success(resp);
83 84 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/convert/user/SysUserConvert.java
... ... @@ -7,7 +7,7 @@ import cn.iocoder.yudao.adminserver.modules.system.controller.user.vo.user.*;
7 7 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO;
8 8 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysPostDO;
9 9 import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysRoleDO;
10   -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.social.SysSocialUserDO;
  10 +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social.SysSocialUserDO;
11 11 import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
12 12 import org.mapstruct.Mapper;
13 13 import org.mapstruct.factory.Mappers;
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/redis/SysRedisKeyConstants.java
... ... @@ -19,12 +19,5 @@ public interface SysRedisKeyConstants {
19 19 "captcha_code:%s", // 参数为 uuid
20 20 STRING, String.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);
21 21  
22   - RedisKeyDefine SOCIAL_AUTH_USER = new RedisKeyDefine("社交的授权用户",
23   - "social_auth_user:%d:%s", // 参数为 type,code
24   - STRING, AuthUser.class, Duration.ofDays(1));
25   -
26   - RedisKeyDefine SOCIAL_AUTH_STATE = new RedisKeyDefine("社交的 state",
27   - "social_auth_state:%s", // 参数为 state
28   - STRING, String.class, Duration.ofHours(24)); // 值为 state
29 22  
30 23 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/SysErrorCodeConstants.java
... ... @@ -89,8 +89,6 @@ public interface SysErrorCodeConstants {
89 89 ErrorCode ERROR_CODE_NOT_EXISTS = new ErrorCode(1002013000, "错误码不存在");
90 90 ErrorCode ERROR_CODE_DUPLICATE = new ErrorCode(1002013001, "已经存在编码为【{}】的错误码");
91 91  
92   - // ========== 社交模块 1002014000 ==========
93   - ErrorCode SOCIAL_AUTH_FAILURE = new ErrorCode(1002014000, "社交授权失败,原因是:{}");
94   - ErrorCode SOCIAL_UNBIND_NOT_SELF = new ErrorCode(1002014001, "社交解绑失败,非当前用户绑定");
  92 +
95 93  
96 94 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java
... ... @@ -6,18 +6,18 @@ import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAu
6 6 import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthSocialLogin2ReqVO;
7 7 import cn.iocoder.yudao.adminserver.modules.system.controller.auth.vo.auth.SysAuthSocialLoginReqVO;
8 8 import cn.iocoder.yudao.adminserver.modules.system.convert.auth.SysAuthConvert;
9   -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.social.SysSocialUserDO;
10 9 import cn.iocoder.yudao.adminserver.modules.system.enums.logger.SysLoginLogTypeEnum;
11 10 import cn.iocoder.yudao.adminserver.modules.system.enums.logger.SysLoginResultEnum;
12 11 import cn.iocoder.yudao.adminserver.modules.system.service.auth.SysAuthService;
13 12 import cn.iocoder.yudao.adminserver.modules.system.service.common.SysCaptchaService;
14 13 import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
15   -import cn.iocoder.yudao.adminserver.modules.system.service.social.SysSocialService;
16 14 import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
  15 +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social.SysSocialUserDO;
17 16 import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
18 17 import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService;
19 18 import cn.iocoder.yudao.coreservice.modules.system.service.logger.SysLoginLogCoreService;
20 19 import cn.iocoder.yudao.coreservice.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
  20 +import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialService;
21 21 import cn.iocoder.yudao.coreservice.modules.system.service.user.SysUserCoreService;
22 22 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
23 23 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
... ... @@ -75,6 +75,9 @@ public class SysAuthServiceImpl implements SysAuthService {
75 75 @Resource
76 76 private SysSocialService socialService;
77 77  
  78 + // TODO @timfruit:静态枚举类,需要都大写,例如说 USER_TYPE_ENUM;静态变量,放在普通变量前面;这个实践不错哈。
  79 + private static final UserTypeEnum userTypeEnum = UserTypeEnum.ADMIN;
  80 +
78 81 @Override
79 82 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
80 83 // 获取 username 对应的 SysUserDO
... ... @@ -198,7 +201,7 @@ public class SysAuthServiceImpl implements SysAuthService {
198 201  
199 202 // 如果未绑定 SysSocialUserDO 用户,则无法自动登录,进行报错
200 203 String unionId = socialService.getAuthUserUnionId(authUser);
201   - List<SysSocialUserDO> socialUsers = socialService.getAllSocialUserList(reqVO.getType(), unionId);
  204 + List<SysSocialUserDO> socialUsers = socialService.getAllSocialUserList(reqVO.getType(), unionId, userTypeEnum);
202 205 if (CollUtil.isEmpty(socialUsers)) {
203 206 throw exception(AUTH_THIRD_LOGIN_NOT_BIND);
204 207 }
... ... @@ -212,11 +215,10 @@ public class SysAuthServiceImpl implements SysAuthService {
212 215  
213 216 // 创建 LoginUser 对象
214 217 LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user);
215   - // TODO 芋艿:需要改造下,增加各种登录方式
216 218 loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表
217 219  
218 220 // 绑定社交用户(更新)
219   - socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser);
  221 + socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, userTypeEnum);
220 222  
221 223 // 缓存登录用户到 Redis 中,返回 sessionId 编号
222 224 return userSessionCoreService.createUserSession(loginUser, userIp, userAgent);
... ... @@ -233,7 +235,7 @@ public class SysAuthServiceImpl implements SysAuthService {
233 235 loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表
234 236  
235 237 // 绑定社交用户(新增)
236   - socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser);
  238 + socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, userTypeEnum);
237 239  
238 240 // 缓存登录用户到 Redis 中,返回 sessionId 编号
239 241 return userSessionCoreService.createUserSession(loginUser, userIp, userAgent);
... ... @@ -246,7 +248,7 @@ public class SysAuthServiceImpl implements SysAuthService {
246 248 Assert.notNull(authUser, "授权用户不为空");
247 249  
248 250 // 绑定社交用户(新增)
249   - socialService.bindSocialUser(userId, reqVO.getType(), authUser);
  251 + socialService.bindSocialUser(userId, reqVO.getType(), authUser, userTypeEnum);
250 252 }
251 253  
252 254 @Override
... ... @@ -267,7 +269,7 @@ public class SysAuthServiceImpl implements SysAuthService {
267 269 reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType());
268 270 reqDTO.setTraceId(TracerUtils.getTraceId());
269 271 reqDTO.setUserId(userId);
270   - reqDTO.setUserType(UserTypeEnum.ADMIN.getValue());
  272 + reqDTO.setUserType(userTypeEnum.getValue());
271 273 reqDTO.setUsername(username);
272 274 reqDTO.setUserAgent(ServletUtils.getUserAgent());
273 275 reqDTO.setUserIp(ServletUtils.getClientIP());
... ...
yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/SysAuthServiceImplTest.java
... ... @@ -7,11 +7,11 @@ import cn.iocoder.yudao.adminserver.modules.system.enums.logger.SysLoginResultEn
7 7 import cn.iocoder.yudao.adminserver.modules.system.service.auth.impl.SysAuthServiceImpl;
8 8 import cn.iocoder.yudao.adminserver.modules.system.service.common.SysCaptchaService;
9 9 import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService;
10   -import cn.iocoder.yudao.adminserver.modules.system.service.social.SysSocialService;
11 10 import cn.iocoder.yudao.adminserver.modules.system.service.user.SysUserService;
12 11 import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
13 12 import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService;
14 13 import cn.iocoder.yudao.coreservice.modules.system.service.logger.SysLoginLogCoreService;
  14 +import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialService;
15 15 import cn.iocoder.yudao.coreservice.modules.system.service.user.SysUserCoreService;
16 16 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
17 17 import cn.iocoder.yudao.framework.security.core.LoginUser;
... ...
yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/social/SysSocialServiceTest.java
1 1 package cn.iocoder.yudao.adminserver.modules.system.service.social;
2 2  
3 3 import cn.iocoder.yudao.adminserver.BaseDbAndRedisUnitTest;
4   -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.social.SysSocialUserDO;
5   -import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.social.SysSocialUserMapper;
6   -import cn.iocoder.yudao.adminserver.modules.system.dal.redis.social.SysSocialAuthUserRedisDAO;
7   -import cn.iocoder.yudao.adminserver.modules.system.enums.social.SysSocialTypeEnum;
8   -import cn.iocoder.yudao.adminserver.modules.system.service.social.impl.SysSocialServiceImpl;
  4 +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social.SysSocialUserDO;
  5 +import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.social.SysSocialUserMapper;
  6 +import cn.iocoder.yudao.coreservice.modules.system.dal.redis.social.SysSocialAuthUserRedisDAO;
  7 +import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
  8 +import cn.iocoder.yudao.coreservice.modules.system.service.social.impl.SysSocialServiceImpl;
9 9 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
10 10 import com.xkcoding.justauth.AuthRequestFactory;
11 11 import me.zhyd.oauth.model.AuthUser;
... ... @@ -23,6 +23,7 @@ import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId
23 23 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
24 24 import static org.junit.jupiter.api.Assertions.assertEquals;
25 25  
  26 +// TODO @timfruit:这个单元测试,挪到 yudao-core-service
26 27 /**
27 28 * {@link SysSocialServiceImpl} 的单元测试类
28 29 *
... ... @@ -53,7 +54,7 @@ public class SysSocialServiceTest extends BaseDbAndRedisUnitTest {
53 54 // mock 方法
54 55  
55 56 // 调用
56   - socialService.bindSocialUser(userId, type, authUser);
  57 + socialService.bindSocialUser(userId, type, authUser, UserTypeEnum.ADMIN);
57 58 // 断言
58 59 List<SysSocialUserDO> socialUsers = socialUserMapper.selectList("user_id", userId);
59 60 assertEquals(1, socialUsers.size());
... ... @@ -78,7 +79,7 @@ public class SysSocialServiceTest extends BaseDbAndRedisUnitTest {
78 79 // mock 方法
79 80  
80 81 // 调用
81   - socialService.bindSocialUser(userId, type, authUser);
  82 + socialService.bindSocialUser(userId, type, authUser, UserTypeEnum.ADMIN);
82 83 // 断言
83 84 List<SysSocialUserDO> socialUsers = socialUserMapper.selectList("user_id", userId);
84 85 assertEquals(1, socialUsers.size());
... ... @@ -103,7 +104,7 @@ public class SysSocialServiceTest extends BaseDbAndRedisUnitTest {
103 104 // mock 方法
104 105  
105 106 // 调用
106   - socialService.bindSocialUser(userId, type, authUser);
  107 + socialService.bindSocialUser(userId, type, authUser, UserTypeEnum.ADMIN);
107 108 // 断言
108 109 List<SysSocialUserDO> socialUsers = socialUserMapper.selectList("user_id", userId);
109 110 assertEquals(1, socialUsers.size());
... ... @@ -140,7 +141,7 @@ public class SysSocialServiceTest extends BaseDbAndRedisUnitTest {
140 141 String newUnionId = oldSocialUser.getUnionId();
141 142  
142 143 // 调用
143   - socialService.unbindOldSocialUser(userId, type, newUnionId);
  144 + socialService.unbindOldSocialUser(userId, type, newUnionId, UserTypeEnum.ADMIN);
144 145 // 断言
145 146 assertEquals(1L, socialUserMapper.selectCount(null).longValue());
146 147 }
... ... @@ -163,7 +164,7 @@ public class SysSocialServiceTest extends BaseDbAndRedisUnitTest {
163 164 String newUnionId = randomString(10);
164 165  
165 166 // 调用
166   - socialService.unbindOldSocialUser(userId, type, newUnionId);
  167 + socialService.unbindOldSocialUser(userId, type, newUnionId, UserTypeEnum.ADMIN);
167 168 // 断言
168 169 assertEquals(0L, socialUserMapper.selectCount(null).longValue());
169 170 }
... ...
yudao-core-service/pom.xml
... ... @@ -95,6 +95,13 @@
95 95 <groupId>com.google.guava</groupId>
96 96 <artifactId>guava</artifactId>
97 97 </dependency>
  98 +
  99 + <!-- 三方云服务相关 -->
  100 + <dependency>
  101 + <groupId>com.xkcoding.justauth</groupId>
  102 + <artifactId>justauth-spring-boot-starter</artifactId>
  103 + </dependency>
  104 +
98 105 </dependencies>
99 106  
100 107 </project>
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/compent/justauth/AuthExtendSource.java 0 → 100644
  1 +package cn.iocoder.yudao.coreservice.modules.system.compent.justauth;
  2 +
  3 +import me.zhyd.oauth.config.AuthSource;
  4 +
  5 +public enum AuthExtendSource implements AuthSource {
  6 +
  7 + /**
  8 + * 微信小程序授权登录
  9 + */
  10 + WECHAT_MINI_PROGRAM{
  11 + @Override
  12 + public String authorize() {
  13 + // https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
  14 + throw new UnsupportedOperationException("不支持获取授权url, 请使用小程序内置函数wx.login()登录获取code");
  15 + }
  16 +
  17 + @Override
  18 + public String accessToken() {
  19 + // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html
  20 + // 获取openid, unionid , session_key
  21 + return "https://api.weixin.qq.com/sns/jscode2session";
  22 + }
  23 +
  24 + @Override
  25 + public String userInfo() {
  26 + //https://developers.weixin.qq.com/miniprogram/dev/api/open-api/user-info/wx.getUserProfile.html
  27 + throw new UnsupportedOperationException("不支持获取用户信息url, 请使用小程序内置函数wx.getUserProfile()获取用户信息");
  28 + }
  29 + }
  30 +
  31 + ;
  32 +
  33 +}
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/compent/justauth/AuthExtendToken.java 0 → 100644
  1 +package cn.iocoder.yudao.coreservice.modules.system.compent.justauth;
  2 +
  3 +import lombok.*;
  4 +import me.zhyd.oauth.model.AuthToken;
  5 +
  6 +/**
  7 + * TODO @timfruit:类注释
  8 + * @author timfruit
  9 + * @date 2021-10-29
  10 + */
  11 +@Getter
  12 +@Setter
  13 +@NoArgsConstructor
  14 +@AllArgsConstructor
  15 +public class AuthExtendToken extends AuthToken {
  16 +
  17 + /**
  18 + * 微信小程序 会话密钥
  19 + */
  20 + private String miniSessionKey;
  21 +
  22 +}
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/compent/justauth/AuthWeChatMiniProgramRequest.java 0 → 100644
  1 +package cn.iocoder.yudao.coreservice.modules.system.compent.justauth;
  2 +
  3 +import com.alibaba.fastjson.JSONObject;
  4 +import me.zhyd.oauth.cache.AuthStateCache;
  5 +import me.zhyd.oauth.config.AuthConfig;
  6 +import me.zhyd.oauth.exception.AuthException;
  7 +import me.zhyd.oauth.model.AuthCallback;
  8 +import me.zhyd.oauth.model.AuthToken;
  9 +import me.zhyd.oauth.model.AuthUser;
  10 +import me.zhyd.oauth.request.AuthDefaultRequest;
  11 +import me.zhyd.oauth.utils.HttpUtils;
  12 +import me.zhyd.oauth.utils.UrlBuilder;
  13 +
  14 +// TODO @timfruit:新建一个 yudao-spring-boot-starter-biz-social 包,把这个拓展拿进去哈。另外,可以思考下。
  15 +// 1. application-local.yaml 的配置里,justauth.extend.enum-class 能否不配置,而是自动配置好
  16 +// 2. application-local.yaml 的配置里,justauth.extend.extend.config.WECHAT_MINI_PROGRAM 有办法和 justauth.type.WECHAT_MP 持平
  17 +/**
  18 + * 微信小程序登陆
  19 + *
  20 + * @author timfruit
  21 + * @date 2021-10-29
  22 + */
  23 +public class AuthWeChatMiniProgramRequest extends AuthDefaultRequest {
  24 +
  25 + public AuthWeChatMiniProgramRequest(AuthConfig config) {
  26 + super(config, AuthExtendSource.WECHAT_MINI_PROGRAM);
  27 + }
  28 +
  29 + public AuthWeChatMiniProgramRequest(AuthConfig config, AuthStateCache authStateCache) {
  30 + super(config, AuthExtendSource.WECHAT_MINI_PROGRAM, authStateCache);
  31 + }
  32 +
  33 + @Override
  34 + protected AuthToken getAccessToken(AuthCallback authCallback) {
  35 + // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html
  36 + String response = new HttpUtils(config.getHttpConfig()).get(accessTokenUrl(authCallback.getCode()));
  37 + JSONObject accessTokenObject = JSONObject.parseObject(response); // TODO @timfruit:使用 JsonUtils,项目尽量避免直接使用某个 json 库
  38 +
  39 + this.checkResponse(accessTokenObject);
  40 +
  41 + AuthExtendToken token = new AuthExtendToken();
  42 + token.setMiniSessionKey(accessTokenObject.getString("session_key"));
  43 + token.setOpenId(accessTokenObject.getString("openid"));
  44 + token.setUnionId(accessTokenObject.getString("unionid"));
  45 + return token;
  46 + }
  47 +
  48 + @Override
  49 + protected AuthUser getUserInfo(AuthToken authToken) {
  50 + // https://developers.weixin.qq.com/miniprogram/dev/api/open-api/user-info/wx.getUserProfile.html
  51 + // 如果需要用户信息,需要在小程序调用函数后传给后端
  52 + return AuthUser.builder()
  53 + .uuid(authToken.getOpenId())
  54 + //TODO 是使用默认值,还是有小程序获取用户信息 和 code 一起传过来
  55 + .nickname("")
  56 + .avatar("")
  57 + .token(authToken)
  58 + .source(source.toString())
  59 + .build();
  60 + }
  61 +
  62 + /**
  63 + * 检查响应内容是否正确
  64 + *
  65 + * @param object 请求响应内容
  66 + */
  67 + private void checkResponse(JSONObject object) {
  68 + int code = object.getIntValue("errcode");
  69 + if(code != 0){ // TODO @timfruit:if (code != 0) { ,注意空格
  70 + throw new AuthException(object.getIntValue("errcode"), object.getString("errmsg"));
  71 + }
  72 + }
  73 +
  74 + /**
  75 + * 返回获取 accessToken 的 url
  76 + *
  77 + * @param code 授权码
  78 + * @return 返回获取 accessToken 的 url
  79 + */
  80 + @Override
  81 + protected String accessTokenUrl(String code) {
  82 + return UrlBuilder.fromBaseUrl(source.accessToken())
  83 + .queryParam("appid", config.getClientId())
  84 + .queryParam("secret", config.getClientSecret())
  85 + .queryParam("js_code", code)
  86 + .queryParam("grant_type", "authorization_code")
  87 + .build();
  88 + }
  89 +
  90 +}
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/dataobject/social/SysSocialUserDO.java renamed to yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/dataobject/social/SysSocialUserDO.java
1   -package cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.social;
  1 +package cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social;
2 2  
3 3 import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.user.SysUserDO;
4 4 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/mysql/social/SysSocialUserMapper.java renamed to yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/mysql/social/SysSocialUserMapper.java
1   -package cn.iocoder.yudao.adminserver.modules.system.dal.mysql.social;
  1 +package cn.iocoder.yudao.coreservice.modules.system.dal.mysql.social;
2 2  
3   -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.social.SysSocialUserDO;
  3 +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social.SysSocialUserDO;
4 4 import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
5 5 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
6 6 import org.apache.ibatis.annotations.Mapper;
... ... @@ -8,6 +8,7 @@ import org.apache.ibatis.annotations.Mapper;
8 8 import java.util.Collection;
9 9 import java.util.List;
10 10  
  11 +// TODO @timfruit:SysSocialUserCoreMapper 改名,方便区分
11 12 @Mapper
12 13 public interface SysSocialUserMapper extends BaseMapperX<SysSocialUserDO> {
13 14  
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/redis/SysRedisKeyCoreConstants.java
... ... @@ -2,6 +2,9 @@ package cn.iocoder.yudao.coreservice.modules.system.dal.redis;
2 2  
3 3 import cn.iocoder.yudao.framework.redis.core.RedisKeyDefine;
4 4 import cn.iocoder.yudao.framework.security.core.LoginUser;
  5 +import me.zhyd.oauth.model.AuthUser;
  6 +
  7 +import java.time.Duration;
5 8  
6 9 import static cn.iocoder.yudao.framework.redis.core.RedisKeyDefine.KeyTypeEnum.STRING;
7 10  
... ... @@ -16,4 +19,11 @@ public interface SysRedisKeyCoreConstants {
16 19 "login_user:%s", // 参数为 sessionId
17 20 STRING, LoginUser.class, RedisKeyDefine.TimeoutTypeEnum.DYNAMIC);
18 21  
  22 + RedisKeyDefine SOCIAL_AUTH_USER = new RedisKeyDefine("社交登陆的授权用户",
  23 + "social_auth_user:%d:%s", // 参数为 type,code
  24 + STRING, AuthUser.class, Duration.ofDays(1));
  25 +
  26 + RedisKeyDefine SOCIAL_AUTH_STATE = new RedisKeyDefine("社交登陆的 state",
  27 + "social_auth_state:%s", // 参数为 state
  28 + STRING, String.class, Duration.ofHours(24)); // 值为 state
19 29 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/dal/redis/social/SysSocialAuthUserRedisDAO.java renamed to yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/dal/redis/social/SysSocialAuthUserRedisDAO.java
1   -package cn.iocoder.yudao.adminserver.modules.system.dal.redis.social;
  1 +package cn.iocoder.yudao.coreservice.modules.system.dal.redis.social;
2 2  
3 3 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
4 4 import me.zhyd.oauth.model.AuthCallback;
... ... @@ -8,10 +8,11 @@ import org.springframework.stereotype.Repository;
8 8  
9 9 import javax.annotation.Resource;
10 10  
11   -import static cn.iocoder.yudao.adminserver.modules.system.dal.redis.SysRedisKeyConstants.SOCIAL_AUTH_USER;
  11 +import static cn.iocoder.yudao.coreservice.modules.system.dal.redis.SysRedisKeyCoreConstants.SOCIAL_AUTH_USER;
12 12  
  13 +// TODO @timfruit,这里的 AuthUser 还是保留全路径,主要想体现出来,不是自己定义的
13 14 /**
14   - * 社交 {@link me.zhyd.oauth.model.AuthUser} 的 RedisDAO
  15 + * 社交 {@link AuthUser} 的 RedisDAO
15 16 *
16 17 * @author 芋道源码
17 18 */
... ...
yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/enums/SysErrorCodeConstants.java
... ... @@ -18,4 +18,8 @@ public interface SysErrorCodeConstants {
18 18 ErrorCode FILE_PATH_EXISTS = new ErrorCode(1006001000, "文件路径已存在");
19 19 ErrorCode FILE_NOT_EXISTS = new ErrorCode(1006001002, "文件不存在");
20 20  
  21 + // ========== 社交模块 1006002000 ==========
  22 + ErrorCode SOCIAL_AUTH_FAILURE = new ErrorCode(1006002000, "社交授权失败,原因是:{}");
  23 + ErrorCode SOCIAL_UNBIND_NOT_SELF = new ErrorCode(1006002001, "社交解绑失败,非当前用户绑定");
  24 +
21 25 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/enums/social/SysSocialTypeEnum.java renamed to yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/enums/social/SysSocialTypeEnum.java
1   -package cn.iocoder.yudao.adminserver.modules.system.enums.social;
  1 +package cn.iocoder.yudao.coreservice.modules.system.enums.social;
2 2  
3 3 import cn.hutool.core.collection.ListUtil;
4 4 import cn.hutool.core.util.ArrayUtil;
... ... @@ -18,14 +18,43 @@ import java.util.List;
18 18 @AllArgsConstructor
19 19 public enum SysSocialTypeEnum implements IntArrayValuable {
20 20  
21   - GITEE(10, "GITEE"), // https://gitee.com/api/v5/oauth_doc#/
22   - DINGTALK(20, "DINGTALK"), // https://developers.dingtalk.com/document/app/obtain-identity-credentials
23   - WECHAT_ENTERPRISE(30, "WECHAT_ENTERPRISE"), // https://xkcoding.com/2019/08/06/use-justauth-integration-wechat-enterprise.html
  21 + /**
  22 + * Gitee
  23 + * 文档链接:https://gitee.com/api/v5/oauth_doc#/
  24 + */
  25 + GITEE(10, "GITEE"),
  26 + /**
  27 + * 钉钉
  28 + * 文档链接:https://developers.dingtalk.com/document/app/obtain-identity-credentials
  29 + */
  30 + DINGTALK(20, "DINGTALK"),
  31 +
  32 + /**
  33 + * 企业微信
  34 + * 文档链接:https://xkcoding.com/2019/08/06/use-justauth-integration-wechat-enterprise.html
  35 + */
  36 + WECHAT_ENTERPRISE(30, "WECHAT_ENTERPRISE"),
  37 + /**
  38 + * 微信公众平台 - 移动端 H5
  39 + * 文档链接:https://www.cnblogs.com/juewuzhe/p/11905461.html
  40 + */
  41 + WECHAT_MP(31, "WECHAT_MP"),
  42 + /**
  43 + * 微信开放平台 - 网站应用 PC 端扫码授权登录
  44 + * 文档链接:https://justauth.wiki/guide/oauth/wechat_open/#_2-申请开发者资质认证
  45 + */
  46 + WECHAT_OPEN(32, "WECHAT_OPEN"),
  47 + /**
  48 + * 微信小程序
  49 + * 文档链接:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
  50 + */
  51 + WECHAT_MINI_PROGRAM(33, "WECHAT_MINI_PROGRAM"),
24 52 ;
25 53  
26 54 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SysSocialTypeEnum::getType).toArray();
27 55  
28   - public static final List<Integer> WECHAT_ALL = ListUtil.toList(WECHAT_ENTERPRISE.type);
  56 + public static final List<Integer> WECHAT_ALL = ListUtil.toList(WECHAT_ENTERPRISE.type, WECHAT_MP.type, WECHAT_OPEN.type,
  57 + WECHAT_MINI_PROGRAM.type);
29 58  
30 59 /**
31 60 * 类型
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/social/SysSocialService.java renamed to yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/social/SysSocialService.java
1   -package cn.iocoder.yudao.adminserver.modules.system.service.social;
  1 +package cn.iocoder.yudao.coreservice.modules.system.service.social;
2 2  
3 3 import cn.hutool.core.util.StrUtil;
4   -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.social.SysSocialUserDO;
5   -import cn.iocoder.yudao.adminserver.modules.system.enums.social.SysSocialTypeEnum;
  4 +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social.SysSocialUserDO;
  5 +import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
  6 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
6 7 import cn.iocoder.yudao.framework.common.exception.ServiceException;
7 8 import me.zhyd.oauth.model.AuthUser;
8 9  
... ... @@ -14,6 +15,7 @@ import java.util.List;
14 15 *
15 16 * @author 芋道源码
16 17 */
  18 +// TODO @timfruit:SysSocialCoreService 改名,方便区分
17 19 public interface SysSocialService {
18 20  
19 21 /**
... ... @@ -49,7 +51,7 @@ public interface SysSocialService {
49 51 * @param unionId 社交平台的 unionId
50 52 * @return 社交用户列表
51 53 */
52   - List<SysSocialUserDO> getAllSocialUserList(Integer type, String unionId);
  54 + List<SysSocialUserDO> getAllSocialUserList(Integer type, String unionId, UserTypeEnum userTypeEnum);
53 55  
54 56 /**
55 57 * 获得指定用户的社交用户列表
... ... @@ -57,7 +59,7 @@ public interface SysSocialService {
57 59 * @param userId 用户编号
58 60 * @return 社交用户列表
59 61 */
60   - List<SysSocialUserDO> getSocialUserList(Long userId);
  62 + List<SysSocialUserDO> getSocialUserList(Long userId, UserTypeEnum userTypeEnum);
61 63  
62 64 /**
63 65 * 绑定社交用户
... ... @@ -66,7 +68,7 @@ public interface SysSocialService {
66 68 * @param type 社交平台的类型 {@link SysSocialTypeEnum}
67 69 * @param authUser 授权用户
68 70 */
69   - void bindSocialUser(Long userId, Integer type, AuthUser authUser);
  71 + void bindSocialUser(Long userId, Integer type, AuthUser authUser, UserTypeEnum userTypeEnum);
70 72  
71 73 /**
72 74 * 取消绑定社交用户
... ... @@ -75,6 +77,7 @@ public interface SysSocialService {
75 77 * @param type 社交平台的类型 {@link SysSocialTypeEnum}
76 78 * @param unionId 社交平台的 unionId
77 79 */
78   - void unbindSocialUser(Long userId, Integer type, String unionId);
  80 + void unbindSocialUser(Long userId, Integer type, String unionId,UserTypeEnum userTypeEnum);
  81 + // TODO @timfruit:逗号后面要有空格;缺少了 @userTypeEnum 的注释,都补充下哈。
79 82  
80 83 }
... ...
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/social/impl/SysSocialServiceImpl.java renamed to yudao-core-service/src/main/java/cn/iocoder/yudao/coreservice/modules/system/service/social/impl/SysSocialServiceImpl.java
1   -package cn.iocoder.yudao.adminserver.modules.system.service.social.impl;
  1 +package cn.iocoder.yudao.coreservice.modules.system.service.social.impl;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4   -import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.social.SysSocialUserDO;
5   -import cn.iocoder.yudao.adminserver.modules.system.dal.mysql.social.SysSocialUserMapper;
6   -import cn.iocoder.yudao.adminserver.modules.system.dal.redis.social.SysSocialAuthUserRedisDAO;
7   -import cn.iocoder.yudao.adminserver.modules.system.enums.social.SysSocialTypeEnum;
8   -import cn.iocoder.yudao.adminserver.modules.system.service.social.SysSocialService;
  4 +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social.SysSocialUserDO;
  5 +import cn.iocoder.yudao.coreservice.modules.system.dal.mysql.social.SysSocialUserMapper;
  6 +import cn.iocoder.yudao.coreservice.modules.system.dal.redis.social.SysSocialAuthUserRedisDAO;
  7 +import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
  8 +import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialService;
9 9 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
10 10 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
11 11 import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
... ... @@ -25,8 +25,8 @@ import javax.annotation.Resource;
25 25 import java.util.List;
26 26 import java.util.Objects;
27 27  
28   -import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.SOCIAL_AUTH_FAILURE;
29   -import static cn.iocoder.yudao.adminserver.modules.system.enums.SysErrorCodeConstants.SOCIAL_UNBIND_NOT_SELF;
  28 +import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.SOCIAL_AUTH_FAILURE;
  29 +import static cn.iocoder.yudao.coreservice.modules.system.enums.SysErrorCodeConstants.SOCIAL_UNBIND_NOT_SELF;
30 30 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
31 31 import static cn.iocoder.yudao.framework.common.util.json.JsonUtils.toJsonString;
32 32  
... ... @@ -75,25 +75,25 @@ public class SysSocialServiceImpl implements SysSocialService {
75 75 }
76 76  
77 77 @Override
78   - public List<SysSocialUserDO> getAllSocialUserList(Integer type, String unionId) {
  78 + public List<SysSocialUserDO> getAllSocialUserList(Integer type, String unionId,UserTypeEnum userTypeEnum) {
79 79 List<Integer> types = SysSocialTypeEnum.getRelationTypes(type);
80   - return socialUserMapper.selectListByTypeAndUnionId(UserTypeEnum.ADMIN.getValue(), types, unionId);
  80 + return socialUserMapper.selectListByTypeAndUnionId(userTypeEnum.getValue(), types, unionId);
81 81 }
82 82  
83 83 @Override
84   - public List<SysSocialUserDO> getSocialUserList(Long userId) {
85   - return socialUserMapper.selectListByUserId(UserTypeEnum.ADMIN.getValue(), userId);
  84 + public List<SysSocialUserDO> getSocialUserList(Long userId,UserTypeEnum userTypeEnum) {
  85 + return socialUserMapper.selectListByUserId(userTypeEnum.getValue(), userId);
86 86 }
87 87  
88 88 @Override
89 89 @Transactional
90   - public void bindSocialUser(Long userId, Integer type, AuthUser authUser) {
  90 + public void bindSocialUser(Long userId, Integer type, AuthUser authUser, UserTypeEnum userTypeEnum) {
91 91 // 获得 unionId 对应的 SysSocialUserDO 列表
92 92 String unionId = getAuthUserUnionId(authUser);
93   - List<SysSocialUserDO> socialUsers = this.getAllSocialUserList(type, unionId);
  93 + List<SysSocialUserDO> socialUsers = this.getAllSocialUserList(type, unionId, userTypeEnum);
94 94  
95 95 // 逻辑一:如果 userId 之前绑定过该 type 的其它账号,需要进行解绑
96   - this.unbindOldSocialUser(userId, type, unionId);
  96 + this.unbindOldSocialUser(userId, type, unionId, userTypeEnum);
97 97  
98 98 // 逻辑二:如果 socialUsers 指定的 userId 改变,需要进行更新
99 99 // 例如说,一个微信 unionId 对应了多个社交账号,结果其中有个关联了新的 userId,则其它也要跟着修改
... ... @@ -112,7 +112,7 @@ public class SysSocialServiceImpl implements SysSocialService {
112 112 .nickname(authUser.getNickname()).avatar(authUser.getAvatar()).rawUserInfo(toJsonString(authUser.getRawUserInfo()))
113 113 .build();
114 114 if (socialUser == null) {
115   - saveSocialUser.setUserId(userId).setUserType(UserTypeEnum.ADMIN.getValue())
  115 + saveSocialUser.setUserId(userId).setUserType(userTypeEnum.getValue())
116 116 .setType(type).setOpenid(authUser.getUuid()).setUnionId(unionId);
117 117 socialUserMapper.insert(saveSocialUser);
118 118 } else {
... ... @@ -122,9 +122,9 @@ public class SysSocialServiceImpl implements SysSocialService {
122 122 }
123 123  
124 124 @Override
125   - public void unbindSocialUser(Long userId, Integer type, String unionId) {
  125 + public void unbindSocialUser(Long userId, Integer type, String unionId, UserTypeEnum userTypeEnum) {
126 126 // 获得 unionId 对应的所有 SysSocialUserDO 社交用户
127   - List<SysSocialUserDO> socialUsers = this.getAllSocialUserList(type, unionId);
  127 + List<SysSocialUserDO> socialUsers = this.getAllSocialUserList(type, unionId, userTypeEnum);
128 128 if (CollUtil.isEmpty(socialUsers)) {
129 129 return;
130 130 }
... ... @@ -140,10 +140,10 @@ public class SysSocialServiceImpl implements SysSocialService {
140 140 }
141 141  
142 142 @VisibleForTesting
143   - public void unbindOldSocialUser(Long userId, Integer type, String newUnionId) {
  143 + public void unbindOldSocialUser(Long userId, Integer type, String newUnionId, UserTypeEnum userTypeEnum) {
144 144 List<Integer> types = SysSocialTypeEnum.getRelationTypes(type);
145 145 List<SysSocialUserDO> oldSocialUsers = socialUserMapper.selectListByTypeAndUserId(
146   - UserTypeEnum.ADMIN.getValue(), types, userId);
  146 + userTypeEnum.getValue(), types, userId);
147 147 // 如果新老的 unionId 是一致的,说明无需解绑
148 148 if (CollUtil.isEmpty(oldSocialUsers) || Objects.equals(newUnionId, oldSocialUsers.get(0).getUnionId())) {
149 149 return;
... ...
yudao-dependencies/pom.xml
... ... @@ -410,7 +410,6 @@
410 410 <artifactId>yunpian-java-sdk</artifactId>
411 411 <version>${yunpian-java-sdk.version}</version>
412 412 </dependency>
413   -
414 413 <dependency>
415 414 <groupId>com.aliyun</groupId>
416 415 <artifactId>aliyun-java-sdk-core</artifactId>
... ... @@ -435,7 +434,7 @@
435 434  
436 435 <dependency>
437 436 <groupId>com.xkcoding.justauth</groupId>
438   - <artifactId>justauth-spring-boot-starter</artifactId>
  437 + <artifactId>justauth-spring-boot-starter</artifactId> <!-- 社交登陆(例如说,个人微信、企业微信等等) -->
439 438 <version>${justauth.version}</version>
440 439 </dependency>
441 440  
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/member/enums/social/SysSocialTypeEnum.java deleted
1   -package cn.iocoder.yudao.userserver.modules.member.enums.social;
2   -
3   -import cn.hutool.core.collection.ListUtil;
4   -import cn.hutool.core.util.ArrayUtil;
5   -import cn.iocoder.yudao.framework.common.core.IntArrayValuable;
6   -import lombok.AllArgsConstructor;
7   -import lombok.Getter;
8   -
9   -import java.util.Arrays;
10   -import java.util.List;
11   -
12   -/**
13   - * 社交平台的类型枚举
14   - *
15   - * @author 芋道源码
16   - */
17   -@Getter
18   -@AllArgsConstructor
19   -public enum SysSocialTypeEnum implements IntArrayValuable {
20   -
21   - GITEE(10, "GITEE"), // https://gitee.com/api/v5/oauth_doc#/
22   - DINGTALK(20, "DINGTALK"), // https://developers.dingtalk.com/document/app/obtain-identity-credentials
23   - WECHAT_ENTERPRISE(30, "WECHAT_ENTERPRISE"), // https://xkcoding.com/2019/08/06/use-justauth-integration-wechat-enterprise.html
24   - ;
25   -
26   - public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SysSocialTypeEnum::getType).toArray();
27   -
28   - public static final List<Integer> WECHAT_ALL = ListUtil.toList(WECHAT_ENTERPRISE.type);
29   -
30   - /**
31   - * 类型
32   - */
33   - private final Integer type;
34   - /**
35   - * 类型的标识
36   - */
37   - private final String source;
38   -
39   - @Override
40   - public int[] array() {
41   - return ARRAYS;
42   - }
43   -
44   - public static SysSocialTypeEnum valueOfType(Integer type) {
45   - return ArrayUtil.firstMatch(o -> o.getType().equals(type), values());
46   - }
47   -
48   - public static List<Integer> getRelationTypes(Integer type) {
49   - if (WECHAT_ALL.contains(type)) {
50   - return WECHAT_ALL;
51   - }
52   - return ListUtil.toList(type);
53   - }
54   -
55   -}
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/SysAuthController.java
1 1 package cn.iocoder.yudao.userserver.modules.system.controller.auth;
2 2  
  3 +import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialService;
  4 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
3 5 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 6 import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.*;
5 7 import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService;
6 8 import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
  9 +import com.alibaba.fastjson.JSON;
7 10 import io.swagger.annotations.Api;
8 11 import io.swagger.annotations.ApiImplicitParam;
9 12 import io.swagger.annotations.ApiImplicitParams;
... ... @@ -13,11 +16,13 @@ import org.springframework.validation.annotation.Validated;
13 16 import org.springframework.web.bind.annotation.*;
14 17  
15 18 import javax.annotation.Resource;
  19 +import javax.servlet.http.HttpServletRequest;
16 20 import javax.validation.Valid;
17 21  
18 22 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
19 23 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
20 24 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getUserAgent;
  25 +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
21 26  
22 27 @Api(tags = "认证")
23 28 @RestController
... ... @@ -30,6 +35,9 @@ public class SysAuthController {
30 35 private SysAuthService authService;
31 36 @Resource
32 37 private SysSmsCodeService smsCodeService;
  38 + @Resource
  39 + private SysSocialService socialService;
  40 +
33 41  
34 42 @PostMapping("/login")
35 43 @ApiOperation("使用手机 + 密码登录")
... ... @@ -70,42 +78,51 @@ public class SysAuthController {
70 78 })
71 79 public CommonResult<String> socialAuthRedirect(@RequestParam("type") Integer type,
72 80 @RequestParam("redirectUri") String redirectUri) {
73   -// return CommonResult.success(socialService.getAuthorizeUrl(type, redirectUri));
74   - return null;
  81 + return CommonResult.success(socialService.getAuthorizeUrl(type, redirectUri));
  82 + }
  83 +
  84 + // TODO @timfruit:这个接口,是要删除的么?
  85 + @GetMapping("/social-login-get")
  86 + @ApiOperation("微信公众号授权回调地址,输出social-login2的必要参数用于测试,使用 code 授权码")
  87 + @ResponseBody
  88 + @Deprecated
  89 + public CommonResult<MbrAuthSocialLoginReqVO> socialLoginGet(HttpServletRequest request,String code,String state) {
  90 + // 返回结果
  91 + MbrAuthSocialLoginReqVO reqVO = MbrAuthSocialLoginReqVO.builder().state(state).code(code).build();
  92 + reqVO.setType(12);
  93 + //输出social-login2的必要参数用于测试
  94 + System.out.println(JSON.toJSON(reqVO));
  95 + return success(reqVO);
75 96 }
76 97  
77 98 @PostMapping("/social-login")
78 99 @ApiOperation("社交登录,使用 code 授权码")
79   - public CommonResult<SysAuthLoginRespVO> socialLogin(@RequestBody @Valid MbrAuthSocialLoginReqVO reqVO) {
80   -// String token = authService.socialLogin(reqVO, getClientIP(), getUserAgent());
81   -// // 返回结果
82   -// return success(MbrAuthLoginRespVO.builder().token(token).build());
83   - return null;
  100 + public CommonResult<SysAuthLoginRespVO> socialLogin(@RequestBody @Valid MbrAuthSocialLoginReqVO reqVO) {
  101 + String token = authService.socialLogin(reqVO, getClientIP(), getUserAgent());
  102 + return success(SysAuthLoginRespVO.builder().token(token).build());
84 103 }
85 104  
  105 + // TODO @timfruit:社交登陆时,使用手机验证码来验证哈。这块我当时没设计好,改改,嘿嘿。
  106 +
86 107 @PostMapping("/social-login2")
87 108 @ApiOperation("社交登录,使用 code 授权码 + 账号密码")
88 109 public CommonResult<SysAuthLoginRespVO> socialLogin2(@RequestBody @Valid MbrAuthSocialLogin2ReqVO reqVO) {
89   -// String token = authService.socialLogin2(reqVO, getClientIP(), getUserAgent());
90   -// // 返回结果
91   -// return success(MbrAuthLoginRespVO.builder().token(token).build());
92   - return null;
  110 + String token = authService.socialLogin2(reqVO, getClientIP(), getUserAgent());
  111 + return success(SysAuthLoginRespVO.builder().token(token).build());
93 112 }
94 113  
95 114 @PostMapping("/social-bind")
96 115 @ApiOperation("社交绑定,使用 code 授权码")
97 116 public CommonResult<Boolean> socialBind(@RequestBody @Valid MbrAuthSocialBindReqVO reqVO) {
98   -// authService.socialBind(getLoginUserId(), reqVO);
99   -// return CommonResult.success(true);
100   - return null;
  117 + authService.socialBind(getLoginUserId(), reqVO);
  118 + return CommonResult.success(true);
101 119 }
102 120  
103 121 @DeleteMapping("/social-unbind")
104 122 @ApiOperation("取消社交绑定")
105 123 public CommonResult<Boolean> socialUnbind(@RequestBody MbrAuthSocialUnbindReqVO reqVO) {
106   -// socialService.unbindSocialUser(getLoginUserId(), reqVO.getType(), reqVO.getUnionId());
107   -// return CommonResult.success(true);
108   - return null;
  124 + socialService.unbindSocialUser(getLoginUserId(), reqVO.getType(), reqVO.getUnionId(), UserTypeEnum.MEMBER);
  125 + return CommonResult.success(true);
109 126 }
110 127  
111 128 }
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/MbrAuthSocialBindReqVO.java
1 1 package cn.iocoder.yudao.userserver.modules.system.controller.auth.vo;
2 2  
  3 +import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
3 4 import cn.iocoder.yudao.framework.common.validation.InEnum;
4   -import cn.iocoder.yudao.userserver.modules.member.enums.social.SysSocialTypeEnum;
5 5 import io.swagger.annotations.ApiModel;
6 6 import io.swagger.annotations.ApiModelProperty;
7 7 import lombok.AllArgsConstructor;
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/MbrAuthSocialLogin2ReqVO.java
1 1 package cn.iocoder.yudao.userserver.modules.system.controller.auth.vo;
2 2  
  3 +import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
3 4 import cn.iocoder.yudao.framework.common.validation.InEnum;
4   -import cn.iocoder.yudao.userserver.modules.member.enums.social.SysSocialTypeEnum;
5 5 import io.swagger.annotations.ApiModel;
6 6 import io.swagger.annotations.ApiModelProperty;
7 7 import lombok.AllArgsConstructor;
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/MbrAuthSocialLoginReqVO.java
1 1 package cn.iocoder.yudao.userserver.modules.system.controller.auth.vo;
2 2  
  3 +import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
3 4 import cn.iocoder.yudao.framework.common.validation.InEnum;
4   -import cn.iocoder.yudao.userserver.modules.member.enums.social.SysSocialTypeEnum;
5 5 import io.swagger.annotations.ApiModel;
6 6 import io.swagger.annotations.ApiModelProperty;
7 7 import lombok.AllArgsConstructor;
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/controller/auth/vo/MbrAuthSocialUnbindReqVO.java
1 1 package cn.iocoder.yudao.userserver.modules.system.controller.auth.vo;
2 2  
  3 +import cn.iocoder.yudao.coreservice.modules.system.enums.social.SysSocialTypeEnum;
3 4 import cn.iocoder.yudao.framework.common.validation.InEnum;
4   -import cn.iocoder.yudao.userserver.modules.member.enums.social.SysSocialTypeEnum;
5 5 import io.swagger.annotations.ApiModel;
6 6 import io.swagger.annotations.ApiModelProperty;
7 7 import lombok.AllArgsConstructor;
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/enums/SysErrorCodeConstants.java
... ... @@ -14,6 +14,7 @@ public interface SysErrorCodeConstants {
14 14 ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1005000001, "登录失败,账号被禁用");
15 15 ErrorCode AUTH_LOGIN_FAIL_UNKNOWN = new ErrorCode(1005000002, "登录失败"); // 登录失败的兜底,未知原因
16 16 ErrorCode AUTH_TOKEN_EXPIRED = new ErrorCode(1005000003, "Token 已经过期");
  17 + ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1005000004, "未绑定账号,需要进行绑定");
17 18  
18 19 // ========== SMS CODE 模块 1005001000 ==========
19 20 ErrorCode USER_SMS_CODE_NOT_FOUND = new ErrorCode(1005001000, "验证码不存在");
... ... @@ -22,4 +23,7 @@ public interface SysErrorCodeConstants {
22 23 ErrorCode USER_SMS_CODE_NOT_CORRECT = new ErrorCode(1005001003, "验证码不正确");
23 24 ErrorCode USER_SMS_CODE_EXCEED_SEND_MAXIMUM_QUANTITY_PER_DAY = new ErrorCode(1005001004, "超过每日短信发送数量");
24 25 ErrorCode USER_SMS_CODE_SEND_TOO_FAST = new ErrorCode(1005001005, "短信发送过于频率");
  26 +
  27 + // ========== 用户模块 1005002000 ==========
  28 + ErrorCode USER_NOT_EXISTS = new ErrorCode(1005002001, "用户不存在");
25 29 }
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/auth/SysAuthService.java
1 1 package cn.iocoder.yudao.userserver.modules.system.service.auth;
2 2  
3 3 import cn.iocoder.yudao.framework.security.core.service.SecurityAuthFrameworkService;
4   -import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthLoginReqVO;
5   -import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthSmsLoginReqVO;
  4 +import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.*;
6 5  
7 6 import javax.validation.Valid;
8 7  
... ... @@ -35,4 +34,33 @@ public interface SysAuthService extends SecurityAuthFrameworkService {
35 34 */
36 35 String smsLogin(@Valid SysAuthSmsLoginReqVO reqVO, String userIp, String userAgent);
37 36  
  37 +
  38 + /**
  39 + * 社交登录,使用 code 授权码
  40 + *
  41 + * @param reqVO 登录信息
  42 + * @param userIp 用户 IP
  43 + * @param userAgent 用户 UA
  44 + * @return 身份令牌,使用 JWT 方式
  45 + */
  46 + String socialLogin(@Valid MbrAuthSocialLoginReqVO reqVO, String userIp, String userAgent);
  47 +
  48 + /**
  49 + * 社交登录,使用 code 授权码 + 账号密码
  50 + *
  51 + * @param reqVO 登录信息
  52 + * @param userIp 用户 IP
  53 + * @param userAgent 用户 UA
  54 + * @return 身份令牌,使用 JWT 方式
  55 + */
  56 + String socialLogin2(@Valid MbrAuthSocialLogin2ReqVO reqVO, String userIp, String userAgent);
  57 +
  58 + /**
  59 + * 社交绑定,使用 code 授权码
  60 + *
  61 + * @param userId 用户编号
  62 + * @param reqVO 绑定信息
  63 + */
  64 + void socialBind(Long userId, @Valid MbrAuthSocialBindReqVO reqVO);
  65 +
38 66 }
... ...
yudao-user-server/src/main/java/cn/iocoder/yudao/userserver/modules/system/service/auth/impl/SysAuthServiceImpl.java
1 1 package cn.iocoder.yudao.userserver.modules.system.service.auth.impl;
2 2  
  3 +import cn.hutool.core.collection.CollUtil;
3 4 import cn.hutool.core.lang.Assert;
4 5 import cn.iocoder.yudao.coreservice.modules.member.dal.dataobject.user.MbrUserDO;
  6 +import cn.iocoder.yudao.coreservice.modules.system.dal.dataobject.social.SysSocialUserDO;
5 7 import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginLogTypeEnum;
6 8 import cn.iocoder.yudao.coreservice.modules.system.enums.logger.SysLoginResultEnum;
7 9 import cn.iocoder.yudao.coreservice.modules.system.service.auth.SysUserSessionCoreService;
8 10 import cn.iocoder.yudao.coreservice.modules.system.service.logger.SysLoginLogCoreService;
9 11 import cn.iocoder.yudao.coreservice.modules.system.service.logger.dto.SysLoginLogCreateReqDTO;
  12 +import cn.iocoder.yudao.coreservice.modules.system.service.social.SysSocialService;
10 13 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
11 14 import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
12 15 import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
13 16 import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
14 17 import cn.iocoder.yudao.framework.security.core.LoginUser;
15 18 import cn.iocoder.yudao.userserver.modules.member.service.user.MbrUserService;
16   -import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthLoginReqVO;
17   -import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.SysAuthSmsLoginReqVO;
  19 +import cn.iocoder.yudao.userserver.modules.system.controller.auth.vo.*;
18 20 import cn.iocoder.yudao.userserver.modules.system.convert.auth.SysAuthConvert;
19 21 import cn.iocoder.yudao.userserver.modules.system.enums.sms.SysSmsSceneEnum;
20 22 import cn.iocoder.yudao.userserver.modules.system.service.auth.SysAuthService;
21 23 import cn.iocoder.yudao.userserver.modules.system.service.sms.SysSmsCodeService;
22 24 import lombok.extern.slf4j.Slf4j;
  25 +import me.zhyd.oauth.model.AuthUser;
23 26 import org.springframework.context.annotation.Lazy;
24 27 import org.springframework.security.authentication.AuthenticationManager;
25 28 import org.springframework.security.authentication.BadCredentialsException;
... ... @@ -33,6 +36,7 @@ import org.springframework.stereotype.Service;
33 36 import org.springframework.transaction.annotation.Transactional;
34 37  
35 38 import javax.annotation.Resource;
  39 +import java.util.List;
36 40 import java.util.Objects;
37 41  
38 42 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
... ... @@ -59,6 +63,9 @@ public class SysAuthServiceImpl implements SysAuthService {
59 63 private SysLoginLogCoreService loginLogCoreService;
60 64 @Resource
61 65 private SysUserSessionCoreService userSessionCoreService;
  66 + @Resource
  67 + private SysSocialService socialService;
  68 + private static final UserTypeEnum userTypeEnum = UserTypeEnum.MEMBER;
62 69  
63 70 @Override
64 71 public UserDetails loadUserByUsername(String mobile) throws UsernameNotFoundException {
... ... @@ -99,6 +106,63 @@ public class SysAuthServiceImpl implements SysAuthService {
99 106 return userSessionCoreService.createUserSession(loginUser, userIp, userAgent);
100 107 }
101 108  
  109 + @Override
  110 + public String socialLogin(MbrAuthSocialLoginReqVO reqVO, String userIp, String userAgent) {
  111 + // 使用 code 授权码,进行登录
  112 + AuthUser authUser = socialService.getAuthUser(reqVO.getType(), reqVO.getCode(), reqVO.getState());
  113 + org.springframework.util.Assert.notNull(authUser, "授权用户不为空");
  114 +
  115 + // 如果未绑定 SysSocialUserDO 用户,则无法自动登录,进行报错
  116 + String unionId = socialService.getAuthUserUnionId(authUser);
  117 + List<SysSocialUserDO> socialUsers = socialService.getAllSocialUserList(reqVO.getType(), unionId, userTypeEnum);
  118 + if (CollUtil.isEmpty(socialUsers)) {
  119 + throw exception(AUTH_THIRD_LOGIN_NOT_BIND);
  120 + }
  121 +
  122 + // 自动登录
  123 + MbrUserDO user = userService.getUser(socialUsers.get(0).getUserId());
  124 + if (user == null) {
  125 + throw exception(USER_NOT_EXISTS);
  126 + }
  127 + this.createLoginLog(user.getMobile(), SysLoginLogTypeEnum.LOGIN_SOCIAL, SysLoginResultEnum.SUCCESS);
  128 +
  129 + // 创建 LoginUser 对象
  130 + LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user);
  131 +
  132 + // 绑定社交用户(更新)
  133 + socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, userTypeEnum);
  134 +
  135 + // 缓存登录用户到 Redis 中,返回 sessionId 编号
  136 + return userSessionCoreService.createUserSession(loginUser, userIp, userAgent);
  137 + }
  138 +
  139 + @Override
  140 + public String socialLogin2(MbrAuthSocialLogin2ReqVO reqVO, String userIp, String userAgent) {
  141 + // 使用 code 授权码,进行登录
  142 + AuthUser authUser = socialService.getAuthUser(reqVO.getType(), reqVO.getCode(), reqVO.getState());
  143 + org.springframework.util.Assert.notNull(authUser, "授权用户不为空");
  144 +
  145 + // 使用账号密码,进行登录。
  146 + LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword());
  147 +// loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表
  148 +
  149 + // 绑定社交用户(新增)
  150 + socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, userTypeEnum);
  151 +
  152 + // 缓存登录用户到 Redis 中,返回 sessionId 编号
  153 + return userSessionCoreService.createUserSession(loginUser, userIp, userAgent);
  154 + }
  155 +
  156 + @Override
  157 + public void socialBind(Long userId, MbrAuthSocialBindReqVO reqVO) {
  158 + // 使用 code 授权码,进行登录
  159 + AuthUser authUser = socialService.getAuthUser(reqVO.getType(), reqVO.getCode(), reqVO.getState());
  160 + org.springframework.util.Assert.notNull(authUser, "授权用户不为空");
  161 +
  162 + // 绑定社交用户(新增)
  163 + socialService.bindSocialUser(userId, reqVO.getType(), authUser, userTypeEnum);
  164 + }
  165 +
102 166 private LoginUser login0(String username, String password) {
103 167 final SysLoginLogTypeEnum logTypeEnum = SysLoginLogTypeEnum.LOGIN_USERNAME;
104 168 // 用户验证
... ... @@ -207,7 +271,7 @@ public class SysAuthServiceImpl implements SysAuthService {
207 271 reqDTO.setLogType(SysLoginLogTypeEnum.LOGOUT_SELF.getType());
208 272 reqDTO.setTraceId(TracerUtils.getTraceId());
209 273 reqDTO.setUserId(userId);
210   - reqDTO.setUserType(UserTypeEnum.MEMBER.getValue());
  274 + reqDTO.setUserType(userTypeEnum.getValue());
211 275 reqDTO.setUsername(username);
212 276 reqDTO.setUserAgent(ServletUtils.getUserAgent());
213 277 reqDTO.setUserIp(ServletUtils.getClientIP());
... ...
yudao-user-server/src/main/resources/application-dev.yaml
... ... @@ -141,3 +141,30 @@ yudao:
141 141 pay:
142 142 pay-notify-url: http://niubi.natapp1.cc/api/pay/order/notify
143 143 refund-notify-url: http://niubi.natapp1.cc/api/pay/refund/notify
  144 +
  145 +
  146 +justauth:
  147 + enabled: true
  148 + type: # TODO @timfruit:GITEE、DINGTALK、WECHAT_ENTERPRISE 这个几个,对于用户端是不需要的哈,可以删除噢
  149 + GITEE: # Gitee
  150 + client-id: ee61f0374a4c6c404a8717094caa7a410d76950e45ff60348015830c519ba5c1
  151 + client-secret: 7c044a5671be3b051414db0cf2cec6ad702dd298d2416ba24ceaf608e6fa26f9
  152 + ignore-check-redirect-uri: true
  153 + DINGTALK: # 钉钉
  154 + client-id: dingvrnreaje3yqvzhxg
  155 + client-secret: i8E6iZyDvZj51JIb0tYsYfVQYOks9Cq1lgryEjFRqC79P3iJcrxEwT6Qk2QvLrLI
  156 + ignore-check-redirect-uri: true
  157 + WECHAT_ENTERPRISE: # 企业微信
  158 + client-id: wwd411c69a39ad2e54
  159 + client-secret: 1wTb7hYxnpT2TUbIeHGXGo7T0odav1ic10mLdyyATOw
  160 + agent-id: 1000004
  161 + ignore-check-redirect-uri: true
  162 + WECHAT_MP: # 微信公众平台 - H5 https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index
  163 + client-id: wxa5a05b85ac361f96
  164 + client-secret: 247073c7cebb67f27f0e769195c2a57e
  165 + ignore-check-redirect-uri: true
  166 + cache:
  167 + type: REDIS
  168 + prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE::
  169 + timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟
  170 +
... ...
yudao-user-server/src/main/resources/application-local.yaml
... ... @@ -155,3 +155,28 @@ yudao:
155 155 pay:
156 156 pay-notify-url: http://niubi.natapp1.cc/api/pay/order/notify
157 157 refund-notify-url: http://niubi.natapp1.cc/api/pay/refund/notify
  158 +
  159 +justauth:
  160 + enabled: true
  161 + type:
  162 + WECHAT_MP: # 微信公众平台 - 移动端 H5 https://www.yuque.com/docs/share/a795bef6-ee8a-494a-8dc4-2ef41927743b?#%20%E3%80%8A%E5%BE%AE%E4%BF%A1%E5%85%AC%E4%BC%97%E5%8F%B7%E6%B5%8B%E8%AF%95%E3%80%8B
  163 + client-id: wxa5a05b85ac361f96
  164 + client-secret: 247073c7cebb67f27f0e769195c2a57e
  165 +# client-id: wx5b23ba7a5589ecbb # TODO 芋艿:自己的测试,后续可以删除
  166 +# client-secret: 2a7b3b20c537e52e74afd395eb85f61f
  167 + ignore-check-redirect-uri: true
  168 + extend:
  169 + enum-class: cn.iocoder.yudao.coreservice.modules.system.compent.justauth.AuthExtendSource
  170 + config:
  171 + WECHAT_MINI_PROGRAM: # 微信小程序 https://www.yuque.com/docs/share/88e3d30a-6830-45fc-8c25-dae485aef3aa?#%20%E3%80%8A%E5%B0%8F%E7%A8%8B%E5%BA%8F%E6%8E%88%E6%9D%83%E7%99%BB%E5%BD%95%E3%80%8B
  172 + request-class: cn.iocoder.yudao.coreservice.modules.system.compent.justauth.AuthWeChatMiniProgramRequest
  173 + client-id: wx44d047d87e6284d8
  174 + client-secret: 21c3b7a8a51ee1b8f5cf875848ed4466
  175 +# client-id: wx63c280fe3248a3e7 # TODO 芋艿:自己的测试,后续可以删除
  176 +# client-secret: 6f270509224a7ae1296bbf1c8cb97aed
  177 + ignore-check-redirect-uri: true
  178 + ignore-check-state: true
  179 + cache:
  180 + type: REDIS
  181 + prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE::
  182 + timeout: 24h # 超时时长,目前只对 Redis 缓存生效,默认 3 分钟
... ...
yudao-user-server/src/main/resources/static/social-login.html 0 → 100644
  1 +<!DOCTYPE html>
  2 +<html>
  3 +<head>
  4 + <meta charset="UTF-8">
  5 + <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/>
  6 + <title>社交登陆测试页</title>
  7 + <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
  8 +</head>
  9 +<body>
  10 +<div>点击如下按钮,发起登陆的测试</div>
  11 +<div>
  12 + <button id="wx_pub">微信公众号</button>
  13 +</div>
  14 +</body>
  15 +<script>
  16 + let server = 'http://127.0.0.1:28080';
  17 +
  18 + // 微信公众号
  19 + $( "#wx_pub").on( "click", function() {
  20 + // 获得授权链接
  21 + $.ajax({
  22 + url: server + "/api/social-auth-redirect?type=31&redirectUri=" +
  23 + encodeURIComponent(server + '/api/social-login-get'),
  24 + method: 'GET',
  25 + success: function( result ) {
  26 + if (result.code !== 0) {
  27 + alert('获得授权链接失败,原因:' + result.msg)
  28 + return;
  29 + }
  30 + // 跳转重定向
  31 + document.location.href = result.data;
  32 + }
  33 + })
  34 + });
  35 +</script>
  36 +</html>
... ...
更新日志.md
... ... @@ -15,6 +15,7 @@ TODO
15 15  
16 16 * 支付
17 17 * 用户前台的社交登陆
  18 +* 用户前台的修改手机、修改密码、忘记密码
18 19  
19 20 ## [v1.1.0] 2021.10.25
20 21  
... ...