Commit e1c08c4661063c3b46c724a2dd8a0ca5103886df

Authored by YunaiV
1 parent 1b7093f5

新增 member/auth/weixin-mini-app-login 接口,实现小程序的手机登录

Showing 16 changed files with 223 additions and 156 deletions
yudao-framework/yudao-spring-boot-starter-biz-social/src/main/java/cn/iocoder/yudao/framework/social/config/YudaoSocialAutoConfiguration.java
1 1 package cn.iocoder.yudao.framework.social.config;
2 2  
3   -import cn.hutool.core.util.ReflectUtil;
4 3 import cn.iocoder.yudao.framework.social.core.YudaoAuthRequestFactory;
5 4 import com.xkcoding.http.HttpUtil;
6 5 import com.xkcoding.http.support.hutool.HutoolImpl;
... ... @@ -11,6 +10,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
11 10 import org.springframework.boot.context.properties.EnableConfigurationProperties;
12 11 import org.springframework.context.annotation.Bean;
13 12 import org.springframework.context.annotation.Configuration;
  13 +import org.springframework.context.annotation.Primary;
14 14  
15 15 /**
16 16 * 社交自动装配类
... ... @@ -24,6 +24,7 @@ import org.springframework.context.annotation.Configuration;
24 24 public class YudaoSocialAutoConfiguration {
25 25  
26 26 @Bean
  27 + @Primary
27 28 @ConditionalOnProperty(prefix = "justauth", value = "enabled", havingValue = "true", matchIfMissing = true)
28 29 public YudaoAuthRequestFactory yudaoAuthRequestFactory(JustAuthProperties properties, AuthStateCache authStateCache) {
29 30 // 需要修改 HttpUtil 使用的实现,避免类报错
... ...
yudao-framework/yudao-spring-boot-starter-biz-social/src/main/java/cn/iocoder/yudao/framework/social/core/YudaoAuthRequestFactory.java
... ... @@ -3,7 +3,7 @@ package cn.iocoder.yudao.framework.social.core;
3 3 import cn.hutool.core.util.EnumUtil;
4 4 import cn.hutool.core.util.ReflectUtil;
5 5 import cn.iocoder.yudao.framework.social.core.enums.AuthExtendSource;
6   -import cn.iocoder.yudao.framework.social.core.request.AuthWeChatMiniProgramRequest;
  6 +import cn.iocoder.yudao.framework.social.core.request.AuthWeChatMiniAppRequest;
7 7 import com.xkcoding.justauth.AuthRequestFactory;
8 8 import com.xkcoding.justauth.autoconfigure.JustAuthProperties;
9 9 import me.zhyd.oauth.cache.AuthStateCache;
... ... @@ -20,7 +20,6 @@ import java.lang.reflect.Method;
20 20 * @author timfruit
21 21 * @date 2021-10-31
22 22 */
23   -// TODO @timfruit:单测
24 23 public class YudaoAuthRequestFactory extends AuthRequestFactory {
25 24  
26 25 protected JustAuthProperties properties;
... ... @@ -69,15 +68,14 @@ public class YudaoAuthRequestFactory extends AuthRequestFactory {
69 68 if (config == null) {
70 69 return null;
71 70 }
72   - // 配置 http config
73   - ReflectUtil.invoke(this, configureHttpConfigMethod,
74   - authExtendSource.name(), config, properties.getHttpConfig());
  71 + // 反射调用,配置 http config
  72 + ReflectUtil.invoke(this, configureHttpConfigMethod, authExtendSource.name(), config, properties.getHttpConfig());
75 73  
76 74 // 获得拓展的 Request
77 75 // noinspection SwitchStatementWithTooFewBranches
78 76 switch (authExtendSource) {
79   - case WECHAT_MINI_PROGRAM:
80   - return new AuthWeChatMiniProgramRequest(config, authStateCache);
  77 + case WECHAT_MINI_APP:
  78 + return new AuthWeChatMiniAppRequest(config, authStateCache);
81 79 default:
82 80 return null;
83 81 }
... ...
yudao-framework/yudao-spring-boot-starter-biz-social/src/main/java/cn/iocoder/yudao/framework/social/core/enums/AuthExtendSource.java
... ... @@ -14,25 +14,25 @@ public enum AuthExtendSource implements AuthSource {
14 14 /**
15 15 * 微信小程序授权登录
16 16 */
17   - WECHAT_MINI_PROGRAM {
  17 + WECHAT_MINI_APP {
18 18  
19 19 @Override
20 20 public String authorize() {
21   - // https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
22   - throw new UnsupportedOperationException("不支持获取授权url, 请使用小程序内置函数wx.login()登录获取code");
  21 + // 参见 https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html 文档
  22 + throw new UnsupportedOperationException("不支持获取授权 url,请使用小程序内置函数 wx.login() 登录获取 code");
23 23 }
24 24  
25 25 @Override
26 26 public String accessToken() {
27   - // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html
28   - // 获取openid, unionid , session_key
  27 + // 参见 https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html 文档
  28 + // 获取 openid, unionId , session_key 等字段
29 29 return "https://api.weixin.qq.com/sns/jscode2session";
30 30 }
31 31  
32 32 @Override
33 33 public String userInfo() {
34   - //https://developers.weixin.qq.com/miniprogram/dev/api/open-api/user-info/wx.getUserProfile.html
35   - throw new UnsupportedOperationException("不支持获取用户信息url, 请使用小程序内置函数wx.getUserProfile()获取用户信息");
  34 + // 参见 https://developers.weixin.qq.com/miniprogram/dev/api/open-api/user-info/wx.getUserProfile.html 文档
  35 + throw new UnsupportedOperationException("不支持获取用户信息 url,请使用小程序内置函数 wx.getUserProfile() 获取用户信息");
36 36 }
37 37 }
38 38  
... ...
yudao-framework/yudao-spring-boot-starter-biz-social/src/main/java/cn/iocoder/yudao/framework/social/core/model/AuthExtendToken.java deleted
1   -package cn.iocoder.yudao.framework.social.core.model;
2   -
3   -import lombok.*;
4   -import me.zhyd.oauth.model.AuthToken;
5   -
6   -/**
7   - * 授权所需的 token 拓展类
8   - *
9   - * @author timfruit
10   - * @date 2021-10-29
11   - */
12   -@Getter
13   -@Setter
14   -@NoArgsConstructor
15   -@AllArgsConstructor
16   -public class AuthExtendToken extends AuthToken {
17   -
18   - /**
19   - * 微信小程序 - 会话密钥
20   - */
21   - private String miniSessionKey;
22   -
23   -}
yudao-framework/yudao-spring-boot-starter-biz-social/src/main/java/cn/iocoder/yudao/framework/social/core/request/AuthWeChatMiniProgramRequest.java renamed to yudao-framework/yudao-spring-boot-starter-biz-social/src/main/java/cn/iocoder/yudao/framework/social/core/request/AuthWeChatMiniAppRequest.java
1   -package cn.iocoder.yudao.framework.social.core.request;
2   -
3   -import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
4   -import cn.iocoder.yudao.framework.social.core.enums.AuthExtendSource;
5   -import cn.iocoder.yudao.framework.social.core.model.AuthExtendToken;
6   -import com.fasterxml.jackson.annotation.JsonProperty;
7   -import lombok.Data;
8   -import me.zhyd.oauth.cache.AuthStateCache;
9   -import me.zhyd.oauth.config.AuthConfig;
10   -import me.zhyd.oauth.exception.AuthException;
11   -import me.zhyd.oauth.model.AuthCallback;
12   -import me.zhyd.oauth.model.AuthToken;
13   -import me.zhyd.oauth.model.AuthUser;
14   -import me.zhyd.oauth.request.AuthDefaultRequest;
15   -import me.zhyd.oauth.utils.HttpUtils;
16   -import me.zhyd.oauth.utils.UrlBuilder;
17   -
18   -/**
19   - * 微信小程序登陆
20   - *
21   - * @author timfruit
22   - * @date 2021-10-29
23   - */
24   -public class AuthWeChatMiniProgramRequest extends AuthDefaultRequest {
25   -
26   - public AuthWeChatMiniProgramRequest(AuthConfig config) {
27   - super(config, AuthExtendSource.WECHAT_MINI_PROGRAM);
28   - }
29   -
30   - public AuthWeChatMiniProgramRequest(AuthConfig config, AuthStateCache authStateCache) {
31   - super(config, AuthExtendSource.WECHAT_MINI_PROGRAM, authStateCache);
32   - }
33   -
34   - @Override
35   - protected AuthToken getAccessToken(AuthCallback authCallback) {
36   - // https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html
37   - String response = new HttpUtils(config.getHttpConfig()).get(accessTokenUrl(authCallback.getCode()));
38   - CodeSessionResponse accessTokenObject = JsonUtils.parseObject(response, CodeSessionResponse.class);
39   -
40   - this.checkResponse(accessTokenObject);
41   -
42   - AuthExtendToken token = new AuthExtendToken();
43   - token.setMiniSessionKey(accessTokenObject.sessionKey);
44   - token.setOpenId(accessTokenObject.openid);
45   - token.setUnionId(accessTokenObject.unionid);
46   - return token;
47   - }
48   -
49   - @Override
50   - protected AuthUser getUserInfo(AuthToken authToken) {
51   - // https://developers.weixin.qq.com/miniprogram/dev/api/open-api/user-info/wx.getUserProfile.html
52   - // 如果需要用户信息,需要在小程序调用函数后传给后端
53   - return AuthUser.builder()
54   - .uuid(authToken.getOpenId())
55   - //TODO 是使用默认值,还是有小程序获取用户信息 和 code 一起传过来
56   - .nickname("")
57   - .avatar("")
58   - .token(authToken)
59   - .source(source.toString())
60   - .build();
61   - }
62   -
63   - /**
64   - * 检查响应内容是否正确
65   - *
66   - * @param object 请求响应内容
67   - */
68   - private void checkResponse(CodeSessionResponse object) {
69   - if (object.errcode != 0) {
70   - throw new AuthException(object.errcode, object.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   - @Data
91   - private static class CodeSessionResponse {
92   - private int errcode;
93   - private String errmsg;
94   - @JsonProperty("session_key")
95   - private String sessionKey;
96   - private String openid;
97   - private String unionid;
98   - }
99   -
100   -}
  1 +package cn.iocoder.yudao.framework.social.core.request;
  2 +
  3 +import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  4 +import cn.iocoder.yudao.framework.social.core.enums.AuthExtendSource;
  5 +import com.fasterxml.jackson.annotation.JsonProperty;
  6 +import lombok.Data;
  7 +import me.zhyd.oauth.cache.AuthStateCache;
  8 +import me.zhyd.oauth.config.AuthConfig;
  9 +import me.zhyd.oauth.exception.AuthException;
  10 +import me.zhyd.oauth.model.AuthCallback;
  11 +import me.zhyd.oauth.model.AuthToken;
  12 +import me.zhyd.oauth.model.AuthUser;
  13 +import me.zhyd.oauth.request.AuthDefaultRequest;
  14 +import me.zhyd.oauth.utils.HttpUtils;
  15 +import me.zhyd.oauth.utils.UrlBuilder;
  16 +
  17 +/**
  18 + * 微信小程序登陆 Request 请求
  19 + *
  20 + * 由于 JustAuth 定位是面向 Web 为主的三方登录,所以微信小程序只能自己封装
  21 + *
  22 + * @author timfruit
  23 + * @date 2021-10-29
  24 + */
  25 +public class AuthWeChatMiniAppRequest extends AuthDefaultRequest {
  26 +
  27 + public AuthWeChatMiniAppRequest(AuthConfig config, AuthStateCache authStateCache) {
  28 + super(config, AuthExtendSource.WECHAT_MINI_APP, authStateCache);
  29 + }
  30 +
  31 + @Override
  32 + protected AuthToken getAccessToken(AuthCallback authCallback) {
  33 + // 参见 https://developers.weixin.qq.com/miniprogram/dev/api-backend/open-api/login/auth.code2Session.html 文档
  34 + // 使用 code 获取对应的 openId、unionId 等字段
  35 + String response = new HttpUtils(config.getHttpConfig()).get(accessTokenUrl(authCallback.getCode()));
  36 + JSCode2SessionResponse accessTokenObject = JsonUtils.parseObject(response, JSCode2SessionResponse.class);
  37 + assert accessTokenObject != null;
  38 + checkResponse(accessTokenObject);
  39 + // 拼装结果
  40 + return AuthToken.builder()
  41 + .openId(accessTokenObject.getOpenid())
  42 + .unionId(accessTokenObject.getUnionId())
  43 + .build();
  44 + }
  45 +
  46 + @Override
  47 + protected AuthUser getUserInfo(AuthToken authToken) {
  48 + // 参见 https://developers.weixin.qq.com/miniprogram/dev/api/open-api/user-info/wx.getUserProfile.html 文档
  49 + // 如果需要用户信息,需要在小程序调用函数后传给后端
  50 + return AuthUser.builder()
  51 + .username("")
  52 + .nickname("")
  53 + .avatar("")
  54 + .uuid(authToken.getOpenId())
  55 + .token(authToken)
  56 + .source(source.toString())
  57 + .build();
  58 + }
  59 +
  60 + /**
  61 + * 检查响应内容是否正确
  62 + *
  63 + * @param response 请求响应内容
  64 + */
  65 + private void checkResponse(JSCode2SessionResponse response) {
  66 + if (response.getErrorCode() != 0) {
  67 + throw new AuthException(response.getErrorCode(), response.getErrorMsg());
  68 + }
  69 + }
  70 +
  71 + @Override
  72 + protected String accessTokenUrl(String code) {
  73 + return UrlBuilder.fromBaseUrl(source.accessToken())
  74 + .queryParam("appid", config.getClientId())
  75 + .queryParam("secret", config.getClientSecret())
  76 + .queryParam("js_code", code) // 和父类不同,所以需要重写该方法
  77 + .queryParam("grant_type", "authorization_code")
  78 + .build();
  79 + }
  80 +
  81 + @Data
  82 + @SuppressWarnings("SpellCheckingInspection")
  83 + private static class JSCode2SessionResponse {
  84 +
  85 + @JsonProperty("errcode")
  86 + private int errorCode;
  87 + @JsonProperty("errmsg")
  88 + private String errorMsg;
  89 + @JsonProperty("session_key")
  90 + private String sessionKey;
  91 + private String openid;
  92 + @JsonProperty("unionid")
  93 + private String unionId;
  94 +
  95 + }
  96 +
  97 +}
... ...
yudao-framework/yudao-spring-boot-starter-biz-weixin/pom.xml
... ... @@ -33,9 +33,13 @@
33 33 <!-- 三方云服务相关 -->
34 34 <dependency>
35 35 <groupId>com.github.binarywang</groupId>
36   -<!-- <artifactId>weixin-java-mp</artifactId>-->
37 36 <artifactId>wx-java-mp-spring-boot-starter</artifactId>
38   - <version>4.1.9.B</version>
  37 + <version>4.3.4.B</version>
  38 + </dependency>
  39 + <dependency>
  40 + <groupId>com.github.binarywang</groupId>
  41 + <artifactId>wx-java-miniapp-spring-boot-starter</artifactId>
  42 + <version>4.3.4.B</version>
39 43 </dependency>
40 44 <!-- TODO 芋艿:清理 -->
41 45 </dependencies>
... ...
yudao-module-member/yudao-module-member-api/src/main/java/cn/iocoder/yudao/module/member/enums/ErrorCodeConstants.java
... ... @@ -13,12 +13,12 @@ public interface ErrorCodeConstants {
13 13 ErrorCode USER_NOT_EXISTS = new ErrorCode(1004001000, "用户不存在");
14 14 ErrorCode USER_PASSWORD_FAILED = new ErrorCode(1004001001, "密码校验失败");
15 15  
16   -
17 16 // ========== AUTH 模块 1004003000 ==========
18 17 ErrorCode AUTH_LOGIN_BAD_CREDENTIALS = new ErrorCode(1004003000, "登录失败,账号密码不正确");
19 18 ErrorCode AUTH_LOGIN_USER_DISABLED = new ErrorCode(1004003001, "登录失败,账号被禁用");
20 19 ErrorCode AUTH_TOKEN_EXPIRED = new ErrorCode(1004003004, "Token 已经过期");
21 20 ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1004003005, "未绑定账号,需要进行绑定");
  21 + ErrorCode AUTH_WEIXIN_MINI_APP_PHONE_CODE_ERROR = new ErrorCode(1004003006, "获得手机号失败");
22 22  
23 23 // ========== 用户收件地址 1004004000 ==========
24 24 ErrorCode ADDRESS_NOT_EXISTS = new ErrorCode(1004004000, "用户收件地址不存在");
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.http
... ... @@ -28,6 +28,17 @@ tenant-id: {{appTenentId}}
28 28 "code": 9999
29 29 }
30 30  
  31 +### 请求 /weixin-mini-app-login 接口 => 成功
  32 +POST {{appApi}}/member/auth/weixin-mini-app-login
  33 +Content-Type: application/json
  34 +tenant-id: {{appTenentId}}
  35 +
  36 +{
  37 + "phoneCode": "618e6412e0c728f5b8fc7164497463d0158a923c9e7fd86af8bba393b9decbc5",
  38 + "loginCode": "001frTkl21JUf94VGxol2hSlff1frTkR"
  39 +}
  40 +
  41 +
31 42 ### 请求 /logout 接口 => 成功
32 43 POST {{appApi}}/member/auth/logout
33 44 Content-Type: application/json
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/AppAuthController.java
... ... @@ -110,4 +110,10 @@ public class AppAuthController {
110 110 return success(authService.socialLogin(reqVO));
111 111 }
112 112  
  113 + @PostMapping("/weixin-mini-app-login")
  114 + @ApiOperation("微信小程序的一键登录")
  115 + public CommonResult<AppAuthLoginRespVO> weixinMiniAppLogin(@RequestBody @Valid AppAuthWeixinMiniAppLoginReqVO reqVO) {
  116 + return success(authService.weixinMiniAppLogin(reqVO));
  117 + }
  118 +
113 119 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/auth/vo/AppAuthWeixinMiniAppLoginReqVO.java 0 → 100644
  1 +package cn.iocoder.yudao.module.member.controller.app.auth.vo;
  2 +
  3 +import io.swagger.annotations.ApiModel;
  4 +import io.swagger.annotations.ApiModelProperty;
  5 +import lombok.AllArgsConstructor;
  6 +import lombok.Builder;
  7 +import lombok.Data;
  8 +import lombok.NoArgsConstructor;
  9 +
  10 +import javax.validation.constraints.NotEmpty;
  11 +
  12 +@ApiModel("用户 APP - 微信小程序手机登录 Request VO")
  13 +@Data
  14 +@NoArgsConstructor
  15 +@AllArgsConstructor
  16 +@Builder
  17 +public class AppAuthWeixinMiniAppLoginReqVO {
  18 +
  19 + @ApiModelProperty(value = "手机 code", required = true, example = "hello", notes = "小程序通过 wx.getPhoneNumber 方法获得")
  20 + @NotEmpty(message = "手机 code 不能为空")
  21 + private String phoneCode;
  22 +
  23 + @ApiModelProperty(value = "登录 code", required = true, example = "word", notes = "小程序通过 wx.login 方法获得")
  24 + @NotEmpty(message = "登录 code 不能为空")
  25 + private String loginCode;
  26 +
  27 +}
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthService.java
... ... @@ -45,6 +45,14 @@ public interface MemberAuthService {
45 45 AppAuthLoginRespVO socialLogin(@Valid AppAuthSocialLoginReqVO reqVO);
46 46  
47 47 /**
  48 + * 微信小程序的一键登录
  49 + *
  50 + * @param reqVO 登录信息
  51 + * @return 登录结果
  52 + */
  53 + AppAuthLoginRespVO weixinMiniAppLogin(AppAuthWeixinMiniAppLoginReqVO reqVO);
  54 +
  55 + /**
48 56 * 获得社交认证 URL
49 57 *
50 58 * @param type 社交平台类型
... ... @@ -81,4 +89,5 @@ public interface MemberAuthService {
81 89 * @return 登录结果
82 90 */
83 91 AppAuthLoginRespVO refreshToken(String refreshToken);
  92 +
84 93 }
... ...
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java
1 1 package cn.iocoder.yudao.module.member.service.auth;
2 2  
  3 +import cn.binarywang.wx.miniapp.api.WxMaService;
  4 +import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
3 5 import cn.hutool.core.lang.Assert;
4 6 import cn.hutool.core.util.ObjectUtil;
5 7 import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
... ... @@ -23,6 +25,7 @@ import cn.iocoder.yudao.module.system.enums.auth.OAuth2ClientConstants;
23 25 import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
24 26 import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
25 27 import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
  28 +import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
26 29 import com.google.common.annotations.VisibleForTesting;
27 30 import lombok.extern.slf4j.Slf4j;
28 31 import org.springframework.security.crypto.password.PasswordEncoder;
... ... @@ -57,6 +60,9 @@ public class MemberAuthServiceImpl implements MemberAuthService {
57 60 private OAuth2TokenApi oauth2TokenApi;
58 61  
59 62 @Resource
  63 + private WxMaService wxMaService;
  64 +
  65 + @Resource
60 66 private PasswordEncoder passwordEncoder;
61 67 @Resource
62 68 private MemberUserMapper userMapper;
... ... @@ -116,12 +122,34 @@ public class MemberAuthServiceImpl implements MemberAuthService {
116 122 return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL);
117 123 }
118 124  
  125 + @Override
  126 + public AppAuthLoginRespVO weixinMiniAppLogin(AppAuthWeixinMiniAppLoginReqVO reqVO) {
  127 + // 获得对应的手机号信息
  128 + WxMaPhoneNumberInfo phoneNumberInfo;
  129 + try {
  130 + phoneNumberInfo = wxMaService.getUserService().getNewPhoneNoInfo(reqVO.getPhoneCode());
  131 + } catch (Exception exception) {
  132 + throw exception(AUTH_WEIXIN_MINI_APP_PHONE_CODE_ERROR);
  133 + }
  134 + // 获得获得注册用户
  135 + MemberUserDO user = userService.createUserIfAbsent(phoneNumberInfo.getPurePhoneNumber(), getClientIP());
  136 + Assert.notNull(user, "获取用户失败,结果为空");
  137 +
  138 + // 绑定社交用户
  139 + socialUserApi.bindSocialUser(new SocialUserBindReqDTO(user.getId(), getUserType().getValue(),
  140 + SocialTypeEnum.WECHAT_MINI_APP.getType(), reqVO.getLoginCode(), ""));
  141 +
  142 + // 创建 Token 令牌,记录登录日志
  143 + return createTokenAfterLoginSuccess(user, user.getMobile(), LoginLogTypeEnum.LOGIN_SOCIAL);
  144 + }
  145 +
119 146 private AppAuthLoginRespVO createTokenAfterLoginSuccess(MemberUserDO user, String mobile, LoginLogTypeEnum logType) {
120 147 // 插入登陆日志
121 148 createLoginLog(user.getId(), mobile, logType, LoginResultEnum.SUCCESS);
122 149 // 创建 Token 令牌
123 150 OAuth2AccessTokenRespDTO accessTokenRespDTO = oauth2TokenApi.createAccessToken(new OAuth2AccessTokenCreateReqDTO()
124   - .setUserId(user.getId()).setUserType(getUserType().getValue()).setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT));
  151 + .setUserId(user.getId()).setUserType(getUserType().getValue())
  152 + .setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT));
125 153 // 构建返回结果
126 154 return AuthConvert.INSTANCE.convert(accessTokenRespDTO);
127 155 }
... ...
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/api/social/dto/SocialUserBindReqDTO.java
... ... @@ -46,7 +46,7 @@ public class SocialUserBindReqDTO {
46 46 /**
47 47 * state
48 48 */
49   - @NotEmpty(message = "state 不能为空")
  49 + @NotNull(message = "state 不能为空")
50 50 private String state;
51 51  
52 52 }
... ...
yudao-module-system/yudao-module-system-api/src/main/java/cn/iocoder/yudao/module/system/enums/social/SocialTypeEnum.java
... ... @@ -6,9 +6,6 @@ import lombok.AllArgsConstructor;
6 6 import lombok.Getter;
7 7  
8 8 import java.util.Arrays;
9   -import java.util.Collection;
10   -import java.util.Set;
11   -import java.util.stream.Collectors;
12 9  
13 10 /**
14 11 * 社交平台的类型枚举
... ... @@ -49,7 +46,7 @@ public enum SocialTypeEnum implements IntArrayValuable {
49 46 * 微信小程序
50 47 * 文档链接:https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/login.html
51 48 */
52   - WECHAT_MINI_PROGRAM(33, "WECHAT_MINI_PROGRAM"),
  49 + WECHAT_MINI_APP(34, "WECHAT_MINI_APP"),
53 50 ;
54 51  
55 52 public static final int[] ARRAYS = Arrays.stream(values()).mapToInt(SocialTypeEnum::getType).toArray();
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/social/SocialUserServiceImpl.java
... ... @@ -3,13 +3,13 @@ package cn.iocoder.yudao.module.system.service.social;
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.lang.Assert;
5 5 import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
  6 +import cn.iocoder.yudao.framework.social.core.YudaoAuthRequestFactory;
6 7 import cn.iocoder.yudao.module.system.api.social.dto.SocialUserBindReqDTO;
7 8 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserBindDO;
8 9 import cn.iocoder.yudao.module.system.dal.dataobject.social.SocialUserDO;
9 10 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserBindMapper;
10 11 import cn.iocoder.yudao.module.system.dal.mysql.social.SocialUserMapper;
11 12 import cn.iocoder.yudao.module.system.enums.social.SocialTypeEnum;
12   -import com.xkcoding.justauth.AuthRequestFactory;
13 13 import lombok.extern.slf4j.Slf4j;
14 14 import me.zhyd.oauth.model.AuthCallback;
15 15 import me.zhyd.oauth.model.AuthResponse;
... ... @@ -39,8 +39,8 @@ import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
39 39 @Slf4j
40 40 public class SocialUserServiceImpl implements SocialUserService {
41 41  
42   - @Resource
43   - private AuthRequestFactory authRequestFactory;
  42 + @Resource// 由于自定义了 YudaoAuthRequestFactory 无法覆盖默认的 AuthRequestFactory,所以只能注入它
  43 + private YudaoAuthRequestFactory yudaoAuthRequestFactory;
44 44  
45 45 @Resource
46 46 private SocialUserBindMapper socialUserBindMapper;
... ... @@ -50,7 +50,7 @@ public class SocialUserServiceImpl implements SocialUserService {
50 50 @Override
51 51 public String getAuthorizeUrl(Integer type, String redirectUri) {
52 52 // 获得对应的 AuthRequest 实现
53   - AuthRequest authRequest = authRequestFactory.get(SocialTypeEnum.valueOfType(type).getSource());
  53 + AuthRequest authRequest = yudaoAuthRequestFactory.get(SocialTypeEnum.valueOfType(type).getSource());
54 54 // 生成跳转地址
55 55 String authorizeUri = authRequest.authorize(AuthStateUtils.createState());
56 56 return HttpUtils.replaceUrlQuery(authorizeUri, "redirect_uri", redirectUri);
... ... @@ -153,7 +153,7 @@ public class SocialUserServiceImpl implements SocialUserService {
153 153 * @return 授权的用户
154 154 */
155 155 private AuthUser getAuthUser(Integer type, String code, String state) {
156   - AuthRequest authRequest = authRequestFactory.get(SocialTypeEnum.valueOfType(type).getSource());
  156 + AuthRequest authRequest = yudaoAuthRequestFactory.get(SocialTypeEnum.valueOfType(type).getSource());
157 157 AuthCallback authCallback = AuthCallback.builder().code(code).state(state).build();
158 158 AuthResponse<?> authResponse = authRequest.login(authCallback);
159 159 log.info("[getAuthUser][请求社交平台 type({}) request({}) response({})]", type,
... ...
yudao-server/src/main/resources/application-local.yaml
... ... @@ -173,10 +173,9 @@ logging:
173 173 cn.iocoder.yudao.module.tool.dal.mysql: debug
174 174 cn.iocoder.yudao.module.member.dal.mysql: debug
175 175  
176   ---- #################### 微信公众号相关配置 ####################
177   -wx: # 参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档
178   - mp:
179   - # 公众号配置(必填)
  176 +--- #################### 微信公众号、小程序相关配置 ####################
  177 +wx:
  178 + mp: # 公众号配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-mp-spring-boot-starter/README.md 文档
180 179 app-id: wx041349c6f39b268b
181 180 secret: 5abee519483bc9f8cb37ce280e814bd0
182 181 # 存储配置,解决 AccessToken 的跨节点的共享
... ... @@ -184,6 +183,13 @@ wx: # 参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-sta
184 183 type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取
185 184 key-prefix: wx # Redis Key 的前缀 TODO 芋艿:解决下 Redis key 管理的配置
186 185 http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台
  186 + miniapp: # 小程序配置(必填),参见 https://github.com/Wechat-Group/WxJava/blob/develop/spring-boot-starters/wx-java-miniapp-spring-boot-starter/README.md 文档
  187 + appid: wx63c280fe3248a3e7
  188 + secret: 6f270509224a7ae1296bbf1c8cb97aed
  189 + config-storage:
  190 + type: RedisTemplate # 采用 RedisTemplate 操作 Redis,会自动从 Spring 中获取
  191 + key-prefix: wa # Redis Key 的前缀 TODO 芋艿:解决下 Redis key 管理的配置
  192 + http-client-type: HttpClient # 采用 HttpClient 请求微信公众号平台
187 193  
188 194 --- #################### 芋道相关配置 ####################
189 195  
... ... @@ -218,6 +224,12 @@ justauth:
218 224 client-secret: 1wTb7hYxnpT2TUbIeHGXGo7T0odav1ic10mLdyyATOw
219 225 agent-id: 1000004
220 226 ignore-check-redirect-uri: true
  227 + WECHAT_MINI_APP: # 微信小程序
  228 + client-id: ${wx.miniapp.appid}
  229 + client-secret: ${wx.miniapp.secret}
  230 + ignore-check-redirect-uri: true
  231 + ignore-check-state: true # 微信小程序,不会使用到 state,所以不进行校验
  232 +
221 233 cache:
222 234 type: REDIS
223 235 prefix: 'social_auth_state:' # 缓存前缀,目前只对 Redis 缓存生效,默认 JUSTAUTH::STATE::
... ...