我有一个spring应用程序,它使用自定义身份验证筛选器说filter1来授权请求,此筛选器使用身份验证管理器进行身份验证,适用于应用程序中的所有URL。
现在,我想实现一个不同的身份验证过滤器说filter2,它必须使用url(/ api /)授权特殊类型的请求。这就是具有url的所有请求(/ api / **)必须使用filter2。
以下是我为此目的而尝试的代码。
public class SecurityAppConfig {
@Configuration
@Order(1)
public static class APISecurityConfig extends WebSecurityConfigurerAdapter {
private CustomAuthenticationManager1 manager1 = new CustomAuthenticationManager1();
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.formLogin().disable().csrf().disable().cors().disable().logout().disable();
if (manager1 != null) {
http.addFilterAfter(new Filter1(manager1),
AnonymousAuthenticationFilter.class);
}
}
}
@Configuration
@Order(2)
public static class OtherApiSecurityConfig extends WebSecurityConfigurerAdapter {
private AuthenticationManager2 manager2 = new AuthenticationManager2();
@Override
protected void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.formLogin().disable().csrf().disable().cors().disable().logout().disable();
if (manager2 != null) {
http.antMatchers("/api/**").addFilterAfter(new Filter2(manager2),
AnonymousAuthenticationFilter.class);
}
}
}
}
在应用程序启动时,过滤器都会向其管理员注册,但是当这个(“/ api / **”)请求到来时,它会进入第一个过滤器进行身份验证,但永远不会进入第二个过滤器。如果我删除了第一个过滤器,那么它可以正常工作但是会覆盖其他api请求的过滤器。
以下是我实施管理员和过滤器的方式
public class Filter1 extends AbstractAuthenticationProcessingFilter {
//implementation omitted for brevity.
}
public class Filter2 extends AbstractAuthenticationProcessingFilter {
//implementation omitted for brevity.
}
public class AuthenticationManager1 implements AuthenticationManager {
//implementation omitted for brevity.
}
public class AuthenticationManager2 implements AuthenticationManager {
//implementation omitted for brevity.
}
有关如何使其正常工作的任何想法。
答案 0 :(得分:4)
我认为你的案子不需要两个配置。我不明白为什么你需要实现自己的身份验证管理器,甚至其中两个。我想你应该使用共享身份验证管理器,实现自己的AuthenticationProvider
(每种身份验证类型一个),并实现自己的身份验证令牌。除此之外,由于您使用AbstractAuthenticationProcessingFilter
作为过滤器的基类 - 您可以将filterProcessesUrl
设置为其中,因此您的过滤器知道应该应用哪个URL。所以,简而言之:
身份验证令牌:
public class MyAuth1AuthenticationToken extends AbstractAuthenticationToken {
// Implementation depends on you auth scheme (you can look on
// `UsernamePasswordAuthenticationToken` for example)
}
public class MyAuth2AuthenticationToken extends AbstractAuthenticationToken {
// ...
}
身份验证提供商:
public class MyAuth1AuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
// Implementation really depends on you auth scheme (you can look on
// `AbstractUserDetailsAuthenticationProvider` for example)
}
@Override
public boolean supports(Class<?> authentication) {
// By this we're saying that this auth provider is responsible for our MyAuth1 auth request
return (MyAuth1AuthenticationToken.class.isAssignableFrom(authentication));
}
}
public class MyAuth2AuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
// ...
}
@Override
public boolean supports(Class<?> authentication) {
return (MyAuth2AuthenticationToken.class.isAssignableFrom(authentication));
}
}
过滤器:强>
public class Auth1Filter extends AbstractAuthenticationProcessingFilter {
public Auth1Filter(AuthenticationManager authManager, String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
setAuthenticationManager(authManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
// extract user info here
// ...
// populate auth request with your info
MyAuth1AuthenticationToken authRequest = new MyAuth1AuthenticationToken(...);
// authenticate
return this.getAuthenticationManager().authenticate(authRequest);
}
}
public class Auth2Filter extends AbstractAuthenticationProcessingFilter {
public Auth2Filter(AuthenticationManager authManager, String defaultFilterProcessesUrl) {
super(defaultFilterProcessesUrl);
setAuthenticationManager(authManager);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) throws AuthenticationException {
// extract user info here
// ...
// populate auth request with your info
MyAuth2AuthenticationToken authRequest = new MyAuth1AuthenticationToken(...);
// authenticate
return this.getAuthenticationManager().authenticate(authRequest);
}
}
安全配置:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception
{
// registering our providers
auth
.authenticationProvider(new MyAuth1AuthenticationProvider())
.authenticationProvider(new MyAuth2AuthenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.formLogin().disable()
.csrf().disable()
.cors().disable()
.logout().disable();
AuthenticationManager authManager = http.getSharedObject(AuthenticationManager.class);
http.addFilterAfter(new Auth1Filter(authManager, "/**"), BasicAuthenticationFilter.class);
http.addFilterAfter(new Auth2Filter(authManager, "/api/**"), BasicAuthenticationFilter.class);
}
}
希望它有所帮助。