文章目录
前言
在做系统登录时,常常以账号密码进行登陆注册。今天我们将通过本文,介绍,如何添加手机短信验证。本文,不着重讲解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