[英]How to check access token only if resource is secured in spring security?
[英]How to apply Spring Security filter only on secured endpoints?
我有以下 Spring 安全配置:
httpSecurity
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/**").fullyAuthenticated()
.and()
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
authenticationTokenFilterBean()
甚至適用於與/api/**
表達式不匹配的端點。 我還嘗試添加以下配置代碼:
@Override
public void configure(WebSecurity webSecurity) {
webSecurity.ignoring().antMatchers("/some_endpoint");
}
但這仍然沒有解決我的問題。 我如何告訴 Spring Security 僅在與安全 URI 表達式匹配的端點上應用過濾器?
我有一個具有相同要求的應用程序,為了解決它,我基本上將 Spring Security 限制為給定的 ant 匹配模式(使用antMatcher
),如下所示:
http.antMatcher("/api/**").authorizeRequests() //
.anyRequest().authenticated() //
.and()
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
您可以按如下方式閱讀:對於http
僅在匹配螞蟻模式的請求上調用這些配置/api/**
授權any request
到經過authenticated
用戶, and
before
UsernamePasswordAuthenticationFilter
before
add filter
authenticationTokenFilterBean()
。 對於所有其他請求,此配置無效。
GenericFilterBean
有以下方法:
/**
* Can be overridden in subclasses for custom filtering control,
* returning {@code true} to avoid filtering of the given request.
* <p>The default implementation always returns {@code false}.
* @param request current HTTP request
* @return whether the given request should <i>not</i> be filtered
* @throws ServletException in case of errors
*/
protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException {
return false;
}
因此,在擴展GenericFilterBean
的過濾器中,您可以覆蓋該方法並實現邏輯以僅在您想要的路由上運行過濾器。
如果您使用
.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
您可以在構造函數中定義它將應用於的特定路徑:
public class JwtAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
super("/api/**");
this.setAuthenticationManager(authenticationManager);
}
@Override
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
return super.requiresAuthentication(request, response);
}
requiresAuthentication
方法將用於知道該端點是否需要身份驗證。
我的要求是排除匹配 /api/auth/** 的端點,以實現相同的我配置我的 WebSecurityConfig spring 配置組件如下:
/**
* The purpose of this method is to exclude the URL's specific to Login, Swagger UI and static files.
* Any URL that should be excluded from the Spring security chain should be added to the ignore list in this
* method only
*/
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/api/auth/**","/v2/api-docs",
"/configuration/ui",
"/swagger-resources",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**",
"/favicon.ico",
"/**/*.png",
"/**/*.gif",
"/**/*.svg",
"/**/*.jpg",
"/**/*.html",
"/**/*.css",
"/**/*.js");
}
/**
* The purpose of this method is to define the HTTP configuration that defines how an HTTP request is
* going to be treated by the Spring Security chain. All the request URL's (excluding the URL's added
* in WebSecurity configuration ignore list) matching this configuration have to pass through the
* custom Spring security filter defined in this method
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.cors().disable()
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
}
/**
* The purpose of this method is to create a new instance of JWTAuthenticationFilter
* and return the same from the method body. It must be ensured that this filter should
* not be configured as a Spring bean or registered into the Spring Application context
* failing which the below filter shall be registered as a default web filter, and thus
* all the URL's even the excluded ones shall be intercepted by the below filter
*/
public JWTAuthenticationFilter authenticationTokenFilterBean() {
return new JWTAuthenticationFilter();
}
我想我已經找到了解決它的方法。 我有JwtTokenAuthenticationProcessingFilter
,它是一個AbstractAuthenticationProcessingFilter
。 如果頭部有令牌,我希望它對請求進行身份驗證,但如果失敗則不阻止請求。 無論認證結果如何(調用 unsuccessfulAuthentication 是可選的),您只需要重寫doFilter並調用chain.doFilter
。 這是我的代碼的一部分。
public class JwtTokenAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
private final TokenExtractor tokenExtractor;
@Autowired
public JwtTokenAuthenticationProcessingFilter(TokenExtractor tokenExtractor, RequestMatcher matcher) {
super(matcher);
this.tokenExtractor = tokenExtractor;
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
if (!this.requiresAuthentication(request, response)) {
chain.doFilter(request, response);
} else {
if (this.logger.isDebugEnabled()) {
this.logger.debug("Request is to process authentication");
}
boolean success = true;
Authentication authResult = null;
try {
authResult = this.attemptAuthentication(request, response);
} catch (InternalAuthenticationServiceException var8) {
this.logger.error("An internal error occurred while trying to authenticate the user.", var8);
success = false;
} catch (AuthenticationException var9) {
success = false;
}
if (success && null != authResult) {
this.successfulAuthentication(request, response, chain, authResult);
}
// Please ensure that chain.doFilter(request, response) is invoked upon successful authentication. You want
// processing of the request to advance to the next filter, because very last one filter
// FilterSecurityInterceptor#doFilter is responsible to actually invoke method in your controller that is
// handling requested API resource.
chain.doFilter(request, response);
}
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
String tokenPayload = request.getHeader(WebSecurityConfig.AUTHENTICATION_HEADER_NAME);
RawAccessJwtToken token = new RawAccessJwtToken(tokenExtractor.extract(tokenPayload));
return getAuthenticationManager().authenticate(new JwtAuthenticationToken(token));
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException {
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authResult);
SecurityContextHolder.setContext(context);
}
}
4月22日更新
要注冊過濾器,只需將以下代碼添加到 WebSecurityConfig
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final JwtAuthenticationProvider mJwtAuthenticationProvider;
@Autowired
public WebSecurityConfig(JwtAuthenticationProvider jwtAuthenticationProvider) {
this.mJwtAuthenticationProvider = jwtAuthenticationProvider;
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// When multiple authentication providers are defined, the providers will be queried in the order they’re
// declared.
auth.authenticationProvider(mJwtAuthenticationProvider);
}
}
在代碼中,我只透露了有關添加過濾器的關鍵部分。 所有這些實現都受到了這個站點的啟發。 感謝作者 Vladimir Stankovic 的詳細解釋。
我們最近更新到 Spring Boot 3.0.0,它使用 Spring Security 6.0.0,並且在將過濾器應用於所有請求時遇到了類似的問題,盡管authorizeHttpRequests()
與定義的特定路徑一起使用。
原來,如果要為特定路徑配置HttpSecurity
,則需要在開始時使用securityMatcher()
。
所以它會是這樣的:
private SecurityFilterChain configureFilterChain(HttpSecurity http, String pattern, String... roles) throws Exception {
return http
.securityMatcher(pattern)
.authorizeHttpRequests(auth -> auth.requestMatchers(AntPathRequestMatcher.antMatcher(pattern)).hasAnyRole(roles))
.addFilterBefore(new TokenFilter(), UsernamePasswordAuthenticationFilter.class)
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.authenticationEntryPoint(new AuthenticationEntryPointImpl())
.accessDeniedHandler(new AccessDeniedHandlerImpl())
.and()
.csrf().disable()
.build();
}
因此,在這種情況下,TokenFilter 將僅應用於具有此pattern
的請求。
要繞過某些特定端點的 spring 安全性,請執行以下操作:
httpSecurity
.authorizeRequests()
.antMatchers("/some_endpoints").permitAll()
.anyRequest().authenticated()
.and()
...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.