SpringSecurity 调用流程:
首先会进入UsernamePasswordAuthenticationFilter并且设置权限为null和是否授权为false,然后进入ProviderManager查找支持UsernamepasswordAuthenticationToken的provider并且调用provider.authenticate(authentication);再然后就是UserDetailsService接口的实现类,然后回调UsernamePasswordAuthenticationFilter并且设置权限(具体业务所查出的权限)和设置授权为true。
下面是实现手机验证码登录的流程:
第一步:新建MyAuthenticationToken 自定义AbstractAuthenticationToken
/**
* @Description 自定义AbstractAuthenticationToken
* @Author wwz
* @Date 2019/08/04
* @Param
* @Return
*/
public class MyAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = 110L;
protected final Object principal;
protected Object credentials;
/**
* This constructor can be safely used by any code that wishes to create a
* <code>UsernamePasswordAuthenticationToken</code>, as the {@link
* #isAuthenticated()} will return <code>false</code>.
*
*/
public MyAuthenticationToken(Object principal, Object credentials) {
super(null);
this.principal = principal;
this.credentials = credentials;
this.setAuthenticated(false);
}
/**
* This constructor should only be used by <code>AuthenticationManager</code> or <code>AuthenticationProvider</code>
* implementations that are satisfied with producing a trusted (i.e. {@link #isAuthenticated()} = <code>true</code>)
* token token.
*
* @param principal
* @param credentials
* @param authorities
*/
public MyAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
super.setAuthenticated(true);
}
@Override
public Object getCredentials() {
return this.credentials;
}
@Override
public Object getPrincipal() {
return this.principal;
}
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");
} else {
super.setAuthenticated(false);
}
}
public void eraseCredentials() {
super.eraseCredentials();
this.credentials = null;
}
}
第二步:新建 (手机验证码登录用)MyPhoneAuthenticationToken 继承 MyAuthenticationToken
/**
* @Description 手机验证token
* @Author wwz
* @Date 2019/08/04
* @Param
* @Return
*/
public class MyPhoneAuthenticationToken extends MyAuthenticationToken {
public MyPhoneAuthenticationToken(Object principal, Object credentials) {
super(principal, credentials);
}
public MyPhoneAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
super(principal, credentials, authorities);
}
}
第三步:新建MyAbstractUserDetailsAuthenticationProvider 抽象类 自定义AuthenticationProvider 抽象,方便其他扩展
/**
* @Description 自定义AuthenticationProvider 抽象,方便其他扩展
* @Author wwz
* @Date 2019/08/04
* @Param
* @Return
*/
public abstract class MyAbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware {
protected final Log logger = LogFactory.getLog(this.getClass());
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
private UserCache userCache = new NullUserCache();
private boolean forcePrincipalAsString = false;
protected boolean hideUserNotFoundExceptions = true;
private UserDetailsChecker preAuthenticationChecks = new MyAbstractUserDetailsAuthenticationProvider.DefaultPreAuthenticationChecks();
private UserDetailsChecker postAuthenticationChecks = new MyAbstractUserDetailsAuthenticationProvider.DefaultPostAuthenticationChecks();
private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
protected abstract void additionalAuthenticationChecks(UserDetails var1, Authentication var2) throws AuthenticationException;
public final void afterPropertiesSet() throws Exception {
Assert.notNull(this.userCache, "A user cache must be set");
Assert.notNull(this.messages, "A message source must be set");
this.doAfterPropertiesSet();
}
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String username = authentication.getPrincipal() == null?"NONE_PROVIDED":authentication.getName();
boolean cacheWasUsed = true;
UserDetails user = this.userCache.getUserFromCache(username);
if(user == null) {
cacheWasUsed = false;
try {