我遇到了使用@secured of spring-security注释的方法的问题
@Secured(value = { "LIST_GIFT" })
该方法已放置在spring-mvc Web应用程序的Controller方法中。
当我通过UserDetailsService实现调试时,我们在loadByUserName方法的末尾有以下UserDetails对象:
SecurityDetails [userId=106, username=john@doe.com, enabled=true, accountNonLocked=true, accountNonExpired=true, credentialsNonExpired=true]
使用以下授权的授权列表:
[LOCK_SERIAL, CALCULATE_BALANCE, REGISTER_FOR_PUSH_NOTIFICATION, TOPUP_BY_POS, LIST_PRODUCTS, LIST_COUPON_ASSIGNMENT, BALANCE, BALANCE_HISTORY, LIST_GIFT, LIST_PROGRAMS, ASSIGN_COUPON, DISTRIBUTE_COUPON, CAN_CONFIGURE_GIFTS]
HTTP始终返回403 Forbidden。当我打开日志记录时,我看到以下内容:
DEBUG: org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor - Secure object: ReflectiveMethodInvocation: public com.foo.products.sva.cc.customer.domain.AccountBalance com.foo.products.sva.cc.customer.controllers.AccountController.getBalance(java.lang.String); target is of class [com.foo.products.sva.cc.customer.controllers.AccountController]; Attributes: [LIST_GIFT]
DEBUG: org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor - Previously Authenticated: org.springframework.security.authentication.UsernamePasswordAuthenticationToken@380cef3f: Principal: SecurityDetails [userId=106, username=john@doe.com, enabled=true, accountNonLocked=true, accountNonExpired=true, credentialsNonExpired=true]; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffed504: RemoteIpAddress: 127.0.0.1; SessionId: F5EAAB76CD6CC8530F3E7E844A13D635; Granted Authorities: CALCULATE_BALANCE, REGISTER_FOR_PUSH_NOTIFICATION, TOPUP_BY_POS, CAN_CONFIGURE_GIFTS, DISTRIBUTE_COUPON, ASSIGN_COUPON, LIST_COUPON_ASSIGNMENT, LIST_GIFT, BALANCE_HISTORY, LIST_PRODUCTS, LOCK_SERIAL, LIST_PROGRAMS, BALANCE
DEBUG: org.springframework.security.access.vote.AffirmativeBased - Voter: org.springframework.security.access.vote.RoleVoter@2059dcd9, returned: 0
DEBUG: org.springframework.security.access.vote.AffirmativeBased - Voter: org.springframework.security.access.vote.AuthenticatedVoter@6bb23b26, returned: 0
DEBUG: org.springframework.security.web.access.ExceptionTranslationFilter - Access is denied (user is not anonymous); delegating to AccessDeniedHandler
org.springframework.security.access.AccessDeniedException: Access is denied
at org.springframework.security.access.vote.AbstractAccessDecisionManager.checkAllowIfAllAbstainDecisions(AbstractAccessDecisionManager.java:70)
at org.springframework.security.access.vote.AffirmativeBased.decide(AffirmativeBased.java:88)
at org.springframework.security.access.intercept.AbstractSecurityInterceptor.beforeInvocation(AbstractSecurityInterceptor.java:205)
at org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor.invoke(MethodSecurityInterceptor.java:59)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
at com.foo.products.sva.cc.customer.controllers.AccountController$$EnhancerByCGLIB$$b72ae4b0.getBalance(<generated>)
我不知道为什么会发生这种情况。
答案 0 :(得分:2)
看起来你所有的AccessDecisionVoter
都没有投票授权(他们都弃权),因此你被拒绝访问。
这样做的原因是,默认情况下,作为默认配置一部分的RoleVoter
将仅响应以前缀&#34; ROLE _&#34;开头的权限。既然你们都不这样做,它就找不到它所知道的任何东西。 This FAQ has some more information
另一种方法是启用基于表达式的安全性,并使用@PreAuthorize
annotation代替,这更灵活。像
@PreAuthorize("hasRole('LIST_GIFT')")
如果您按照描述启用注释,应该可以开箱即用。
答案 1 :(得分:2)
问题在于,当您在会话中加载用户GrantedAuthority
元素时,您应该以不同方式命名它们以区分用户配置文件的权限。
ROLE
前缀PERM
前缀因此,您应将自己的权限命名为PERM_LIST_GIFT
,并使用hasAuthority
注释。我还建议将许可证作为CRUD;因此,对于列出礼物,您将有权阅读礼物:PERM_READ_GIFT。要改进此访问权限,您可以创建自定义注释,以指示某人有权访问(至少只读)您的礼物对象。类似的东西:
/**
* Grants permissions of accessing to Gifts module
*
*/
@Target(
{
ElementType.TYPE, ElementType.METHOD
})
@Component
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@PreAuthorize("hasAuthority('PERM_READ_GIFT')")
public @interface GiftsAuthorized
{
}
因此,您可以使用此功能注释所有功能,如果策略更改为访问您的礼品元素,您只需更改一次。它更好,更容易处理。