前提:auth服务旧版本是用springSecurity oauth2.0实现的,现版本改为springSecurity+jwt
springSecurity原认证流程
1、SpringSecurity默认自带的拦截器是拦截/login路径,但由于oauth2前用的是oauth/token 接口,考虑到其他产品已接sso登录,为了后续更新兼容旧的sso需要写一个新的拦截器,拦截路径/oauth/token,定义一个EoiAuthenticationFilter
2、在SpringSecurity默认的AuthenticationManager实现类是ProviderManager在ProviderManager中关键代码为通过supports方法去选择到具体的provider
为了兼容之前oauth自定义的那些认证方法(根据前端的grantType决定用哪种认证),要需要重写supports校验规则,自定义一个EoiAuthenticationProvider接口(主要是为了重写supports方法传参为String类型)
3、因为重写了supports校验规则,Security默认的ProviderManager就用不了了(接口类型不一致,更主要是为了重写选择规则),需要自定义一个EoiProviderManager继承AuthenticationManager
伪代码:
class EoiAuthenticationFilter extends AbstractAuthenticationProcessingFilter{
private static final AntPathRequestMatcher OAUTH_TOKEN_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher("/oauth/token",
"POST");
protected EoiAuthenticationFilter(String defaultFilterProcessesUrl) {
//定义拦截路径
super(OAUTH_TOKEN_ANT_PATH_REQUEST_MATCHER);
}
//重写setDetails方法
protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
//将请求参数传进去
authRequest.setDetails(request.getParameterMap());
}
//其他与UsernamePasswordAuthenticationFilter逻辑一致
return this.getAuthenticationManager().authenticate(authRequest);
}
//自定义接口
public interface EoiAuthenticationProvider {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
boolean supports(String grantType);
}
//自定义的认证方式
@Component
public class CaptchaTokenProvider implements EoiAuthenticationProvider {
public static final String GRANT_TYPE = "captcha";
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
//自定义具体逻辑
return null;
}
@Override
public boolean supports(String grantType) {
//是否匹配认证方式
return GRANT_TYPE.equalsIgnoreCase(grantType);
}
}
//自定义ProviderManager
public class EoiProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Map<String, String[]> details = (Map<String, String[]>) authentication.getDetails();
for (EoiAuthenticationProvider provider : getProviders()) {
if(provider.supports(details.get("grant_type")){
provider.authenticate(authentication)
}
}
//省略其他代码
//其他与ProviderManage一致
}
//Security配置文件
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
private final UserDetailsService userDetailsService;
//由spring注入
private final List<EoiAuthenticationProvider> providers;
@Bean
public PasswordEncoder passwordEncoder() {
return OriginPasswordEncoderFactories.createDelegatingPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//设置自定义的密码检验逻辑
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) {
http.headers().frameOptions().disable();
//添加拦截器 将自定义的Provider注入到自定义的Manager中
http.addFilterBefore(new EoiAuthenticationFilter(new EoiProviderManager(providers)), UsernamePasswordAuthenticationFilter.class);
//添加自定义成功处理器,封装token信息与颁发token
http.formLogin().successHandler(new EoiAuthenticationSuccessHandler)
}
}
//springSecurity并没有带RANT_TYPE = "password";
@Component
@AllArgsConstructor
public class PasswordProvider extends DaoAuthenticationProvider implements EoiAuthenticationProvider {
public static final String GRANT_TYPE = "password";
@Bean
public PasswordEncoder passwordEncoder() {
return OriginPasswordEncoderFactories.createDelegatingPasswordEncoder();
}
private UserDetailsService userDetailsService;
@PostConstruct
void init() {
this.setUserDetailsService(userDetailsService);
this.setPasswordEncoder(this.passwordEncoder());
}
@Override
public boolean supports(String grantType) {
return GRANT_TYPE.equalsIgnoreCase(grantType);
}
}