1. 修改 LoginBody,添加登录类型字段
- @Data
- public class LoginBody {
- /**
- * 用户名
- */
- private String username;
-
- /**
- * 用户密码
- */
- private String password;
-
- /**
- * 验证码
- */
- private String code;
-
- /**
- * 唯一标识
- */
- private String uuid;
-
- /**
- * 登录类型
- */
- private String loginType;
- }
2.定义一个常量
- package com.ruoyi.common.core.domain.constant;
-
- /**
- * @author Ls
- * @date 2024/6/4
- */
- public class LoginTypeConstant {
- public static final String PASSWORD_LOGIN = "password";
- public static final String MOBILE_LOGIN = "mobile";
- public static final String QR_CODE_LOGIN = "qrCode";
- }
3.修改登录接口
- @PostMapping("/login")
- public AjaxResult login(@RequestBody LoginBody loginBody) {
- AjaxResult ajax = AjaxResult.success();
- loginBody.setLoginType(LoginTypeConstant.MOBILE_LOGIN);
- // 生成令牌
- String token = loginService.login(loginBody);
- ajax.put(Constants.TOKEN, token);
- return ajax;
- }
4.重载登录实现类,基本不用改,loginbody 作为 credentials传入UsernamePasswordAuthenticationToken
- public String login(LoginBody loginBody) {
- String username = loginBody.getUsername();
- // // 验证码校验
- // validateCaptcha(username, code, uuid);
- // // 登录前置校验
- // loginPreCheck(username, password);
- // 用户验证
- Authentication authentication = null;
- try {
- UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, loginBody);
- AuthenticationContextHolder.setContext(authenticationToken);
- // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
- authentication = authenticationManager.authenticate(authenticationToken);
- } catch (Exception e) {
- if (e instanceof BadCredentialsException) {
- AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
- throw new UserPasswordNotMatchException();
- } else {
- AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
- throw new ServiceException(e.getMessage());
- }
- } finally {
- AuthenticationContextHolder.clearContext();
- }
- AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
- LoginUser loginUser = (LoginUser) authentication.getPrincipal();
- recordLoginInfo(loginUser.getUserId());
- // 生成token
- return tokenService.createToken(loginUser);
- }
5.自定义MyAuthenticationProvider类
- package com.ruoyi.framework.security.mobile;
-
- import com.ruoyi.common.core.domain.constant.LoginTypeConstant;
- import com.ruoyi.common.core.domain.model.LoginBody;
- import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
- import com.ruoyi.framework.web.service.UserDetailsServiceImpl;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.security.authentication.AuthenticationProvider;
- import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
- import org.springframework.security.core.Authentication;
- import org.springframework.security.core.AuthenticationException;
- import org.springframework.security.core.userdetails.UserDetails;
- import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
- import org.springframework.stereotype.Component;
-
- /**
- * @author Ls
- * @date 2024/6/4
- */
- @Component
- public class MyAuthenticationProvider implements AuthenticationProvider {
- @Autowired
- private UserDetailsServiceImpl userDetailsService;
-
- @Autowired
- private BCryptPasswordEncoder bCryptPasswordEncoder;
-
- @Override
- public Authentication authenticate(Authentication authentication) throws AuthenticationException, UserPasswordNotMatchException {
- String name = authentication.getName();
- LoginBody loginBody = (LoginBody) authentication.getCredentials();
- String loginType = loginBody.getLoginType();
- UserDetails user;
- switch (loginType) {
- case LoginTypeConstant.PASSWORD_LOGIN:
- user = userDetailsService.loadUserByUsername(name);
- String password = loginBody.getPassword();
- String encoderPassword = bCryptPasswordEncoder.encode(password);
- // 数据库账号密码的校验能通过就通过
- if (bCryptPasswordEncoder.matches(password, user.getPassword())) {
- return new UsernamePasswordAuthenticationToken(user, encoderPassword);
- }
- case LoginTypeConstant.MOBILE_LOGIN:
- user = userDetailsService.loadUserByPhone(loginBody);
- return new UsernamePasswordAuthenticationToken(user, loginBody.getCode());
- case LoginTypeConstant.QR_CODE_LOGIN:
- break;
- default:
- break;
- }
- // 如果都登录不了,就返回异常输出
- throw new UserPasswordNotMatchException();
- }
-
- @Override
- public boolean supports(Class> aClass) {
- return true;
- }
- }
6.用户验证类新增手机号登录 UserDetailsServiceImpl
-
- public UserDetails loadUserByPhone(LoginBody loginBody) throws UsernameNotFoundException {
- // TODO: 2024/6/4 各种业务效验,这里图省事验证码放在password
- if (!Objects.equals(loginBody.getPassword(), "123456")) {
- throw new ServiceException("验证码错误");
- }
-
- //这里应该是根据手机号查询,我这里图省事直接拿账号登录
- String username = loginBody.getUsername();
- SysUser user = userService.selectUserByUserName(username);
- return createLoginUser(user);
- }
-
7.SecurityConfig调整,配置一下MyAuthenticationProvider
- /**
- * 自定义用户认证逻辑
- */
- @Autowired
- private MyAuthenticationProvider myAuthenticationProvider;
-
-
- /**
- * 身份认证接口
- */
- @Override
- protected void configure(AuthenticationManagerBuilder auth) throws Exception {
- auth.authenticationProvider(myAuthenticationProvider);
- }
-