diff --git a/service/src/main/java/cn/bunny/services/security/config/WebSecurityConfig.java b/service/src/main/java/cn/bunny/services/security/config/WebSecurityConfig.java index 126af86..42f9bcd 100644 --- a/service/src/main/java/cn/bunny/services/security/config/WebSecurityConfig.java +++ b/service/src/main/java/cn/bunny/services/security/config/WebSecurityConfig.java @@ -1,20 +1,25 @@ package cn.bunny.services.security.config; +import cn.bunny.dao.entity.system.AdminUser; +import cn.bunny.dao.vo.result.ResultCodeEnum; +import cn.bunny.services.mapper.UserMapper; +import cn.bunny.services.security.custom.CustomAuthorizationManagerServiceImpl; import cn.bunny.services.security.custom.CustomPasswordEncoder; -import cn.bunny.services.security.custom.service.CustomUserDetailsService; -import cn.bunny.services.security.custom.service.impl.CustomAuthorizationManagerServiceImpl; import cn.bunny.services.security.filter.TokenLoginFilterService; import cn.bunny.services.security.handelr.SecurityAccessDeniedHandler; import cn.bunny.services.security.handelr.SecurityAuthenticationEntryPoint; +import cn.bunny.services.service.UserService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.redis.core.RedisTemplate; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.util.matcher.RegexRequestMatcher; @@ -24,6 +29,7 @@ import org.springframework.security.web.util.matcher.RegexRequestMatcher; @EnableMethodSecurity public class WebSecurityConfig { + // 需要排出的无需验证的请求路径 public static String[] annotations = { "/", "/ws/**", "/*/*/noAuth/**", "/*/noAuth/**", "/noAuth/**", @@ -32,10 +38,7 @@ public class WebSecurityConfig { }; @Autowired - private RedisTemplate redisTemplate; - - @Autowired - private CustomUserDetailsService customUserDetailsService; + private UserService userService; @Autowired private CustomPasswordEncoder customPasswordEncoder; @@ -47,7 +50,7 @@ public class WebSecurityConfig { private AuthenticationConfiguration authenticationConfiguration; @Bean - public SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception { + public SecurityFilterChain filterChain(HttpSecurity httpSecurity, UserMapper userMapper) throws Exception { httpSecurity // 前端段分离不需要---禁用明文验证 .httpBasic(AbstractHttpConfigurer::disable) @@ -73,10 +76,35 @@ public class WebSecurityConfig { exception.accessDeniedHandler(new SecurityAccessDeniedHandler()); }) // 登录验证过滤器 - .addFilterBefore(new TokenLoginFilterService(authenticationConfiguration, customUserDetailsService), UsernamePasswordAuthenticationFilter.class) + .addFilterBefore(new TokenLoginFilterService(authenticationConfiguration, userService), UsernamePasswordAuthenticationFilter.class) // 自定义密码加密器和用户登录 - .passwordManagement(customPasswordEncoder).userDetailsService(customUserDetailsService); + .passwordManagement(customPasswordEncoder); return httpSecurity.build(); } + + + /** + * 使用数据库方式 + * 登录方式:邮箱+用户名 + * + * @param userMapper 获取用户数据 + * @return 数据库的用户 + */ + @Bean + public UserDetailsService userDetailsService(UserMapper userMapper) { + return username -> { + // 查询用户相关内容 + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() + .eq(AdminUser::getEmail, username) + .or() + .eq(AdminUser::getUsername, username); + + // 根据邮箱查询用户名 + AdminUser adminUser = userMapper.selectOne(queryWrapper); + if (adminUser == null) throw new UsernameNotFoundException(ResultCodeEnum.USER_IS_EMPTY.getMessage()); + + return adminUser; + }; + } } diff --git a/service/src/main/java/cn/bunny/services/security/custom/CustomAuthenticationException.java b/service/src/main/java/cn/bunny/services/security/custom/CustomAuthenticationException.java index c4d0033..7a84a68 100644 --- a/service/src/main/java/cn/bunny/services/security/custom/CustomAuthenticationException.java +++ b/service/src/main/java/cn/bunny/services/security/custom/CustomAuthenticationException.java @@ -13,10 +13,11 @@ import org.springframework.security.core.AuthenticationException; @ToString @Slf4j public class CustomAuthenticationException extends AuthenticationException { + String message; ResultCodeEnum resultCodeEnum; - public CustomAuthenticationException(ResultCodeEnum codeEnum) { - super(codeEnum.getMessage()); - this.resultCodeEnum = codeEnum; + public CustomAuthenticationException(String message) { + super(message); + this.message = message; } } diff --git a/service/src/main/java/cn/bunny/services/security/custom/service/impl/CustomAuthorizationManagerServiceImpl.java b/service/src/main/java/cn/bunny/services/security/custom/CustomAuthorizationManagerServiceImpl.java similarity index 89% rename from service/src/main/java/cn/bunny/services/security/custom/service/impl/CustomAuthorizationManagerServiceImpl.java rename to service/src/main/java/cn/bunny/services/security/custom/CustomAuthorizationManagerServiceImpl.java index b46fbe9..f3615c7 100644 --- a/service/src/main/java/cn/bunny/services/security/custom/service/impl/CustomAuthorizationManagerServiceImpl.java +++ b/service/src/main/java/cn/bunny/services/security/custom/CustomAuthorizationManagerServiceImpl.java @@ -1,4 +1,4 @@ -package cn.bunny.services.security.custom.service.impl; +package cn.bunny.services.security.custom; import cn.bunny.common.service.context.BaseContext; import cn.bunny.common.service.utils.JwtHelper; @@ -9,7 +9,6 @@ import cn.bunny.dao.vo.result.ResultCodeEnum; import cn.bunny.dao.vo.system.user.LoginVo; import cn.bunny.services.mapper.PowerMapper; import cn.bunny.services.mapper.RoleMapper; -import cn.bunny.services.security.custom.CustomAuthenticationException; import cn.bunny.services.utils.RoleUtil; import com.alibaba.fastjson2.JSON; import jakarta.servlet.http.HttpServletRequest; @@ -19,6 +18,7 @@ import org.springframework.data.redis.core.RedisTemplate; import org.springframework.security.authorization.AuthorizationDecision; import org.springframework.security.authorization.AuthorizationManager; import org.springframework.security.core.Authentication; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.web.access.intercept.RequestAuthorizationContext; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import org.springframework.stereotype.Component; @@ -54,12 +54,12 @@ public class CustomAuthorizationManagerServiceImpl implements AuthorizationManag // 判断是否有 token String token = request.getHeader("token"); if (token == null) { - throw new CustomAuthenticationException(ResultCodeEnum.LOGIN_AUTH); + throw new UsernameNotFoundException(ResultCodeEnum.LOGIN_AUTH.getMessage()); } // 判断 token 是否过期 if (JwtHelper.isExpired(token)) { - throw new CustomAuthenticationException(ResultCodeEnum.AUTHENTICATION_EXPIRED); + throw new UsernameNotFoundException(ResultCodeEnum.AUTHENTICATION_EXPIRED.getMessage()); } // 解析JWT中的用户名 @@ -72,12 +72,12 @@ public class CustomAuthorizationManagerServiceImpl implements AuthorizationManag // 登录信息为空 if (loginVo == null) { - throw new CustomAuthenticationException(ResultCodeEnum.LOGIN_AUTH); + throw new UsernameNotFoundException(ResultCodeEnum.LOGIN_AUTH.getMessage()); } // 判断用户是否禁用 if (loginVo.getStatus()) { - throw new CustomAuthenticationException(ResultCodeEnum.FAIL_NO_ACCESS_DENIED_USER_LOCKED); + throw new UsernameNotFoundException(ResultCodeEnum.FAIL_NO_ACCESS_DENIED_USER_LOCKED.getMessage()); } // 设置用户信息 diff --git a/service/src/main/java/cn/bunny/services/security/custom/service/CustomUserDetailsService.java b/service/src/main/java/cn/bunny/services/security/custom/service/CustomUserDetailsService.java deleted file mode 100644 index 59a691e..0000000 --- a/service/src/main/java/cn/bunny/services/security/custom/service/CustomUserDetailsService.java +++ /dev/null @@ -1,24 +0,0 @@ -package cn.bunny.services.security.custom.service; - -import cn.bunny.dao.dto.system.user.LoginDto; -import cn.bunny.dao.vo.system.user.LoginVo; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.core.userdetails.UsernameNotFoundException; - -public interface CustomUserDetailsService extends UserDetailsService { - /** - * 根据用户名获取用户对象(获取不到直接抛异常) - */ - @Override - UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; - - /** - * 前台用户登录接口 - * - * @param loginDto 登录参数 - * @return 登录后结果返回 - */ - LoginVo login(LoginDto loginDto, HttpServletResponse response); -} diff --git a/service/src/main/java/cn/bunny/services/security/custom/service/impl/CustomUserDetailsServiceImpl.java b/service/src/main/java/cn/bunny/services/security/custom/service/impl/CustomUserDetailsServiceImpl.java deleted file mode 100644 index 48b294e..0000000 --- a/service/src/main/java/cn/bunny/services/security/custom/service/impl/CustomUserDetailsServiceImpl.java +++ /dev/null @@ -1,103 +0,0 @@ -package cn.bunny.services.security.custom.service.impl; - -import cn.bunny.common.service.exception.AuthCustomerException; -import cn.bunny.dao.dto.system.user.LoginDto; -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.ResultCodeEnum; -import cn.bunny.dao.vo.system.user.LoginVo; -import cn.bunny.services.mapper.UserMapper; -import cn.bunny.services.security.custom.service.CustomUserDetailsService; -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 jakarta.servlet.http.HttpServletResponse; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.redis.core.RedisTemplate; -import org.springframework.security.core.userdetails.UserDetails; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.stereotype.Component; -import org.springframework.util.DigestUtils; -import org.springframework.util.StringUtils; - -import java.util.HashMap; - -import static cn.bunny.common.service.utils.ResponseUtil.out; - -@Component -public class CustomUserDetailsServiceImpl implements CustomUserDetailsService { - - @Autowired - private RedisTemplate redisTemplate; - - @Autowired - private UserMapper userMapper; - - @Autowired - private UserUtil userUtil; - - /** - * 根据用户名获取用户对象(获取不到直接抛异常) - * - * @param username 用户名 - */ - @Override - public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { - // 查询用户相关内容 - LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper() - .eq(AdminUser::getEmail, username) - .or() - .eq(AdminUser::getUsername, username); - - // 根据邮箱查询用户名 - AdminUser adminUser = userMapper.selectOne(queryWrapper); - if (adminUser == null) throw new UsernameNotFoundException(ResultCodeEnum.USER_IS_EMPTY.getMessage()); - - // return new CustomUser(adminUser, AuthorityUtils.createAuthorityList()); - return adminUser; - } - - /** - * 前台用户登录接口 - * - * @param loginDto 登录参数 - * @return 登录后结果返回 - */ - @Override - public LoginVo login(LoginDto loginDto, HttpServletResponse response) { - String password = loginDto.getPassword(); - Long readMeDay = loginDto.getReadMeDay(); - - // type不能为空 - String type = loginDto.getType(); - if (!StringUtils.hasText(type)) { - out(response, Result.error(ResultCodeEnum.REQUEST_IS_EMPTY)); - return null; - } - - // 初始化登录策略,如果有需要添加策略放在这里 - HashMap 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) { - out(response, Result.error(ResultCodeEnum.LOGIN_ERROR)); - return null; - } - - // 对登录密码进行md5加密判断,是否与数据库中一致 - String md5Password = DigestUtils.md5DigestAsHex(password.getBytes()); - if (!user.getPassword().equals(md5Password)) throw new AuthCustomerException(ResultCodeEnum.LOGIN_ERROR); - - return userUtil.buildLoginUserVo(user, readMeDay); - } -} diff --git a/service/src/main/java/cn/bunny/services/security/filter/TokenLoginFilterService.java b/service/src/main/java/cn/bunny/services/security/filter/TokenLoginFilterService.java index 39fc9ab..70f2241 100644 --- a/service/src/main/java/cn/bunny/services/security/filter/TokenLoginFilterService.java +++ b/service/src/main/java/cn/bunny/services/security/filter/TokenLoginFilterService.java @@ -1,14 +1,14 @@ package cn.bunny.services.security.filter; +import cn.bunny.common.service.utils.ResponseUtil; 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.ResultCodeEnum; import cn.bunny.dao.vo.system.user.LoginVo; -import cn.bunny.services.security.custom.service.CustomUserDetailsService; import cn.bunny.services.security.handelr.SecurityAuthenticationFailureHandler; import cn.bunny.services.security.handelr.SecurityAuthenticationSuccessHandler; +import cn.bunny.services.service.UserService; import com.fasterxml.jackson.databind.ObjectMapper; import jakarta.servlet.FilterChain; import jakarta.servlet.http.HttpServletRequest; @@ -18,31 +18,27 @@ import org.springframework.security.authentication.UsernamePasswordAuthenticatio import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; -import org.springframework.util.StringUtils; -import java.io.IOException; - -import static cn.bunny.common.service.utils.ResponseUtil.out; /** - * UsernamePasswordAuthenticationFilter - * 也可以在这里添加验证码、短信等的验证 - * 由于SpringSecurity的登录只能是表单形式 并且用户名密码需要时username、password,可以通过继承 UsernamePasswordAuthenticationFilter 获取登录请求的参数 - * 再去设置到 UsernamePasswordAuthenticationToken 中 来改变请求传参方式、参数名等 或者也可以在登录的时候加入其他参数等等 + * 自定义登录 + * 自定义登录路径和自定义登录返回数据 */ public class TokenLoginFilterService extends UsernamePasswordAuthenticationFilter { - private final CustomUserDetailsService customUserDetailsService; - private LoginDto loginDto; + private final UserService userService; + LoginDto loginDto; - public TokenLoginFilterService(AuthenticationConfiguration authenticationConfiguration, CustomUserDetailsService customUserDetailsService) throws Exception { + public TokenLoginFilterService(AuthenticationConfiguration authenticationConfiguration, UserService customUserDetailsService) throws Exception { this.setAuthenticationSuccessHandler(new SecurityAuthenticationSuccessHandler()); this.setAuthenticationFailureHandler(new SecurityAuthenticationFailureHandler()); this.setPostOnly(false); + // 自定义登录路径,自定义登录请求类型 this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(LoginEnums.LOGIN_REQUEST_API.getValue(), HttpMethod.POST.name())); this.setAuthenticationManager(authenticationConfiguration.getAuthenticationManager()); - this.customUserDetailsService = customUserDetailsService; + this.userService = customUserDetailsService; } /** @@ -56,28 +52,20 @@ public class TokenLoginFilterService extends UsernamePasswordAuthenticationFilte loginDto = objectMapper.readValue(request.getInputStream(), LoginDto.class); UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(loginDto.getUsername(), loginDto.getPassword()); return getAuthenticationManager().authenticate(authentication); - } catch (IOException e) { - out(response, Result.error(ResultCodeEnum.ILLEGAL_DATA_REQUEST)); - return null; + } catch (Exception exception) { + throw new UsernameNotFoundException(exception.getMessage()); } } /** * 验证成功 + * 在这里用户的账号和密码是对的 + * 此时不要再去解析/转换 request.getInputStream() 因为流已经关闭 */ @Override protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication auth) { - // 获取登录返回信息 - LoginVo loginVo = customUserDetailsService.login(loginDto, response); - if (loginVo == null) return; - - // 判断用户是否禁用 - if (loginVo.getStatus()) { - out(response, Result.error(ResultCodeEnum.FAIL_NO_ACCESS_DENIED_USER_LOCKED)); - return; - } - - out(response, Result.success(loginVo)); + LoginVo loginVo = userService.login(loginDto, response); + ResponseUtil.out(response, Result.success(loginVo)); } /** @@ -85,12 +73,6 @@ public class TokenLoginFilterService extends UsernamePasswordAuthenticationFilte */ @Override protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) { - String password = loginDto.getPassword(); - String username = loginDto.getUsername(); - - if (!StringUtils.hasText(password) || !StringUtils.hasText(username)) - out(response, Result.error(ResultCodeEnum.USERNAME_OR_PASSWORD_NOT_EMPTY)); - else - out(response, Result.error(null, ResultCodeEnum.LOGIN_ERROR)); + ResponseUtil.out(response, Result.error(null, failed.getMessage())); } } \ No newline at end of file diff --git a/service/src/main/java/cn/bunny/services/service/UserService.java b/service/src/main/java/cn/bunny/services/service/UserService.java index cf1c3cd..0dacce1 100644 --- a/service/src/main/java/cn/bunny/services/service/UserService.java +++ b/service/src/main/java/cn/bunny/services/service/UserService.java @@ -6,6 +6,7 @@ import cn.bunny.dao.vo.result.PageResult; import cn.bunny.dao.vo.system.user.*; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; +import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import org.jetbrains.annotations.NotNull; @@ -20,6 +21,14 @@ import java.util.List; * @since 2024-09-26 */ public interface UserService extends IService { + + /** + * 前台用户登录接口 + * + * @param loginDto 登录参数 + * @return 登录后结果返回 + */ + LoginVo login(LoginDto loginDto, HttpServletResponse response); /** * * 获取用户信息列表 diff --git a/service/src/main/java/cn/bunny/services/service/impl/UserServiceImpl.java b/service/src/main/java/cn/bunny/services/service/impl/UserServiceImpl.java index 28a56fb..64a2a8f 100644 --- a/service/src/main/java/cn/bunny/services/service/impl/UserServiceImpl.java +++ b/service/src/main/java/cn/bunny/services/service/impl/UserServiceImpl.java @@ -13,6 +13,7 @@ import cn.bunny.dao.entity.system.AdminUser; import cn.bunny.dao.entity.system.Role; import cn.bunny.dao.entity.system.UserDept; import cn.bunny.dao.enums.EmailTemplateEnums; +import cn.bunny.dao.enums.LoginEnums; import cn.bunny.dao.views.ViewUserDept; import cn.bunny.dao.vo.result.PageResult; import cn.bunny.dao.vo.result.ResultCodeEnum; @@ -23,6 +24,10 @@ import cn.bunny.services.service.FilesService; import cn.bunny.services.service.UserService; import cn.bunny.services.utils.UserUtil; import cn.bunny.services.utils.email.ConcreteSenderEmailTemplate; +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 cn.hutool.captcha.CaptchaUtil; import cn.hutool.captcha.CircleCaptcha; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; @@ -30,12 +35,14 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import jakarta.servlet.http.HttpServletResponse; import jakarta.validation.Valid; import lombok.SneakyThrows; import org.jetbrains.annotations.NotNull; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.util.DigestUtils; @@ -84,6 +91,40 @@ public class UserServiceImpl extends ServiceImpl implemen @Autowired private RoleMapper roleMapper; + @Autowired + private UserMapper userMapper; + + /** + * 前台用户登录接口 + * 这里不用判断用户是否为空,因为在登录时已经校验过了 + *

+ * 抛出异常使用自带的 UsernameNotFoundException 或者自己封装
+ * 但是这两个效果传入参数都是一样的,所以全部使用 UsernameNotFoundException + *

+ * + * @param loginDto 登录参数 + * @return 登录后结果返回 + */ + @Override + public LoginVo login(LoginDto loginDto, HttpServletResponse response) { + Long readMeDay = loginDto.getReadMeDay(); + + // 初始化登录策略,如果有需要添加策略放在这里 + HashMap 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(loginDto); + + // 判断用户是否禁用 + if (user.getStatus()) { + throw new UsernameNotFoundException(ResultCodeEnum.FAIL_NO_ACCESS_DENIED_USER_LOCKED.getMessage()); + } + return userUtil.buildLoginUserVo(user, readMeDay); + } + /** * 登录发送邮件验证码 * diff --git a/service/src/main/java/cn/bunny/services/utils/login/DefaultLoginStrategy.java b/service/src/main/java/cn/bunny/services/utils/login/DefaultLoginStrategy.java index 441f8e2..4f216a5 100644 --- a/service/src/main/java/cn/bunny/services/utils/login/DefaultLoginStrategy.java +++ b/service/src/main/java/cn/bunny/services/utils/login/DefaultLoginStrategy.java @@ -4,7 +4,6 @@ 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; /** * 使用用户名登录 @@ -18,15 +17,15 @@ public class DefaultLoginStrategy implements LoginStrategy { /** * 登录鉴定方法 + * 默认登录方式,使用用户名查询用户 * - * @param response 返回的响应 * @param loginDto 登录参数 * @return 鉴定身份验证 */ @Override - public AdminUser authenticate(HttpServletResponse response, LoginDto loginDto) { + public AdminUser authenticate(LoginDto loginDto) { String username = loginDto.getUsername(); - String password = loginDto.getPassword(); + // 查询用户相关内容 LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(AdminUser::getUsername, username); diff --git a/service/src/main/java/cn/bunny/services/utils/login/EmailLoginStrategy.java b/service/src/main/java/cn/bunny/services/utils/login/EmailLoginStrategy.java index 36bec3c..b4d21a5 100644 --- a/service/src/main/java/cn/bunny/services/utils/login/EmailLoginStrategy.java +++ b/service/src/main/java/cn/bunny/services/utils/login/EmailLoginStrategy.java @@ -1,15 +1,13 @@ 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; +import org.springframework.security.core.userdetails.UsernameNotFoundException; /** * 邮箱登录策略 @@ -25,26 +23,29 @@ public class EmailLoginStrategy implements LoginStrategy { /** * 登录鉴定方法 + * 只要判断邮箱验证码是否相等,在前面已经验证过用户密码 + *

+ * 抛出异常类型 UsernameNotFoundException 如果要自定义状态码需要使用 HttpServletResponse + * 有封装好的 ResponseUtil.out() 方法 + *

* - * @param response 返回的响应 * @param loginDto 登录参数 * @return 鉴定身份验证 */ @Override - public AdminUser authenticate(HttpServletResponse response, LoginDto loginDto) { + public AdminUser authenticate(LoginDto loginDto) { String username = loginDto.getUsername(); String emailCode = loginDto.getEmailCode().toLowerCase(); + // 查找Redis中的验证码 Object redisEmailCode = redisTemplate.opsForValue().get(RedisUserConstant.getAdminUserEmailCodePrefix(username)); if (redisEmailCode == null) { - ResponseUtil.out(response, Result.error(ResultCodeEnum.EMAIL_CODE_EMPTY)); - return null; + throw new UsernameNotFoundException(ResultCodeEnum.EMAIL_CODE_EMPTY.getMessage()); } // 判断用户邮箱验证码是否和Redis中发送的验证码 if (!emailCode.equals(redisEmailCode.toString().toLowerCase())) { - ResponseUtil.out(response, Result.error(ResultCodeEnum.EMAIL_CODE_NOT_MATCHING)); - return null; + throw new UsernameNotFoundException(ResultCodeEnum.EMAIL_CODE_NOT_MATCHING.getMessage()); } // 查询用户相关内容 diff --git a/service/src/main/java/cn/bunny/services/utils/login/LoginContext.java b/service/src/main/java/cn/bunny/services/utils/login/LoginContext.java index ab877f8..984ba4e 100644 --- a/service/src/main/java/cn/bunny/services/utils/login/LoginContext.java +++ b/service/src/main/java/cn/bunny/services/utils/login/LoginContext.java @@ -2,7 +2,7 @@ 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 org.springframework.security.core.userdetails.UsernameNotFoundException; import java.util.Map; @@ -16,11 +16,19 @@ public class LoginContext { this.strategies = strategies; } - public AdminUser executeStrategy(String type, LoginDto loginDto, HttpServletResponse response) { + /** + * 执行登录策略 + * 根据情况判断 type 是否为空 + * + * @param loginDto 登录参数 + * @return 用户 + */ + public AdminUser executeStrategy(LoginDto loginDto) { + String type = loginDto.getType(); LoginStrategy strategy = strategies.get(type); if (strategy == null) { - throw new IllegalArgumentException("不支持登录类型: " + type); + throw new UsernameNotFoundException("不支持登录类型: " + type); } - return strategy.authenticate(response, loginDto); + return strategy.authenticate(loginDto); } } \ No newline at end of file diff --git a/service/src/main/java/cn/bunny/services/utils/login/LoginStrategy.java b/service/src/main/java/cn/bunny/services/utils/login/LoginStrategy.java index c5b910b..ae0c932 100644 --- a/service/src/main/java/cn/bunny/services/utils/login/LoginStrategy.java +++ b/service/src/main/java/cn/bunny/services/utils/login/LoginStrategy.java @@ -2,7 +2,6 @@ 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; /** * 登录策略 @@ -12,9 +11,8 @@ public interface LoginStrategy { /** * 登录鉴定方法 * - * @param response 返回的响应 * @param loginDto 登录参数 * @return 鉴定身份验证 */ - AdminUser authenticate(HttpServletResponse response, LoginDto loginDto); + AdminUser authenticate(LoginDto loginDto); } diff --git a/service/src/main/resources/application.yml b/service/src/main/resources/application.yml index 70e60bb..e6ca447 100644 --- a/service/src/main/resources/application.yml +++ b/service/src/main/resources/application.yml @@ -89,7 +89,7 @@ management: web: exposure: include: "*" - base-path: /admin/actuator + base-path: /api/actuator info: env: enabled: true