Bootstrap

若依添加手机号验证


前言

在做系统登录时,常常以账号密码进行登陆注册。今天我们将通过本文,介绍,如何添加手机短信验证。本文,不着重讲解SpringSecurity,因此,是基于若依框架做的介绍。

一、阿里云短信服务


在阿里云(可以免费申请100条)、腾讯云之类的。
然后创建自己的签名并添加自己的短信模版。

二、自定义短信登录 token 验证

仿照 UsernamePasswordAuthenticationToken 类,编写短信登录 token 验证。 所在包:package com.ruoyi.framework.security.authentication;
/**
* 自定义短信登录token验证
*/
public class SmsCodeAuthenticationToken extends AbstractAuthenticationToken {
   

private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

/**
 * 存储手机号码
 */
private final Object principal;

/**
 * 构建一个没有鉴权的构造函数
 */
public SmsCodeAuthenticationToken(Object principal) {
   
    super(null);
    this.principal = principal;
    setAuthenticated(false);
}

/**
 * 构建一个拥有鉴权的构造函数
 */
public SmsCodeAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {
   
    super(authorities);
    this.principal = principal;
    super.setAuthenticated(true);
}

@Override
public Object getCredentials() {
   
    return null;
}

@Override
public Object getPrincipal() {
   
    return this.principal;
}

@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
   
    if (isAuthenticated) {
   
        throw new IllegalArgumentException(
                "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
    }
    super.setAuthenticated(false);
}

@Override
public void eraseCredentials() {
   
    super.eraseCredentials();
}

}

三、编写 UserDetailsService 实现类

在用户信息库中查找出当前需要鉴权的用户,如果用户不存在,loadUserByUsername() 方法抛出异常;如果用户名存在,将用户信息和权限列表一起封装到 UserDetails 对象中。 所在包: package com.ruoyi.framework.web.service;
/**
 * 用户验证处理
 *
 * @author yql
 */
@Service("userDetailsByPhonenumber")
public class UserDetailsByPhonenumberServiceImpl implements UserDetailsService {
   

private static final Logger log = LoggerFactory.getLogger(UserDetailsByPhonenumberServiceImpl.class);

@Autowired
private ISysUserService userService;

@Autowired
private SysPermissionService permissionService;

@Override
public UserDetails loadUserByUsername(String phoneNumber) throws UsernameNotFoundException {
   
    SysUser user = userService.findUserByPhone(phoneNumber);
    return createLoginUser(user);
}

public UserDetails createLoginUser(SysUser user) {
   
    return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
    // return new LoginUser(user, permissionService.getMenuPermission(user));
}

}

四、自定义短信登录身份认证

自定义一个身份认证,实现 AuthenticationProvider 接口;

确定 AuthenticationProvider 仅支持短信登录类型的 Authentication 对象验证;

1、重写 supports(Class<?> authentication) 方法,指定所定义的 AuthenticationProvider 仅支持短信身份验证。

2、重写 authenticate(Authentication authentication) 方法,实现身份验证逻辑。
所在包:package com.ruoyi.framework.security.authentication;

/**
 * 自定义短信登录身份认证
 */
   public class SmsCodeAuthenticationProvider implements AuthenticationProvider {
   
private UserDetailsService userDetailsService;

public SmsCodeAuthenticationProvider(UserDetailsService userDetailsService){
   

    setUserDetailsService(userDetailsService);
}

/**
 * 重写 authenticate方法,实现身份验证逻辑。
 */
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
   
    SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication;
    String telephone = (String) authenticationToken.getPrincipal();
    // 委托 UserDetailsService 查找系统用户
    UserDetails userDetails = this.userDetailsService.loadUserByUsername(telephone);
    // 鉴权成功,返回一个拥有鉴权的 AbstractAuthenticationToken
    SmsCodeAuthenticationToken authenticationResult = new SmsCodeAuthenticationToken(userDetails, userDetails.getAuthorities());
    authenticationResult.setDetails(authenticationToken.getDetails());
    return authenticationResult;
}

/**
 * 重写supports方法,指定此 AuthenticationProvider 仅支持短信验证码身份验证。
 */
@Override
public boolean supports(Class<?> authentication) {
   
    return 
;