[英]Spring security UsernamePasswordAuthenticationToken always returns 403: User credentials have expired
[英]Spring security always returns HTTP 403
我已經配置了一個自定義Filter
,它為/login
以外的每個 URL 授予 spring 權限:
public class TokenFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
GrantedAuthority authority = new SimpleGrantedAuthority("myAuthority");
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user, token, Arrays.asList(authority));
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
以及保護具有該權限的所有請求(但 / login
)的 spring 配置:
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/login").permitAll()
.anyRequest().hasAuthority("myAuthority");
}
}
但是除了/login
之外的每個請求都會得到一個 HTTP 403
Forbidden。
我已經調試並確保過濾器中的代碼真的被觸發了。
可能是什么問題呢?
編輯 - 將 spring 安全日志放入調試中時,我得到以下堆棧跟蹤:
2015-07-31 14:52:42 [http-nio-8002-exec-2] DEBUG o.s.s.w.a.ExceptionTranslationFilter - Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Accès refusé
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:83) ~[spring-security-core-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:206) ~[spring-security-core-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:115) ~[spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:84) ~[spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:113) ~[spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:103) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:113) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:154) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:45) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:57) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) [spring-security-web-3.2.4.RELEASE.jar:3.2.4.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [tomcat-embed-core-7.0.54.jar:7.0.54]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [tomcat-embed-core-7.0.54.jar:7.0.54]
at com.kgwebapps.tonpronostic.security.TokenFilter.doFilter(TokenFilter.java:55) [classes/:na]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [tomcat-embed-core-7.0.54.jar:7.0.54]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [tomcat-embed-core-7.0.54.jar:7.0.54]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) [tomcat-embed-core-7.0.54.jar:7.0.54]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) [tomcat-embed-core-7.0.54.jar:7.0.54]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501) [tomcat-embed-core-7.0.54.jar:7.0.54]
at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:683) [tomcat-embed-core-7.0.54.jar:7.0.54]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171) [tomcat-embed-core-7.0.54.jar:7.0.54]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [tomcat-embed-core-7.0.54.jar:7.0.54]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) [tomcat-embed-core-7.0.54.jar:7.0.54]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408) [tomcat-embed-core-7.0.54.jar:7.0.54]
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1040) [tomcat-embed-core-7.0.54.jar:7.0.54]
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:607) [tomcat-embed-core-7.0.54.jar:7.0.54]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1720) [tomcat-embed-core-7.0.54.jar:7.0.54]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1679) [tomcat-embed-core-7.0.54.jar:7.0.54]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_40]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_40]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-7.0.54.jar:7.0.54]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_40]
我對你有同樣的問題,每個請求都被 403 錯誤阻止,除了 [/] 請求。 在瘋狂了很多時間之后,我找到了根本原因,那就是 [csrf]。
然后我的安全配置如下:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/delete/**").authenticated().and().httpBasic().and().csrf().disable();
}
這個配置說:只有 [delete/**] 應該被授權。
我將 [delete] 操作標記為如下:
@PreAuthorize("hasRole('ROLE_ADMIN')")
void delete(String id);
希望能幫助某人。
正如其他人所說,403 表示用戶已登錄但沒有查看資源的正確權限; 我會檢查以下內容:
@Secured( {"ROLE_myAuthority"} )
new SimpleGrantedAuthority("ROLE_myAuthority");
過濾器被正確注入
Authentication auth = new UsernamePasswordAuthenticationToken(username, authentication.getCredentials(), authorities); Collection<? extends GrantedAuthority> auths = auth.getAuthorities();` Iterator authsIterator = auths.iterator(); while (authsIterator.hasNext()) { SimpleGrantedAuthority sga = (SimpleGrantedAuthority) authsIterator.next(); sga.getAuthority(); // ... }
可能導致 403 的唯一(明顯)事情是用戶角色未設置為ROLE_myAuthority
。
獲得 403 而不是 401 通常意味着您已登錄但您未被允許(通過權限)查看資源。
調試並確認您登錄的用戶具有該權限(我知道您的代碼設置了它,但也許您設置了其他錯誤)。
UsernamePasswordAuthenticationToken
擴展AbstractAuthenticationToken
, AbstractAuthenticationToken
實現Authentication
。
Spring security 調用Authentication's
方法isAuthenticated()
來檢查是否應該通過。
所以你應該調用UsernamePasswordAuthenticationToken
實例的setAuthenticated
並設置參數true
。
像這樣:
public class TokenFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
GrantedAuthority authority = new SimpleGrantedAuthority("myAuthority");
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(user, token, Arrays.asList(authority));
auth.setAuthenticated(true);
SecurityContextHolder.getContext().setAuthentication(auth);
}
}
很老的問題,但以防萬一有人偶然發現這篇文章,一個應用程序有同樣的問題,結果是@ControllerAdvice
的問題。
基本上,設置是這樣的:
@ControllerAdvice
class MainController {
@PreAuthorize("...")
class AdminController extends MainController {
出於一個奇怪的原因,任何從MainController
擴展的控制器都會觸發AdminController
類的@PreAuthorize
,即使此控制器與后者之間沒有關系。
就我而言,這是一個簡單的修復,因為刪除@ControllerAdvice
就足夠了,但是如果您需要@ControllerAdvice
,您可以將注釋移動到一個從未用作超類的類。
我知道這是一個非常古老的問題,但我遇到了同樣的錯誤,而且我沒有在互聯網上找到任何解決方案。
403表示用戶已通過身份驗證但未獲得獲取資源的授權,這是正確的。 這與您的 JWT 中的聲明部分有關。
您的 JWT 構建器需要為用戶設置正確的聲明:
List<GrantedAuthority> grantedAuthorities = AuthorityUtils
.commaSeparatedStringToAuthorityList("ROLE_USER");
Jwts.builder()//
.setIssuer(...)//
.setSubject(...)//
.setAudience(...)
// This is the part that you missed
.claim("authorities",
grantedAuthorities.stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList()))
// Ends here
.setIssuedAt(date)//
.setExpiration(new Date(date.getTime() + jwtExpirationMs))
.signWith(SignatureAlgorithm.HS512, signingKey)//
.compact();
我的網絡安全配置:
public class WebSecurity extends WebSecurityConfigurerAdapter {
...
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()//
.authorizeRequests()//
.antMatchers(...).permitAll()//
.anyRequest().authenticated()
.and()
.sessionManagement()//
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterAfter(authenticationJwtTokenFilter(), BasicAuthenticationFilter.class);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.