备忘贴
转自:【若依RuoYi短信验证码登录】汇总_数据库_z_xiao_qiang-RuoYi 若依
配置Security:
按照Security的流程图可知,实现多种方式登录,只需要重写三个主要的组件,第一个用户认证处理过滤器,第二个用户认证token类,第三个,自定义短信登录身份认证。
/**
* 参考UsernamePasswordAuthenticationToken类,继承AbstractAuthenticationToken,重写以下几个方法,自定义短信登录token验证。
* 自定义短信登录token验证
*/
public class UsernamePhoneAuthenticationToken extends AbstractAuthenticationToken {
/**
* 手机号
*/
private final Object principal;
public UsernamePhoneAuthenticationToken(Object principals){
super(null);
this.principal = principals;
setAuthenticated(false);
}
public UsernamePhoneAuthenticationToken(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方法,实现用户验证处理。
* 用户验证处理
*/
@Service("userDetailsByPhone")
public class UsernamePhoneUserDetailsServiceImpl implements UserDetailsService {
private static final Logger logger = LoggerFactory.getLogger(UsernamePhoneUserDetailsServiceImpl.class);
@Autowired
private ISysUserService userService;
@Autowired
private SysUserMapper sysUserMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
SysUser sysUser;
if(Pattern.compile("^[1][1,2,3,4,5,6,7,8,9][0-9]{9}$").matcher(username).matches()){
sysUser = sysUserMapper.selectUserByTel(username);
}else if(username.matches("\\w{1,30}@[a-zA-Z0-9]{2,20}(\\.[a-zA-Z0-9]{2,20}){1,2}")){
sysUser = sysUserMapper.selectUserByEmail(username);
}else{
throw new ServiceException("请使用手机号或者邮箱进行登录!");
}
if(StringUtils.isNull(sysUser)){
logger.info("登录用户:{} 不存在.", username);
throw new ServiceException("登录用户:" + username+ " 不存在");
}
return createLoginUser(sysUser);
}
public UserDetails createLoginUser(SysUser user){
return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
}
/**
* 自定义一个短信登录的身份鉴权, UserDetailsService 只负责根据用户名返回用户信息,AuthenticationProvider负责将 UserDetails 组装成 Authentication 向调用者返回。
* 自定义短信登录身份认证
*/
public class UsernamePhoneAuthenticationProvider implements AuthenticationProvider {
private UserDetailsService userDetailsService;
public UsernamePhoneAuthenticationProvider(UserDetailsService userDetailsService){
setUserDetailsService(userDetailsService);
}
/**
* 重写authentication方法,实现身份验证逻辑
*/
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
UsernamePhoneAuthenticationToken authenticationToken = (UsernamePhoneAuthenticationToken) authentication;
String phone = (String) authenticationToken.getPrincipal();
//委托 UserDetailsService 查找系统用户
UserDetails userDetails = userDetailsService.loadUserByUsername(phone);
//鉴权成功,返回一个拥有鉴权的AbstractAuthenticationToken
UsernamePhoneAuthenticationToken authenticationTokenRes = new UsernamePhoneAuthenticationToken(userDetails, userDetails.getAuthorities());
authenticationTokenRes.setDetails(authenticationToken.getDetails());
return authenticationTokenRes;
}
/**
* 重写supports方法,指定此AuthenticationProvider 仅支持短信验证码身份验证
*/
@Override
public boolean supports(Class<?> authentication){
return UsernamePhoneAuthenticationToken.class.isAssignableFrom(authentication);
}
public UserDetailsService getUserDetailsService() {
return userDetailsService;
}
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
/**
* 配置SecurityConfig 的configure方法
* spring security配置
*
* @author victor_zhang
*/
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{
/**
* 自定义用户认证逻辑(账号密码)
*/
@Autowired
@Qualifier("userDetailsByPass")
private UserDetailsService userDetailsService;
/**
* 自定义用户认证逻辑(手机号验证码)
*/
@Autowired
@Qualifier("userDetailsByPhone")
private UserDetailsService userDetailsByPhone;
/**
* 认证失败处理类
*/
@Autowired
private AuthenticationEntryPointImpl unauthorizedHandler;
/**
* 退出处理类
*/
@Autowired
private LogoutSuccessHandlerImpl logoutSuccessHandler;
/**
* token认证过滤器
*/
@Autowired
private JwtAuthenticationTokenFilter authenticationTokenFilter;
//此处省略n行代码......
/**
* 身份认证接口
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
{
//手机或邮箱的验证码的验证
auth.authenticationProvider(new UsernamePhoneAuthenticationProvider(userDetailsByPhone));
//账号密码的验证
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
}