spring security异常记录:org.springframework.security.access.AccessDeniedException: Access is denied
Posted sword to coding
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring security异常记录:org.springframework.security.access.AccessDeniedException: Access is denied相关的知识,希望对你有一定的参考价值。
最近在做ssm项目的时候用到spring security时遇到了异常,如下所示:
15:06:28,144 DEBUG FilterSecurityInterceptor:348 - Previously Authenticated: org.springframework.security.authentication.AnonymousAuthenticationToken@52dd6d71: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
15:06:28,180 DEBUG AffirmativeBased:66 - Voter: org.springframework.security.web.access.expression.WebExpressionVoter@1f4acb36, returned: -1
15:06:28,185 DEBUG ExceptionTranslationFilter:181 - Access is denied (user is anonymous); redirecting to authentication entry point
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:84)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:233)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:124)
at org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:119)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:170)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.www.BasicAuthenticationFilter.doFilterInternal(BasicAuthenticationFilter.java:158)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:66)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:357)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:270)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
网上查阅了很多资料,出现这种异常主要有以下几种原因:
情况一
用户已经登录成功,但是该用户的权限不能够操作受限制的页面
我看了我的配置文件,发现出现的错误并不是该原因:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
<!-- 定义放行的页面-->
<security:http security="none" pattern="/login.html"></security:http>
<security:http security="none" pattern="/css/**"></security:http>
<security:http security="none" pattern="/img/**"></security:http>
<security:http security="none" pattern="/js/**"></security:http>
<security:http security="none" pattern="/plugins/**"></security:http>
<!-- 定义保护的页面,只要认证通过就放行,具体的权限使用注解的方式去拦截-->
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/pages/**" access="isAuthenticated()"></security:intercept-url>
<security:headers>
<!--设置在页面可以通过iframe访问受保护的页面,默认为不允许访问-->
<security:frame-options policy="SAMEORIGIN"></security:frame-options>
</security:headers>
<!-- 自定义登陆页面-->
<security:form-login
login-page="/login.html"
username-parameter="username"
password-parameter="password"
login-processing-url="/login.do"
default-target-url="/pages/main.html"
authentication-failure-url="/login.html"
></security:form-login>
<security:csrf disabled="true"></security:csrf>
<!-- 退出登录-->
<security:logout
logout-url="/logout.do"
logout-success-url="/login.html"
invalidate-session="true"></security:logout>
</security:http>
<!-- 授权关系管理-->
<security:authentication-manager>
<security:authentication-provider user-service-ref="springSecurityUserService">
<security:password-encoder ref="passwordEncoder"></security:password-encoder>
</security:authentication-provider>
</security:authentication-manager>
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean>
<security:global-method-security pre-post-annotations="enabled"></security:global-method-security>
</beans>
其中
<security:intercept-url pattern="/pages/**" access="isAuthenticated()"></security:intercept-url>
表示只要是登录成功的都可以访问pages下的页面,但是我登录了却还是报错
情况二:
网上的观点:
情况三:
我的分析:
org.springframework.security.access.AccessDeniedException: Access is denied
at
这个异常在spring security中通常都是指登录的用户没有权限访问请求的资源。但是我看了配置文件是正常配置了访问权限的。之后我又看了打印的日志信息:
我的异常出现之前都会有这个日志,我的猜想是无论我登录了怎样的用户,被授予的权限都是ROLE_ANONYMOUS (表示匿名用户)
所以导致我无权访问被保护的页面。
解决方案
已解决
我的错误:禁用了网站的cookie
允许cookie即可
参考文章:
Spring Security出现问题:Access is denied 及我的解决方案
User Granted Authorities are always : ROLE_ANONYMOUS?
登录不跳转RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS
甚至没有调用自定义 Spring Security 身份验证提供程序?
【中文标题】甚至没有调用自定义 Spring Security 身份验证提供程序?【英文标题】:Custom Spring Security Authentication provider not even being called? 【发布时间】:2021-12-25 19:04:32 【问题描述】:我需要从 3rd 方应用授权用户。基本上这是一个 REST api 调用,但这不是问题。每次我导航到一个页面时,我都会自动重定向到错误页面,根本没有任何解释。日志中没有任何内容,即使我的日志记录:logging.level.org.springframework.security=DEBUG 和我的根级别为 WARN
我的安全配置如下所示:
@Configuration
@EnableWebSecurity
@ConfigurationProperties("security")
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
@Autowired
ELPAuthenticationProvider authenticationProvider;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception
auth.authenticationProvider(authenticationProvider);
@Override
protected void configure(HttpSecurity http) throws Exception
elpLogger.debug("****************Configuring HttpSecurity");
http.authorizeRequests().antMatchers("/hello/**").permitAll();
http.authorizeRequests().anyRequest().authenticated();
还有我的身份验证提供者:
@Component
public class ELPAuthenticationProvider implements AuthenticationProvider
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException
logger.debug("In Authenticate");
final List<GrantedAuthority> grantedAuths = new ArrayList<>();
grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
final UserBean principal = new UserBean("admin", "password", grantedAuths);
final Authentication auth = new UsernamePasswordAuthenticationToken(principal, "password", grantedAuths);
return auth;
@Override
public boolean supports(Class<? extends Object> authentication)
return true;
对我来说,这看起来应该验证任何东西。但是除了我的 HelloWorldController ("/hello") 之外的所有东西我都会被扔到我的错误页面而没有任何解释。我的日志如下所示:
o.s.security.web.FilterChainProxy : Securing GET /
s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to empty SecurityContext
o.s.s.w.a.AnonymousAuthenticationFilter : Set SecurityContextHolder to anonymous SecurityContext
o.s.s.w.a.i.FilterSecurityInterceptor : Failed to authorize filter invocation [GET /] with attributes [authenticated]
o.s.s.w.s.HttpSessionRequestCache : Saved request http://localhost:7080/ to session
o.s.s.w.a.Http403ForbiddenEntryPoint : Pre-authenticated entry point called. Rejecting access
w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
w.c.HttpSessionSecurityContextRepository : Did not store empty SecurityContext
s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
c.e.web.controllers.ELPErrorController : ************************ Error handler
所以我不知道为什么我的身份验证提供程序甚至没有被调用,其次,我不知道为什么会抛出异常。 (或者为什么我被重定向到错误页面而不是未授权页面)
有什么想法吗?
编辑 我从 AuthenticationProvider 中删除了 @Component 注释,并在我的主 Application.java 中将其声明为 bean 将其自动连接到 SecurityConfiguration 中。我在上面的示例中进行了更改。完全相同的问题。没有变化。
【问题讨论】:
请 (1.) 还要确保logging.level.<package.of.elpauthenticationprovider>=debug
和 (2.) 它是组件(自动扫描?)还是 bean? (我知道/理解它是完全一样的,但可能是冲突的......当一起使用时(没有警告??))
@xerx593 没有变化。日志级别是调试。但我确实有两个组件注释,并将其声明为 Bean。我去掉了组件注解,把Bean方法放到Application.java中我相应地调整了问题中的代码。
除了下面的@fast-reflexes 回答之外,请确保您不要两次致电http.authorizeRequests()
。第二次调用会覆盖第一次。您可以将规则链接在一起,如:http.authorizeRequests().antMatchers("/hello/**").permitAll()..anyRequest().authenticated()
.
【参考方案1】:
鉴于AuthenticationProvider
接口中的authenticate
方法将身份验证作为参数,我们可以放心,必须进行某种初始身份验证,以便为提供者提供一些工作。以下摘录在 Kotlin 中给出。
即使使用带有基本身份验证的标准设置
@Configuration
class SecurityAssets
@Bean
fun passwordEncoder(): PasswordEncoder =
return BCryptPasswordEncoder()
@EnableWebSecurity
class Config(val encoder: PasswordEncoder): WebSecurityConfigurerAdapter()
override fun configure(auth: AuthenticationManagerBuilder)
auth
.inMemoryAuthentication()
.withUser("user")
.password(encoder.encode("password"))
.roles("USER")
override fun configure(http: HttpSecurity)
http
.authorizeRequests()
.anyRequest()
.authenticated()
以上内容不会触发身份验证。为此,我们需要为 Spring 添加一些方法来创建初始身份验证,然后由配置的提供者进行身份验证:
@EnableWebSecurity
class Config(val encoder: PasswordEncoder): WebSecurityConfigurerAdapter()
...
override fun configure(http: HttpSecurity)
http
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.httpBasic()
现在可以了!
在你的情况下,类似的事情也会起作用:
class CustomAuthenticationProvider : AuthenticationProvider
override fun authenticate(authentication: Authentication): Authentication
println("In Authenticate")
val grantedAuths: MutableList<GrantedAuthority> = ArrayList()
grantedAuths.add(SimpleGrantedAuthority("ROLE_USER"))
val principal = AuthenticatedPrincipal "Name"
return UsernamePasswordAuthenticationToken(principal, "password", grantedAuths)
override fun supports(authentication: Class<*>?): Boolean
println("In supports")
return true
@EnableWebSecurity
class Config(val encoder: PasswordEncoder): WebSecurityConfigurerAdapter()
override fun configure(auth: AuthenticationManagerBuilder)
auth
.authenticationProvider(CustomAuthenticationProvider())
override fun configure(http: HttpSecurity)
http
.authorizeRequests()
.anyRequest()
.authenticated()
.and()
.httpBasic()
如何使自定义提供程序对配置器可用并不重要,您可以使用 bean 或简单地在需要时将其实例化。
如果您需要一些不同的主要身份验证方法,您可以将httpBasic
更改为其他内容。如果您需要自定义实际的身份验证方法(例如,查找一些自定义标头或其他过滤器尚不存在的东西),那么您应该实现一个自定义过滤器,该过滤器被添加到安全过滤器链中,然后委托给您的提供商。
安全过滤器链中的过滤器是实际处理请求的内容,简单地添加安全提供程序不会添加新过滤器,在本例中,httpBasic
会添加新过滤器。
【讨论】:
以上是关于spring security异常记录:org.springframework.security.access.AccessDeniedException: Access is denied的主要内容,如果未能解决你的问题,请参考以下文章
如何处理 grails spring-security-rest 插件中的自定义身份验证异常?
甚至没有调用自定义 Spring Security 身份验证提供程序?
Spring Security入门(3-4)Spring Security 异常处理异常传递和异常获取