feat: 微信登录功能开发
This commit is contained in:
@@ -35,5 +35,8 @@ public interface SecurityConstants {
|
||||
*/
|
||||
String JWT_TOKEN_PREFIX = "Bearer ";
|
||||
|
||||
|
||||
/**
|
||||
* 微信登录路径
|
||||
*/
|
||||
String WX_LOGIN_PATH = "/api/v1/auth/wechatLogin";
|
||||
}
|
||||
|
||||
@@ -54,7 +54,11 @@ public class SecurityConfig {
|
||||
http
|
||||
|
||||
.authorizeHttpRequests(requestMatcherRegistry ->
|
||||
requestMatcherRegistry.requestMatchers(SecurityConstants.LOGIN_PATH).permitAll()
|
||||
requestMatcherRegistry
|
||||
.requestMatchers(
|
||||
SecurityConstants.LOGIN_PATH,
|
||||
SecurityConstants.WX_LOGIN_PATH)
|
||||
.permitAll()
|
||||
.anyRequest().authenticated()
|
||||
)
|
||||
.exceptionHandling(httpSecurityExceptionHandlingConfigurer ->
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
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
|
||||
* @date 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;
|
||||
}
|
||||
}
|
||||
@@ -61,4 +61,14 @@ public class AuthController {
|
||||
AuthTokenResponse authTokenResponse = authService.refreshToken(request);
|
||||
return Result.success(authTokenResponse);
|
||||
}
|
||||
|
||||
@Operation(summary = "微信登录")
|
||||
@PostMapping("/wechatLogin")
|
||||
@Log(value = "微信登录", module = LogModuleEnum.LOGIN)
|
||||
public Result<AuthTokenResponse> wechatLogin(
|
||||
@Parameter(description = "微信授权码", example = "code") @RequestParam String code
|
||||
) {
|
||||
AuthTokenResponse loginResult = authService.wechatLogin(code);
|
||||
return Result.success(loginResult);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,4 +40,11 @@ public interface AuthService {
|
||||
* @return 登录结果
|
||||
*/
|
||||
AuthTokenResponse refreshToken(RefreshTokenRequest request);
|
||||
|
||||
/**
|
||||
* 微信登录
|
||||
* @param code 微信登录code
|
||||
* @return 登录结果
|
||||
*/
|
||||
AuthTokenResponse wechatLogin(String code);
|
||||
}
|
||||
|
||||
@@ -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,51 @@ public class AuthServiceImpl implements AuthService {
|
||||
return tokenService.refreshToken(refreshToken);
|
||||
}
|
||||
|
||||
@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("微信用户注册失败");
|
||||
}
|
||||
}
|
||||
user = userService.getUserByOpenId(openId);
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -72,4 +72,9 @@ public class User extends BaseEntity {
|
||||
* 是否删除(0-否 1-是)
|
||||
*/
|
||||
private Integer isDeleted;
|
||||
|
||||
/**
|
||||
* 微信openid
|
||||
*/
|
||||
private String openId;
|
||||
}
|
||||
@@ -56,4 +56,7 @@ public class UserForm {
|
||||
@NotEmpty(message = "用户角色不能为空")
|
||||
private List<Long> roleIds;
|
||||
|
||||
@Schema(description="微信openId")
|
||||
private String openId;
|
||||
|
||||
}
|
||||
|
||||
@@ -158,4 +158,11 @@ public interface UserService extends IService<User> {
|
||||
* @return {@link List<Option<String>>} 用户选项列表
|
||||
*/
|
||||
List<Option<String>> listUserOptions();
|
||||
|
||||
/**
|
||||
* 根据openId获取用户信息
|
||||
* @param openId openId
|
||||
* @return {@link User}
|
||||
*/
|
||||
User getUserByOpenId(String openId);
|
||||
}
|
||||
|
||||
@@ -445,4 +445,14 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据openId获取用户信息
|
||||
* @param openId openId
|
||||
* @return {@link User}
|
||||
*/
|
||||
@Override
|
||||
public User getUserByOpenId(String openId) {
|
||||
return this.getOne(new LambdaQueryWrapper<User>().eq(User::getOpenId, openId));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user