diff --git a/pom.xml b/pom.xml
index da94204c..b9d42191 100644
--- a/pom.xml
+++ b/pom.xml
@@ -54,6 +54,9 @@
4.6.4
2.2.1
+
+
+ 4.5.5.B
@@ -223,6 +226,12 @@
${aliyun.java.sdk.dysmsapi.version}
+
+ com.github.binarywang
+ weixin-java-miniapp
+ ${weixin-java.version}
+
+
diff --git a/sql/mysql5/youlai_boot.sql b/sql/mysql5/youlai_boot.sql
index 25811e4e..841cefb8 100644
--- a/sql/mysql5/youlai_boot.sql
+++ b/sql/mysql5/youlai_boot.sql
@@ -405,6 +405,7 @@ CREATE TABLE `sys_user` (
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
`update_by` bigint NULL DEFAULT NULL COMMENT '修改人ID',
`is_deleted` tinyint(1) NULL DEFAULT 0 COMMENT '逻辑删除标识(0-未删除 1-已删除)',
+ `open_id` char(28) DEFAULT NULL COMMENT '微信 openid',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `login_name`(`username` ASC) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户信息表' ROW_FORMAT = DYNAMIC;
diff --git a/sql/mysql8/youlai_boot.sql b/sql/mysql8/youlai_boot.sql
index 01800cf0..0e334723 100644
--- a/sql/mysql8/youlai_boot.sql
+++ b/sql/mysql8/youlai_boot.sql
@@ -367,6 +367,7 @@
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
`update_by` bigint NULL DEFAULT NULL COMMENT '修改人ID',
`is_deleted` tinyint(1) NULL DEFAULT 0 COMMENT '逻辑删除标识(0-未删除 1-已删除)',
+ `open_id` char(28) DEFAULT NULL COMMENT '微信 openid',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `login_name`(`username` ASC) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '用户信息表' ROW_FORMAT = DYNAMIC;
diff --git a/src/main/java/com/youlai/boot/common/constant/SecurityConstants.java b/src/main/java/com/youlai/boot/common/constant/SecurityConstants.java
index 3a3128b0..5115cce4 100644
--- a/src/main/java/com/youlai/boot/common/constant/SecurityConstants.java
+++ b/src/main/java/com/youlai/boot/common/constant/SecurityConstants.java
@@ -35,5 +35,8 @@ public interface SecurityConstants {
*/
String JWT_TOKEN_PREFIX = "Bearer ";
-
+ /**
+ * 微信登录路径
+ */
+ String WECHAT_LOGIN_PATH = "/api/v1/auth/wechat-login";
}
diff --git a/src/main/java/com/youlai/boot/config/SecurityConfig.java b/src/main/java/com/youlai/boot/config/SecurityConfig.java
index 98f12c3f..e7955cd7 100644
--- a/src/main/java/com/youlai/boot/config/SecurityConfig.java
+++ b/src/main/java/com/youlai/boot/config/SecurityConfig.java
@@ -54,7 +54,11 @@ public class SecurityConfig {
http
.authorizeHttpRequests(requestMatcherRegistry ->
- requestMatcherRegistry.requestMatchers(SecurityConstants.LOGIN_PATH).permitAll()
+ requestMatcherRegistry
+ .requestMatchers(
+ SecurityConstants.LOGIN_PATH,
+ SecurityConstants.WECHAT_LOGIN_PATH)
+ .permitAll()
.anyRequest().authenticated()
)
.exceptionHandling(httpSecurityExceptionHandlingConfigurer ->
diff --git a/src/main/java/com/youlai/boot/config/WechatMiniAppConfig.java b/src/main/java/com/youlai/boot/config/WechatMiniAppConfig.java
new file mode 100644
index 00000000..129186fd
--- /dev/null
+++ b/src/main/java/com/youlai/boot/config/WechatMiniAppConfig.java
@@ -0,0 +1,41 @@
+package com.youlai.boot.config;
+
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
+import cn.binarywang.wx.miniapp.config.WxMaConfig;
+import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 配置微信 appId 和 appSecret
+ *
+ * @author wangtao
+ * @since 2024/11/26 17:28
+ */
+@Setter
+@ConfigurationProperties(prefix = "wechat.miniapp")
+@Configuration
+public class WechatMiniAppConfig {
+
+ private String appId;
+
+ private String appSecret;
+
+ @Bean
+ public WxMaConfig wxMaConfig() {
+ WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
+ config.setAppid(appId);
+ config.setSecret(appSecret);
+ return config;
+ }
+
+ @Bean
+ public WxMaService wxMaService(WxMaConfig wxMaConfig) {
+ WxMaService service = new WxMaServiceImpl();
+ service.setWxMaConfig(wxMaConfig);
+ return service;
+ }
+}
diff --git a/src/main/java/com/youlai/boot/shared/auth/controller/AuthController.java b/src/main/java/com/youlai/boot/shared/auth/controller/AuthController.java
index 6defa625..091806d4 100644
--- a/src/main/java/com/youlai/boot/shared/auth/controller/AuthController.java
+++ b/src/main/java/com/youlai/boot/shared/auth/controller/AuthController.java
@@ -61,4 +61,14 @@ public class AuthController {
AuthTokenResponse authTokenResponse = authService.refreshToken(request);
return Result.success(authTokenResponse);
}
+
+ @Operation(summary = "微信登录")
+ @PostMapping("/wechat-login")
+ @Log(value = "微信登录", module = LogModuleEnum.LOGIN)
+ public Result wechatLogin(
+ @Parameter(description = "微信授权码", example = "code") @RequestParam String code
+ ) {
+ AuthTokenResponse loginResult = authService.wechatLogin(code);
+ return Result.success(loginResult);
+ }
}
diff --git a/src/main/java/com/youlai/boot/shared/auth/service/AuthService.java b/src/main/java/com/youlai/boot/shared/auth/service/AuthService.java
index ca462a54..1a4215a4 100644
--- a/src/main/java/com/youlai/boot/shared/auth/service/AuthService.java
+++ b/src/main/java/com/youlai/boot/shared/auth/service/AuthService.java
@@ -40,4 +40,12 @@ public interface AuthService {
* @return 登录结果
*/
AuthTokenResponse refreshToken(RefreshTokenRequest request);
+
+ /**
+ * 微信小程序登录
+ *
+ * @param code 微信登录code
+ * @return 登录结果
+ */
+ AuthTokenResponse wechatLogin(String code);
}
diff --git a/src/main/java/com/youlai/boot/shared/auth/service/impl/AuthServiceImpl.java b/src/main/java/com/youlai/boot/shared/auth/service/impl/AuthServiceImpl.java
index 5ef814a9..54e7243b 100644
--- a/src/main/java/com/youlai/boot/shared/auth/service/impl/AuthServiceImpl.java
+++ b/src/main/java/com/youlai/boot/shared/auth/service/impl/AuthServiceImpl.java
@@ -1,11 +1,14 @@
package com.youlai.boot.shared.auth.service.impl;
+import cn.binarywang.wx.miniapp.api.WxMaService;
+import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.youlai.boot.common.constant.SecurityConstants;
+import com.youlai.boot.common.constant.SystemConstants;
import com.youlai.boot.common.exception.BusinessException;
import com.youlai.boot.common.result.ResultCode;
import com.youlai.boot.core.security.util.SecurityUtils;
@@ -16,8 +19,12 @@ import com.youlai.boot.shared.auth.model.CaptchaResponse;
import com.youlai.boot.shared.auth.model.AuthTokenResponse;
import com.youlai.boot.config.property.CaptchaProperties;
import com.youlai.boot.shared.auth.service.TokenService;
+import com.youlai.boot.system.model.entity.User;
+import com.youlai.boot.system.model.form.UserForm;
+import com.youlai.boot.system.service.UserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
+import me.chanjar.weixin.common.error.WxErrorException;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -26,6 +33,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import java.awt.*;
+import java.util.Objects;
import java.util.concurrent.TimeUnit;
/**
@@ -45,6 +53,8 @@ public class AuthServiceImpl implements AuthService {
private final Font captchaFont;
private final CaptchaProperties captchaProperties;
private final TokenService tokenService;
+ private final WxMaService wxMaService;
+ private final UserService userService;
/**
* 登录
@@ -148,4 +158,54 @@ public class AuthServiceImpl implements AuthService {
return tokenService.refreshToken(refreshToken);
}
+ /**
+ * 微信小程序登录
+ *
+ * @param code 微信登录code
+ * @return 访问令牌
+ */
+ @Override
+ public AuthTokenResponse wechatLogin(String code) {
+ // 1. 通过code获取微信access_token
+ WxMaJscode2SessionResult sessionInfo = null;
+ try {
+ sessionInfo = wxMaService.getUserService().getSessionInfo(code);
+ } catch (WxErrorException e) {
+ log.error("微信小程序登录失败", e);
+ throw new BusinessException(e);
+ }
+
+ String openId = sessionInfo.getOpenid();
+ if (StrUtil.isBlank(openId)) {
+ throw new BusinessException("微信授权失败");
+ }
+
+ // todo 获取微信用户信息
+// WxMaUserInfo userInfo = wxMaService.getUserService().getUserInfo(sessionInfo.getSessionKey(), sessionInfo.getOpenid());
+
+ // 2. 根据openId查询用户信息,如果不存在则注册新用户
+ User user = userService.getUserByOpenId(openId);
+ if (Objects.isNull(user)) {
+ String name = "微信用户" + IdUtil.simpleUUID();
+ UserForm newUser = new UserForm();
+ newUser.setOpenId(openId);
+ newUser.setNickname(name);
+ newUser.setUsername(name);
+ boolean result = userService.saveUser(newUser);
+ if (!result) {
+ throw new BusinessException("微信用户注册失败");
+ }
+ }
+ UsernamePasswordAuthenticationToken authenticationToken =
+ new UsernamePasswordAuthenticationToken(user.getUsername().toLowerCase().trim(), SystemConstants.DEFAULT_PASSWORD);
+ // 执行用户认证
+ Authentication authentication = authenticationManager.authenticate(authenticationToken);
+ // 认证成功后生成JWT令牌
+ AuthTokenResponse authTokenResponse = tokenService.generateToken(authentication);
+ // 将认证信息存入Security上下文,便于在AOP(如日志记录)中获取当前用户信息
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ // 返回包含JWT令牌的登录结果
+ return authTokenResponse;
+ }
+
}
diff --git a/src/main/java/com/youlai/boot/system/controller/ConfigController.java b/src/main/java/com/youlai/boot/system/controller/ConfigController.java
index 3ba45f80..174c9c3d 100644
--- a/src/main/java/com/youlai/boot/system/controller/ConfigController.java
+++ b/src/main/java/com/youlai/boot/system/controller/ConfigController.java
@@ -57,7 +57,7 @@ public class ConfigController {
}
@Operation(summary = "刷新系统配置缓存")
- @PutMapping(value = "/refresh")
+ @PutMapping("/refresh")
@PreAuthorize("@ss.hasPerm('sys:config:refresh')")
public Result refreshCache() {
return Result.judge(configService.refreshCache());
diff --git a/src/main/java/com/youlai/boot/system/controller/NoticeController.java b/src/main/java/com/youlai/boot/system/controller/NoticeController.java
index 3e415478..7c529ec6 100644
--- a/src/main/java/com/youlai/boot/system/controller/NoticeController.java
+++ b/src/main/java/com/youlai/boot/system/controller/NoticeController.java
@@ -83,8 +83,7 @@ public class NoticeController {
}
@Operation(summary = "发布通知公告")
- @PatchMapping(value = "/{id}/publish")
- @PutMapping(value = "/{id}/publish")
+ @PutMapping("/{id}/publish")
@PreAuthorize("@ss.hasPerm('sys:notice:publish')")
public Result publishNotice(
@Parameter(description = "通知公告ID") @PathVariable Long id
@@ -94,8 +93,7 @@ public class NoticeController {
}
@Operation(summary = "撤回通知公告")
- @PutMapping(value = "/{id}/revoke")
- @PatchMapping(value = "/{id}/revoke")
+ @PutMapping("/{id}/revoke")
@PreAuthorize("@ss.hasPerm('sys:notice:revoke')")
public Result revokeNotice(
@Parameter(description = "通知公告ID") @PathVariable Long id
diff --git a/src/main/java/com/youlai/boot/system/model/entity/User.java b/src/main/java/com/youlai/boot/system/model/entity/User.java
index 62535380..71e74f7f 100644
--- a/src/main/java/com/youlai/boot/system/model/entity/User.java
+++ b/src/main/java/com/youlai/boot/system/model/entity/User.java
@@ -72,4 +72,9 @@ public class User extends BaseEntity {
* 是否删除(0-否 1-是)
*/
private Integer isDeleted;
+
+ /**
+ * 微信openid
+ */
+ private String openId;
}
\ No newline at end of file
diff --git a/src/main/java/com/youlai/boot/system/model/form/UserForm.java b/src/main/java/com/youlai/boot/system/model/form/UserForm.java
index 8b48259a..8d4f8423 100644
--- a/src/main/java/com/youlai/boot/system/model/form/UserForm.java
+++ b/src/main/java/com/youlai/boot/system/model/form/UserForm.java
@@ -56,4 +56,7 @@ public class UserForm {
@NotEmpty(message = "用户角色不能为空")
private List roleIds;
+ @Schema(description="微信openId")
+ private String openId;
+
}
diff --git a/src/main/java/com/youlai/boot/system/service/UserService.java b/src/main/java/com/youlai/boot/system/service/UserService.java
index 612413bf..189d4abb 100644
--- a/src/main/java/com/youlai/boot/system/service/UserService.java
+++ b/src/main/java/com/youlai/boot/system/service/UserService.java
@@ -158,4 +158,12 @@ public interface UserService extends IService {
* @return {@link List