refactor: 优化登录策略

This commit is contained in:
Bunny 2025-02-17 19:43:01 +08:00
parent da7157e0c4
commit 08aeca4834
34 changed files with 252 additions and 82 deletions

View File

@ -25,9 +25,39 @@ public class Knife4jConfig {
return new OpenAPI().info(info).externalDocs(new ExternalDocumentation()); return new OpenAPI().info(info).externalDocs(new ExternalDocumentation());
} }
// 管理员相关分类接口
@Bean @Bean
public GroupedOpenApi groupedOpenAdminApi() { public GroupedOpenApi all() {
return GroupedOpenApi.builder().group("默认请求接口").pathsToMatch("/admin/**").build(); return GroupedOpenApi.builder().group("全部请求接口").pathsToMatch("/api/**").build();
}
@Bean
public GroupedOpenApi i18n() {
return GroupedOpenApi.builder().group("多语言").pathsToMatch("/api/i18n/**", "/api/i18nType/**").build();
}
@Bean
public GroupedOpenApi config() {
return GroupedOpenApi.builder().group("配置")
.pathsToMatch("/api/config/**", "/api/emailTemplate/**", "/api/emailUsers/**",
"/api/message/**", "/api/messageReceived/**", "/api/messageType/**",
"/api/menuIcon/**", "/api/schedulers/**", "/api/schedulersGroup/**"
)
.build();
}
@Bean
public GroupedOpenApi system() {
return GroupedOpenApi.builder().group("系统")
.pathsToMatch("/api/dept/**", "/api/files/**", "/api/power/**",
"/api/rolePower/**", "/api/role/**", "/api/router/**",
"/api/routerRole/**", "/api/user/**", "/api/userRole/**"
).build();
}
@Bean
public GroupedOpenApi log() {
return GroupedOpenApi.builder().group("日志")
.pathsToMatch("/api/userLoginLog/**", "/api/quartzExecuteLog/**"
).build();
} }
} }

View File

@ -11,13 +11,13 @@ import java.io.IOException;
public class ResponseUtil { public class ResponseUtil {
public static void out(HttpServletResponse response, Result<Object> result) { public static void out(HttpServletResponse response, Result<Object> result) {
try {
ObjectMapper mapper = new ObjectMapper(); ObjectMapper mapper = new ObjectMapper();
// 注册JavaTimeModule模块 // 注册JavaTimeModule模块
mapper.registerModule(new JavaTimeModule()); mapper.registerModule(new JavaTimeModule());
response.setContentType("application/json;charset=UTF-8"); response.setContentType("application/json;charset=UTF-8");
response.setStatus(HttpStatus.OK.value()); response.setStatus(HttpStatus.OK.value());
try {
mapper.writeValue(response.getWriter(), result); mapper.writeValue(response.getWriter(), result);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();

View File

@ -37,7 +37,7 @@ public class LoginDto {
@Schema(name = "type", title = "登录类型") @Schema(name = "type", title = "登录类型")
@NotBlank(message = "登录类型不能为空") @NotBlank(message = "登录类型不能为空")
@NotNull(message = "登录类型能为空") @NotNull(message = "登录类型能为空")
private String type; private String type = "default";
@Schema(name = "readMeDay", title = "记住我的天数") @Schema(name = "readMeDay", title = "记住我的天数")
private Long readMeDay = 1L; private Long readMeDay = 1L;

View File

@ -0,0 +1,21 @@
package cn.bunny.dao.enums;
import lombok.Getter;
@Getter
public enum LoginEnums {
// 邮箱登录请求
EMAIL_STRATEGY("email"),
// 默认登录请求
default_STRATEGY("default"),
// 登良路请求API
LOGIN_REQUEST_API("/api/login"),
;
private final String value;
LoginEnums(String value) {
this.value = value;
}
}

View File

@ -24,7 +24,7 @@ public enum ResultCodeEnum {
EMAIL_CODE_NOT_EMPTY(201, "邮箱验证码不能为空"), EMAIL_CODE_NOT_EMPTY(201, "邮箱验证码不能为空"),
SEND_EMAIL_CODE_NOT_EMPTY(201, "请先发送邮箱验证码"), SEND_EMAIL_CODE_NOT_EMPTY(201, "请先发送邮箱验证码"),
EMAIL_CODE_NOT_MATCHING(201, "邮箱验证码不匹配"), EMAIL_CODE_NOT_MATCHING(201, "邮箱验证码不匹配"),
LOGIN_ERROR(201, "账号或密码错误"), LOGIN_ERROR(500, "账号或密码错误"),
LOGIN_ERROR_USERNAME_PASSWORD_NOT_EMPTY(201, "登录信息不能为空"), LOGIN_ERROR_USERNAME_PASSWORD_NOT_EMPTY(201, "登录信息不能为空"),
GET_BUCKET_EXCEPTION(201, "获取文件信息失败"), GET_BUCKET_EXCEPTION(201, "获取文件信息失败"),
SEND_MAIL_CODE_ERROR(201, "邮件发送失败"), SEND_MAIL_CODE_ERROR(201, "邮件发送失败"),

View File

@ -14,7 +14,7 @@ import reactor.core.publisher.Mono;
@Tag(name = "系统配置", description = "系统配置相关接口") @Tag(name = "系统配置", description = "系统配置相关接口")
@RestController @RestController
@RequestMapping("/admin/config") @RequestMapping("/api/config")
public class ConfigurationController { public class ConfigurationController {
@Autowired @Autowired

View File

@ -30,7 +30,7 @@ import java.util.List;
*/ */
@Tag(name = "系统部门", description = "部门相关接口") @Tag(name = "系统部门", description = "部门相关接口")
@RestController @RestController
@RequestMapping("/admin/dept") @RequestMapping("/api/dept")
public class DeptController { public class DeptController {
@Autowired @Autowired

View File

@ -31,7 +31,7 @@ import java.util.Map;
*/ */
@Tag(name = "邮件模板", description = "邮件模板相关接口") @Tag(name = "邮件模板", description = "邮件模板相关接口")
@RestController @RestController
@RequestMapping("admin/emailTemplate") @RequestMapping("api/emailTemplate")
public class EmailTemplateController { public class EmailTemplateController {
@Autowired @Autowired

View File

@ -32,7 +32,7 @@ import java.util.Map;
*/ */
@Tag(name = "邮箱用户发送配置", description = "邮箱用户发送配置相关接口") @Tag(name = "邮箱用户发送配置", description = "邮箱用户发送配置相关接口")
@RestController @RestController
@RequestMapping("admin/emailUsers") @RequestMapping("api/emailUsers")
public class EmailUsersController { public class EmailUsersController {
@Autowired @Autowired

View File

@ -36,7 +36,7 @@ import java.util.Set;
*/ */
@Tag(name = "系统文件表", description = "系统文件相关接口") @Tag(name = "系统文件表", description = "系统文件相关接口")
@RestController @RestController
@RequestMapping("admin/files") @RequestMapping("api/files")
public class FilesController { public class FilesController {
@Autowired @Autowired

View File

@ -31,7 +31,7 @@ import java.util.Map;
*/ */
@Tag(name = "多语言", description = "多语言相关接口") @Tag(name = "多语言", description = "多语言相关接口")
@RestController @RestController
@RequestMapping("admin/i18n") @RequestMapping("api/i18n")
public class I18nController { public class I18nController {
@Autowired @Autowired

View File

@ -26,7 +26,7 @@ import java.util.List;
*/ */
@Tag(name = "多语言类型", description = "多语言类型相关接口") @Tag(name = "多语言类型", description = "多语言类型相关接口")
@RestController @RestController
@RequestMapping("admin/i18nType") @RequestMapping("api/i18nType")
public class I18nTypeController { public class I18nTypeController {
@Autowired @Autowired

View File

@ -30,7 +30,7 @@ import java.util.List;
*/ */
@Tag(name = "系统菜单图标", description = "系统菜单图标相关接口") @Tag(name = "系统菜单图标", description = "系统菜单图标相关接口")
@RestController @RestController
@RequestMapping("admin/menuIcon") @RequestMapping("api/menuIcon")
public class MenuIconController { public class MenuIconController {
@Autowired @Autowired

View File

@ -32,7 +32,7 @@ import java.util.List;
*/ */
@Tag(name = "系统消息", description = "系统消息相关接口") @Tag(name = "系统消息", description = "系统消息相关接口")
@RestController @RestController
@RequestMapping("admin/message") @RequestMapping("api/message")
public class MessageController { public class MessageController {
@Autowired @Autowired

View File

@ -31,7 +31,7 @@ import java.util.List;
*/ */
@Tag(name = "消息接收(用户消息)", description = "消息接收(用户消息)相关接口") @Tag(name = "消息接收(用户消息)", description = "消息接收(用户消息)相关接口")
@RestController @RestController
@RequestMapping("/admin/messageReceived") @RequestMapping("/api/messageReceived")
public class MessageReceivedController { public class MessageReceivedController {
@Autowired @Autowired

View File

@ -30,7 +30,7 @@ import java.util.List;
*/ */
@Tag(name = "系统消息类型", description = "系统消息类型相关接口") @Tag(name = "系统消息类型", description = "系统消息类型相关接口")
@RestController @RestController
@RequestMapping("admin/messageType") @RequestMapping("api/messageType")
public class MessageTypeController { public class MessageTypeController {
@Autowired @Autowired

View File

@ -31,7 +31,7 @@ import java.util.List;
*/ */
@Tag(name = "权限", description = "权限相关接口") @Tag(name = "权限", description = "权限相关接口")
@RestController @RestController
@RequestMapping("admin/power") @RequestMapping("api/power")
public class PowerController { public class PowerController {
@Autowired @Autowired

View File

@ -30,7 +30,7 @@ import java.util.List;
*/ */
@Tag(name = "角色", description = "角色相关接口") @Tag(name = "角色", description = "角色相关接口")
@RestController @RestController
@RequestMapping("admin/role") @RequestMapping("api/role")
public class RoleController { public class RoleController {
@Autowired @Autowired

View File

@ -22,7 +22,7 @@ import java.util.List;
*/ */
@Tag(name = "角色和权限", description = "角色和权限相关接口") @Tag(name = "角色和权限", description = "角色和权限相关接口")
@RestController @RestController
@RequestMapping("admin/rolePower") @RequestMapping("api/rolePower")
public class RolePowerController { public class RolePowerController {
@Autowired @Autowired

View File

@ -32,7 +32,7 @@ import java.util.List;
*/ */
@Tag(name = "系统路由", description = "系统路由相关接口") @Tag(name = "系统路由", description = "系统路由相关接口")
@RestController @RestController
@RequestMapping("admin/router") @RequestMapping("api/router")
public class RouterController { public class RouterController {
@Autowired @Autowired

View File

@ -21,7 +21,7 @@ import java.util.List;
*/ */
@Tag(name = "路由和角色", description = "路由和角色相关接口") @Tag(name = "路由和角色", description = "路由和角色相关接口")
@RestController @RestController
@RequestMapping("admin/routerRole") @RequestMapping("api/routerRole")
public class RouterRoleController { public class RouterRoleController {
@Autowired @Autowired

View File

@ -27,7 +27,7 @@ import java.util.List;
*/ */
@Tag(name = "调度任务执行日志", description = "调度任务执行日志相关接口") @Tag(name = "调度任务执行日志", description = "调度任务执行日志相关接口")
@RestController @RestController
@RequestMapping("admin/quartzExecuteLog") @RequestMapping("api/quartzExecuteLog")
public class ScheduleExecuteLogController { public class ScheduleExecuteLogController {
@Autowired @Autowired

View File

@ -32,7 +32,7 @@ import java.util.Map;
*/ */
@Tag(name = "调度任务", description = "调度任务相关接口") @Tag(name = "调度任务", description = "调度任务相关接口")
@RestController @RestController
@RequestMapping("admin/schedulers") @RequestMapping("api/schedulers")
public class SchedulersController { public class SchedulersController {
@Autowired @Autowired

View File

@ -30,7 +30,7 @@ import java.util.List;
*/ */
@Tag(name = "任务调度分组", description = "任务调度分组相关接口") @Tag(name = "任务调度分组", description = "任务调度分组相关接口")
@RestController @RestController
@RequestMapping("admin/schedulersGroup") @RequestMapping("api/schedulersGroup")
public class SchedulersGroupController { public class SchedulersGroupController {
@Autowired @Autowired

View File

@ -21,7 +21,7 @@ import java.util.List;
@Tag(name = "用户信息", description = "用户信息相关接口") @Tag(name = "用户信息", description = "用户信息相关接口")
@RestController @RestController
@RequestMapping("/admin/user") @RequestMapping("/api/user")
public class UserController { public class UserController {
@Autowired @Autowired

View File

@ -28,7 +28,7 @@ import java.util.List;
*/ */
@Tag(name = "用户登录日志", description = "用户登录日志相关接口") @Tag(name = "用户登录日志", description = "用户登录日志相关接口")
@RestController @RestController
@RequestMapping("admin/userLoginLog") @RequestMapping("api/userLoginLog")
public class UserLoginLogController { public class UserLoginLogController {
@Autowired @Autowired

View File

@ -21,7 +21,7 @@ import java.util.List;
*/ */
@Tag(name = "用户和角色", description = "用户和角色相关接口") @Tag(name = "用户和角色", description = "用户和角色相关接口")
@RestController @RestController
@RequestMapping("admin/userRole") @RequestMapping("api/userRole")
public class UserRoleController { public class UserRoleController {
@Autowired @Autowired

View File

@ -73,7 +73,7 @@ public class WebSecurityConfig {
exception.accessDeniedHandler(new SecurityAccessDeniedHandler()); exception.accessDeniedHandler(new SecurityAccessDeniedHandler());
}) })
// 登录验证过滤器 // 登录验证过滤器
.addFilterBefore(new TokenLoginFilterService(authenticationConfiguration, redisTemplate, customUserDetailsService), UsernamePasswordAuthenticationFilter.class) .addFilterBefore(new TokenLoginFilterService(authenticationConfiguration, customUserDetailsService), UsernamePasswordAuthenticationFilter.class)
// 自定义密码加密器和用户登录 // 自定义密码加密器和用户登录
.passwordManagement(customPasswordEncoder).userDetailsService(customUserDetailsService); .passwordManagement(customPasswordEncoder).userDetailsService(customUserDetailsService);

View File

@ -1,8 +1,8 @@
package cn.bunny.services.security.filter; package cn.bunny.services.security.filter;
import cn.bunny.dao.constant.RedisUserConstant;
import cn.bunny.dao.dto.system.user.LoginDto; import cn.bunny.dao.dto.system.user.LoginDto;
import cn.bunny.dao.enums.LoginEnums;
import cn.bunny.dao.vo.result.Result; import cn.bunny.dao.vo.result.Result;
import cn.bunny.dao.vo.result.ResultCodeEnum; import cn.bunny.dao.vo.result.ResultCodeEnum;
import cn.bunny.dao.vo.system.user.LoginVo; import cn.bunny.dao.vo.system.user.LoginVo;
@ -13,7 +13,6 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.servlet.FilterChain; import jakarta.servlet.FilterChain;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
@ -34,18 +33,15 @@ import static cn.bunny.common.service.utils.ResponseUtil.out;
* 再去设置到 UsernamePasswordAuthenticationToken 来改变请求传参方式参数名等 或者也可以在登录的时候加入其他参数等等 * 再去设置到 UsernamePasswordAuthenticationToken 来改变请求传参方式参数名等 或者也可以在登录的时候加入其他参数等等
*/ */
public class TokenLoginFilterService extends UsernamePasswordAuthenticationFilter { public class TokenLoginFilterService extends UsernamePasswordAuthenticationFilter {
private final RedisTemplate<String, Object> redisTemplate;
private final CustomUserDetailsService customUserDetailsService; private final CustomUserDetailsService customUserDetailsService;
private LoginDto loginDto; private LoginDto loginDto;
public TokenLoginFilterService(AuthenticationConfiguration authenticationConfiguration, RedisTemplate<String, Object> redisTemplate, CustomUserDetailsService customUserDetailsService) throws Exception { public TokenLoginFilterService(AuthenticationConfiguration authenticationConfiguration, CustomUserDetailsService customUserDetailsService) throws Exception {
this.setAuthenticationSuccessHandler(new SecurityAuthenticationSuccessHandler()); this.setAuthenticationSuccessHandler(new SecurityAuthenticationSuccessHandler());
this.setAuthenticationFailureHandler(new SecurityAuthenticationFailureHandler()); this.setAuthenticationFailureHandler(new SecurityAuthenticationFailureHandler());
this.setPostOnly(false); this.setPostOnly(false);
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/login", HttpMethod.POST.name())); this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(LoginEnums.LOGIN_REQUEST_API.getValue(), HttpMethod.POST.name()));
this.setAuthenticationManager(authenticationConfiguration.getAuthenticationManager()); this.setAuthenticationManager(authenticationConfiguration.getAuthenticationManager());
this.redisTemplate = redisTemplate;
this.customUserDetailsService = customUserDetailsService; this.customUserDetailsService = customUserDetailsService;
} }
@ -58,39 +54,8 @@ public class TokenLoginFilterService extends UsernamePasswordAuthenticationFilte
ObjectMapper objectMapper = new ObjectMapper(); ObjectMapper objectMapper = new ObjectMapper();
try { try {
loginDto = objectMapper.readValue(request.getInputStream(), LoginDto.class); loginDto = objectMapper.readValue(request.getInputStream(), LoginDto.class);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword());
// type不能为空 return getAuthenticationManager().authenticate(authentication);
String type = loginDto.getType();
if (!StringUtils.hasText(type)) {
out(response, Result.error(ResultCodeEnum.REQUEST_IS_EMPTY));
return null;
}
String emailCode = loginDto.getEmailCode();
String username = loginDto.getUsername();
String password = loginDto.getPassword();
// 如果有邮箱验证码表示是邮箱登录
if (type.equals("email")) {
emailCode = emailCode.toLowerCase();
Object redisEmailCode = redisTemplate.opsForValue().get(RedisUserConstant.getAdminUserEmailCodePrefix(username));
// --------TODO 线上取消注释这个
// ----测试
// --------线上取消注释这个
// if (redisEmailCode == null) {
// out(response, Result.error(ResultCodeEnum.EMAIL_CODE_EMPTY));
// return null;
// }
//
// // 判断用户邮箱验证码是否和Redis中发送的验证码
// if (!emailCode.equals(redisEmailCode.toString().toLowerCase())) {
// out(response, Result.error(ResultCodeEnum.EMAIL_CODE_NOT_MATCHING));
// return null;
// }
}
Authentication authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
return getAuthenticationManager().authenticate(authenticationToken);
} catch (IOException e) { } catch (IOException e) {
out(response, Result.error(ResultCodeEnum.ILLEGAL_DATA_REQUEST)); out(response, Result.error(ResultCodeEnum.ILLEGAL_DATA_REQUEST));
return null; return null;

View File

@ -3,26 +3,38 @@ package cn.bunny.services.security.service.impl;
import cn.bunny.common.service.exception.AuthCustomerException; import cn.bunny.common.service.exception.AuthCustomerException;
import cn.bunny.dao.dto.system.user.LoginDto; import cn.bunny.dao.dto.system.user.LoginDto;
import cn.bunny.dao.entity.system.AdminUser; import cn.bunny.dao.entity.system.AdminUser;
import cn.bunny.dao.enums.LoginEnums;
import cn.bunny.dao.vo.result.Result; import cn.bunny.dao.vo.result.Result;
import cn.bunny.dao.vo.result.ResultCodeEnum; import cn.bunny.dao.vo.result.ResultCodeEnum;
import cn.bunny.dao.vo.system.user.LoginVo; import cn.bunny.dao.vo.system.user.LoginVo;
import cn.bunny.services.mapper.UserMapper; import cn.bunny.services.mapper.UserMapper;
import cn.bunny.services.security.custom.CustomUser; import cn.bunny.services.security.custom.CustomUser;
import cn.bunny.services.utils.UserUtil; import cn.bunny.services.utils.UserUtil;
import cn.bunny.services.utils.login.DefaultLoginStrategy;
import cn.bunny.services.utils.login.EmailLoginStrategy;
import cn.bunny.services.utils.login.LoginContext;
import cn.bunny.services.utils.login.LoginStrategy;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils; import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import java.util.HashMap;
import static cn.bunny.common.service.utils.ResponseUtil.out; import static cn.bunny.common.service.utils.ResponseUtil.out;
@Component @Component
public class CustomUserDetailsServiceImpl implements cn.bunny.services.security.service.CustomUserDetailsService { public class CustomUserDetailsServiceImpl implements cn.bunny.services.security.service.CustomUserDetailsService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Autowired @Autowired
private UserMapper userMapper; private UserMapper userMapper;
@ -57,18 +69,24 @@ public class CustomUserDetailsServiceImpl implements cn.bunny.services.security.
*/ */
@Override @Override
public LoginVo login(LoginDto loginDto, HttpServletResponse response) { public LoginVo login(LoginDto loginDto, HttpServletResponse response) {
String username = loginDto.getUsername();
String password = loginDto.getPassword(); String password = loginDto.getPassword();
Long readMeDay = loginDto.getReadMeDay(); Long readMeDay = loginDto.getReadMeDay();
// 查询用户相关内容 // type不能为空
LambdaQueryWrapper<AdminUser> queryWrapper = new LambdaQueryWrapper<>(); String type = loginDto.getType();
if (loginDto.getType().equals("email")) { if (!StringUtils.hasText(type)) {
queryWrapper.eq(AdminUser::getEmail, username); out(response, Result.error(ResultCodeEnum.REQUEST_IS_EMPTY));
} else { return null;
queryWrapper.eq(AdminUser::getUsername, username);
} }
AdminUser user = userMapper.selectOne(queryWrapper);
// 初始化登录策略如果有需要添加策略放在这里
HashMap<String, LoginStrategy> loginStrategyHashMap = new HashMap<>();
loginStrategyHashMap.put(LoginEnums.EMAIL_STRATEGY.getValue(), new EmailLoginStrategy(redisTemplate, userMapper));
loginStrategyHashMap.put(LoginEnums.default_STRATEGY.getValue(), new DefaultLoginStrategy(userMapper));
// 使用登录上下文调用登录策略
LoginContext loginContext = new LoginContext(loginStrategyHashMap);
AdminUser user = loginContext.executeStrategy(type, loginDto, response);
// 判断用户是否为空 // 判断用户是否为空
if (user == null) { if (user == null) {

View File

@ -0,0 +1,35 @@
package cn.bunny.services.utils.login;
import cn.bunny.dao.dto.system.user.LoginDto;
import cn.bunny.dao.entity.system.AdminUser;
import cn.bunny.services.mapper.UserMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.servlet.http.HttpServletResponse;
/**
* 使用用户名登录
*/
public class DefaultLoginStrategy implements LoginStrategy {
private final UserMapper userMapper;
public DefaultLoginStrategy(UserMapper userMapper) {
this.userMapper = userMapper;
}
/**
* 登录鉴定方法
*
* @param response 返回的响应
* @param loginDto 登录参数
* @return 鉴定身份验证
*/
@Override
public AdminUser authenticate(HttpServletResponse response, LoginDto loginDto) {
String username = loginDto.getUsername();
String password = loginDto.getPassword();
// 查询用户相关内容
LambdaQueryWrapper<AdminUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(AdminUser::getUsername, username);
return userMapper.selectOne(queryWrapper);
}
}

View File

@ -0,0 +1,55 @@
package cn.bunny.services.utils.login;
import cn.bunny.common.service.utils.ResponseUtil;
import cn.bunny.dao.constant.RedisUserConstant;
import cn.bunny.dao.dto.system.user.LoginDto;
import cn.bunny.dao.entity.system.AdminUser;
import cn.bunny.dao.vo.result.Result;
import cn.bunny.dao.vo.result.ResultCodeEnum;
import cn.bunny.services.mapper.UserMapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.data.redis.core.RedisTemplate;
/**
* 邮箱登录策略
*/
public class EmailLoginStrategy implements LoginStrategy {
private final RedisTemplate<String, Object> redisTemplate;
private final UserMapper userMapper;
public EmailLoginStrategy(RedisTemplate<String, Object> redisTemplate, UserMapper userMapper) {
this.redisTemplate = redisTemplate;
this.userMapper = userMapper;
}
/**
* 登录鉴定方法
*
* @param response 返回的响应
* @param loginDto 登录参数
* @return 鉴定身份验证
*/
@Override
public AdminUser authenticate(HttpServletResponse response, LoginDto loginDto) {
String username = loginDto.getUsername();
String emailCode = loginDto.getEmailCode().toLowerCase();
Object redisEmailCode = redisTemplate.opsForValue().get(RedisUserConstant.getAdminUserEmailCodePrefix(username));
if (redisEmailCode == null) {
ResponseUtil.out(response, Result.error(ResultCodeEnum.EMAIL_CODE_EMPTY));
return null;
}
// 判断用户邮箱验证码是否和Redis中发送的验证码
if (!emailCode.equals(redisEmailCode.toString().toLowerCase())) {
ResponseUtil.out(response, Result.error(ResultCodeEnum.EMAIL_CODE_NOT_MATCHING));
return null;
}
// 查询用户相关内容
LambdaQueryWrapper<AdminUser> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(AdminUser::getEmail, username);
return userMapper.selectOne(queryWrapper);
}
}

View File

@ -0,0 +1,26 @@
package cn.bunny.services.utils.login;
import cn.bunny.dao.dto.system.user.LoginDto;
import cn.bunny.dao.entity.system.AdminUser;
import jakarta.servlet.http.HttpServletResponse;
import java.util.Map;
/**
* 登录策略上下文
*/
public class LoginContext {
private final Map<String, LoginStrategy> strategies;
public LoginContext(Map<String, LoginStrategy> strategies) {
this.strategies = strategies;
}
public AdminUser executeStrategy(String type, LoginDto loginDto, HttpServletResponse response) {
LoginStrategy strategy = strategies.get(type);
if (strategy == null) {
throw new IllegalArgumentException("不支持登录类型: " + type);
}
return strategy.authenticate(response, loginDto);
}
}

View File

@ -0,0 +1,20 @@
package cn.bunny.services.utils.login;
import cn.bunny.dao.dto.system.user.LoginDto;
import cn.bunny.dao.entity.system.AdminUser;
import jakarta.servlet.http.HttpServletResponse;
/**
* 登录策略
*/
public interface LoginStrategy {
/**
* 登录鉴定方法
*
* @param response 返回的响应
* @param loginDto 登录参数
* @return 鉴定身份验证
*/
AdminUser authenticate(HttpServletResponse response, LoginDto loginDto);
}