【问题标题】:Spring Security, Method Security annotation (@Secured ) is not working (java config)Spring Security,方法安全注释(@Secured)不起作用(java config)
【发布时间】:2015-09-20 02:47:00
【问题描述】:

我正在尝试使用 @Secured("ADMIN") 设置方法安全注释(没有任何 XML,只有 java 配置,Spring Boot)。但是通过角色访问不起作用。

安全配置:

@Configuration
@EnableWebSecurity
public class AppSecurityConfiguration extends WebSecurityConfigurerAdapter{

.....

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers("/api/**").fullyAuthenticated().and()
                .addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    }

.....

}

我想限制对控制器方法的访问:

@RestController
@RequestMapping("/api/groups")
public class GroupController {

    @Autowired
    private GroupService groupService;

    @Secured("ADMIN")
    @RequestMapping
    public List<Group> list() {
        return groupService.findAll();
    }

}

通过 url 限制访问有效,使用:

.antMatchers("/api/**").hasAuthority("ADMIN")

也许我忘了指定我要按角色进行限制?

统一更新: 按照规则,@PreAuthorize("hasRole('ADMIN')")必须在Controller层还是Service层的哪一层?

【问题讨论】:

  • 什么不起作用?浏览器是否没有尝试对您进行身份验证?它会忽略您提供的凭据吗?顺便说一句:您还应该发布将用户映射到管理员组的位置,也许这​​是有问题的区域。
  • 身份验证工作正常,但任何角色的任何用户都可以访问“/api/groups”
  • 你在哪里设置 ROLE 'ADMIN',你能告诉我吗??
  • 尽管角色定义正确:org.springframework.security.authentication.UsernamePasswordAuthenticationToken: Principal: SecurityUser; Credentials: [PROTECTED]; Authenticated: true; Details: null; Granted Authorities: ADMIN
  • 在这里您可以看到权限实际上是 ADMIN 而不是 ROLE_ADMIN。因为 RoleVoter 检查以ROLE_ 开头的权限,所以找不到您的权限(即ADMIN),因此弃权

标签: java spring security spring-security spring-boot


【解决方案1】:

欢迎添加

@EnableGlobalMethodSecurity(securedEnabled = true)

此元素用于在您的应用程序中启用基于注释的安全性(通过在元素上设置适当的属性),并将安全切入点声明组合在一起,这些声明将应用于您的整个应用程序上下文,专门针对@Secured。 因此你的代码应该是这样的

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class AppSecurityConfiguration extends WebSecurityConfigurerAdapter{..

【讨论】:

  • 对特别secureEnabled = true进行了编辑
  • 我正在尝试这个,但这不能正常工作,即弹簧响应“访问被拒绝”
  • 让我们做一些分析,在 Secured("ADMIN") 下添加@RequestMapping 的任何幸存原因
  • 有什么进展吗?您是否尝试删除 @Secured("ADMIN") 下方的 @RequestMapping
  • 如果您取得了任何进展,或者解决方案是否在建议的解决方案的帮助下得到解决,请告诉我,然后请接受答案以结束问题
【解决方案2】:

我知道这个帖子已经很老了,我的回答暗示了这个帖子中不同人的部分答案;但这里是一个包含陷阱和答案的列表:

  1. 使用@Secured 时,角色名称为(例如)ADMIN;这意味着@Secured("ROLE_ADMIN") 的注释。
  2. WebSecurityConfigurerAdapter 必须有 @EnableGlobalMethodSecurity(securedEnabled = true)
  3. 与大多数与 Spring 相关的代理一样,确保类和安全方法不是最终的。对于 Kotlin,这意味着“打开”每个方法以及类。
  4. 当类及其方法是虚拟的(“开放”)时,就不需要接口了。

这是一个工作 Kotlin 示例的一部分:

@RestController
@RequestMapping("api/v1")

    open class DiagnosticsController {
        @Autowired
        lateinit var systemDao : SystemDao

        @RequestMapping("ping", method = arrayOf(RequestMethod.GET))
        @Secured("ROLE_ADMIN")
        open fun ping(request : HttpServletRequest, response: HttpServletResponse) : String { ... 
    }

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
open class WebSecurityConfig : WebSecurityConfigurerAdapter() {

问候

【讨论】:

  • 在 kotlin 中你需要打开控制器类和方法,否则你会得到 --> 原因:java.lang.IllegalArgumentException: Cannot subclass final class
【解决方案3】:

控制器上的方法安全性不起作用的原因可能有很多。

首先,因为它从未在 Spring Security 手册中被引用为示例……开玩笑,但将 Spring 工具带到他们不想去的地方可能会很棘手。

更严重的是,您应该启用@Mudassar 已经说过的方法安全性。手册说:

我们可以在任何@Configuration 实例上使用@EnableGlobalMethodSecurity 注释来启用基于注释的安全性。例如,以下将启用 Spring Security 的 @Secured 注释。

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class MethodSecurityConfig {
   // ...
}

请注意,Mudassar 的回答到此为止都是正确的。

但方法安全性基于 AOP,默认情况下在 接口 上使用 JDK 代理。这就是所有示例都在服务层应用方法安全性的原因,因为服务类通常作为接口注入到控制器中。

你当然可以在控制器层使用它,但是:

  • 您的所有控制器都为您实现所有@Secured 注释方法的接口
  • 或者您必须切换到类代理

我尝试遵循的规则是:

  • 如果我想保护 URL,我坚持使用 HTTPSecurity
  • 如果我需要允许更细粒度的访问,我会在服务层添加安全性

【讨论】:

  • 只使用 HTTP 安全的缺点是通常在控制器中使用请求相关的注解(如@GetMapping@POST 等)定义 URL。但是,角色映射的 URL 被放置在单独的 HTTP 安全配置类中。一旦控制器中的 URL 发生更改,它实际上会失去其当前的角色要求,除非您也更改安全配置中的 URL。如果方法被注释,它们不会意外丢失角色信息。
【解决方案4】:

这个问题已经解决了。

我加@EnableGlobalMethodSecurity(prePostEnabled = true)

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class AppSecurityConfiguration extends WebSecurityConfigurerAdapter{
}

在控制器中,我将 @Secured("ADMIN") 更改为 @PreAuthorize("hasRole('ADMIN')")

【讨论】:

  • 根据@user1210708 的回答,@Secured("ROLE_ADMIN") 应该同样适用于@EnableGlobalMethodSecurity 注释中设置的securedEnabled=true 标志。
  • securedEnabled=true 对我不起作用:无论用户角色如何,Spring 都授予对控制器的访问权限。相反,我使用了prePostEnabled = true 并将@Secured 替换为@PreAuthorize 并且它起作用了。魔法!
【解决方案5】:

我想分享我的决定,可能会有所帮助。

使用spring mvc + spring security,版本4.2.9.RELEASE

例如,我有一个带有 @Secured 注释方法的服务

@Secured("ACTION_USER_LIST_VIEW")
List<User> getUsersList();

但是,它不起作用,因为 GlobalMethodSecurityConfiguration 有内部方法。

protected AccessDecisionManager accessDecisionManager()

其中用默认的rolePrefix = "ROLE_"; 初始化了new RoleVoter() (这使得无法使用bean 来设置你的角色前缀) 这给了我们无效的注释,因为RoleVoter 需要以 'ROLE_'

开头的注释值

为了解决这个问题,我像这样覆盖 GlobalMethodSecurityConfiguration

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class AppMethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
    @Override
    protected AccessDecisionManager accessDecisionManager() {
        List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList<>();
        ExpressionBasedPreInvocationAdvice expressionAdvice = new ExpressionBasedPreInvocationAdvice();
        expressionAdvice.setExpressionHandler(getExpressionHandler());
        decisionVoters.add(getRoleVoter());
        decisionVoters.add(new AuthenticatedVoter());
        return new AffirmativeBased(decisionVoters);
    }

    private RoleVoter getRoleVoter() {
        RoleVoter e = new RoleVoter();
        e.setRolePrefix("");
        return e;
    }
}

【讨论】:

    【解决方案6】:

    您需要使用@secured(ROLE_ADMIN) 而不是@secured(ADMIN)。您需要在角色名称前写上“ROLE_”。请找到下面提到的示例,该示例确保只有具有管理员角色的用户才能访问 list() 方法。

    @RestController
    @RequestMapping("/api/groups")
    public class GroupController {
    
        @Autowired
        private GroupService groupService;
    
        @Secured("ROLE_ADMIN")
        @RequestMapping
        public List<Group> list() {
            return groupService.findAll();
        }
    
    }
    

    【讨论】:

      【解决方案7】:

      也许您应该将 AppSecurityConfiguration 注册到与 WebMvcConfig(扩展 WebMvcConfigurerAdapter)相同的上下文。

      AnnotationConfigWebApplicationContext mvcContext = new AnnotationConfigWebApplicationContext();      
      mvcContext.register(WebMvcConfig.class, SecurityConfig.class);
      

      【讨论】:

        猜你喜欢
        • 2021-09-27
        • 2012-01-01
        • 2018-02-22
        • 1970-01-01
        • 1970-01-01
        • 2012-01-12
        • 2015-05-30
        • 2021-12-15
        • 2013-10-21
        相关资源
        最近更新 更多