场景:A服务器的平台需要跳转B服务器的平台,中间通过一个链接把A平台的身份信息带入,直接进入B平台做校验,实现到B平台的免登陆流程。
实现思路:对跳转的url路径做Filter过滤,Filter里写具体实现逻辑。总结一下用SRT实现的流程。
需要实现的三个核心类
SecurityConfigurerAdapter //定义的配置信息
AuthenticationProvider //核心处理器
AbstractAuthenticationProcessingFilter //核心过滤器
上代码,定义一个配置类。把过滤的一系列操作定义好。
@Component("MerchantAuthenticationSecurityConfig")
@EnableWebSecurity //配置注解
public class MerchantAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void configure(HttpSecurity http) {
//将自定义的登录配置放入链中
MerchantAuthenticationProvider merchantAuthenticationProver = new MerchantAuthenticationProvider(userDetailsService,sysUserService); //构造Provider'
MerchantAuthenticationFilter merchantAuthenticationFilter = new MerchantAuthenticationFilter("/rdp/boss/asc",confPath);//构造方法将请求链接放入
merchantAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));//设置鉴权处理器
merchantAuthenticationFilter.setAuthenticationSuccessHandler(loginResultHandler);//设置处理成功的Handle
merchantAuthenticationFilter.setAuthenticationFailureHandler(loginResultHandler);//设置处理失败的Handle
merchantAuthenticationFilter.setRememberMeServices(tokenBasedRememberMeServices);
//设置会话记录服务
//统一用户平台登录,核心设置
http.authenticationProvider(merchantAuthenticationProver)
.addFilterAfter(merchantAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
}
然后一个核心处理类
public class MerchantAuthenticationProvider implements AuthenticationProvider {
private UserDetailsService userDetailsService;
private SysUserService sysUserService;
public MerchantAuthenticationProvider(UserDetailsService userDetailsService, SysUserService sysUserService){
this.userDetailsService = userDetailsService;
this.sysUserService = sysUserService;
}
//该方法在dofilter后调用
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
//TODO此处写验证逻辑
return new Authentication();
}
@Override
public boolean supports(Class<?> authentication) {
// 判断 authentication 是不是 OperatorAuthenticationToken 的子类或子接口
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
}
}
核心过滤器
public class MerchantAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private static final Logger logger = LoggerFactory.getLogger(MerchantAuthenticationFilter.class);
public MerchantAuthenticationFilter(String loginPath,String confPath) {
super(new AntPathRequestMatcher(loginPath, REQUEST_METHOD));
this.confPath = confPath;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
//TODO此处写具体业务逻辑
return new Authentication();
}
}
整体代码的加载流程,项目启动时先加载配置类将配置信息加载。 然后开始统一登录认证,会优先对所配置的路径进行拦截进入Filter中的doFilter方法。此处我没重写AbstractAuthenticationProcessingFilter 的doFilter方法,所以会复用父类方法。在父类方法中会调用到attemptAuthentication方法,此处就是我子类的具体实现。看下源码图。
该方法会返回一个Authentication 对象,这个对象恰好是用在AuthenticationProvider类的authenticate方法中入参。所以doFilter走完后它会根据配置的Provider去找authenticate方法执行。在业务代码中就是记录会话的操作。由此来实现统一登录。