カスタムフィルターを実行してトークンを取得し、検証しようとしています。私はこのアプローチに従っています response 。
これは関連する構成です:
SecurityConfig:
@Configuration
@EnableWebSecurity
@ComponentScan(basePackages = {"com.company.app"})
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Inject
AuthenticationTokenFilter authenticationTokenFilter;
@Inject
TokenAuthenticationProvider tokenAuthenticationProvider;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterBefore(authenticationTokenFilter, BasicAuthenticationFilter.class)
.antMatcher("/*")
.authenticationProvider(tokenAuthenticationProvider)
.authorizeRequests()
.anyRequest().authenticated();
}
}
AuthenticationTokenFilter:
@Component
public class AuthenticationTokenFilter implements Filter {
private static final Logger logger = LoggerFactory.getLogger(AuthenticationTokenFilter.class);
@Override
public void init(FilterConfig fc) throws ServletException {
logger.info("Init AuthenticationTokenFilter");
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain fc) throws IOException, ServletException {
SecurityContext context = SecurityContextHolder.getContext();
if (context.getAuthentication() != null && context.getAuthentication().isAuthenticated()) {
// do nothing
} else {
Map<String,String[]> params = req.getParameterMap();
if (!params.isEmpty() && params.containsKey("auth_token")) {
String token = params.get("auth_token")[0];
if (token != null) {
Authentication auth = new TokenAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
}
fc.doFilter(req, res);
}
@Override
public void destroy() {
}
}
TokenAuthentication:
public class TokenAuthentication implements Authentication {
private String token;
public TokenAuthentication(String token) {
this.token = token;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return new ArrayList<GrantedAuthority>(0);
}
@Override
public Object getCredentials() {
return token;
}
@Override
public Object getDetails() {
return null;
}
@Override
public Object getPrincipal() {
return null;
}
@Override
public boolean isAuthenticated() {
return false;
}
@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
}
@Override
public String getName() {
return null;
}
}
TokenAuthenticationProvider:
@Component
public class TokenAuthenticationProvider implements AuthenticationProvider {
private static final Logger logger = LoggerFactory.getLogger(TokenAuthenticationProvider.class);
@Override
public Authentication authenticate(Authentication auth) throws AuthenticationException {
if (auth.isAuthenticated())
return auth;
String token = auth.getCredentials().toString();
User user = userSvc.validateApiAuthenticationToken(token);
if (user != null) {
auth = new PreAuthenticatedAuthenticationToken(user, token);
auth.setAuthenticated(true);
logger.debug("Token authentication. Token: ");
} else
throw new BadCredentialsException("Invalid token " + token);
return auth;
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
しかし、AuthenticationTokenFilterがチェーンに追加されていないようです。デバッグ呼び出しを行うと、SecurityConfigおよびconfigureメソッドに入力されますが、フィルターには入力されないことがわかります。何が欠けている?
anonymous
認証を無効にして、セキュリティルールをfully
認証に変更してみてください。
このようなもの :
http
.addFilterBefore(authenticationTokenFilter, BasicAuthenticationFilter.class)
.antMatcher("/token")
.authenticationProvider(tokenAuthenticationProvider)
.authorizeUrls().anyRequest().fullyAuthenticated()
.and()
.anonymous().disable()
あなたが欠けているのは
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
web.xmlまたはクラスパスの初期化子の同等のもの:
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
@Order(value = 1)
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
これは、WebApplicationInitializerとは別のものです。ご了承ください:
「WebApplicationInitializerの注文」
AbstractSecurityWebApplicationInitializerが呼び出された後にサーブレットフィルターマッピングが追加された場合、springSecurityFilterChainの前に誤って追加される可能性があります。アプリケーションに保護する必要のないFilterインスタンスが含まれていない限り、springSecurityFilterChainは他のFilterマッピングの前にある必要があります。 @Orderアノテーションを使用すると、WebApplicationInitializerが確定的な順序でロードされるようになります。
例:
@Order(value = 10)
public class AppWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { AppConfig.class, SecurityConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { RestConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/rest/*"};
}
}
要約すると、Springのドキュメントから:
サーブレットフィルタを使用する場合は、明らかにweb.xmlで宣言する必要があります。そうしないと、サーブレットコンテナによって無視されます。 Spring Securityでは、フィルタークラスもアプリケーションコンテキストで定義されたSpring Beanであるため、Springの豊富な依存性注入機能とライフサイクルインターフェイスを利用できます。 SpringのDelegatingFilterProxyは、web.xmlとアプリケーションコンテキスト間のリンクを提供します。
古い投稿ですが、authenticationProvider()は「addBeforeFilter」の前に来る必要があると思います。それが今日違いを生むかどうかはわかりませんが、それは重要かもしれません。それはそれほど重要ではないかもしれません。
また、これを構成クラスに追加して、問題を解決してみてください。
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {