无法在 Spring Security 中获取 @Secured Method Security 注释

Posted

技术标签:

【中文标题】无法在 Spring Security 中获取 @Secured Method Security 注释【英文标题】:Can not get the @Secured Method Security annotations working in Spring Security 【发布时间】:2015-05-30 07:37:27 【问题描述】:

我做了很多研究,在我看来一切都正确......但我无法让它发挥作用!有人知道吗?

无论我做什么,相关映射对任何人都是公开的(匿名或登录,无论他们拥有什么角色)。

理想情况下,我希望所有请求都是公开的,除了那些由 @Secured() 注释的请求 - 显然只有具有特定角色的用户才能访问这些映射。

这可能吗?

仅供参考,作为一种解决方法,我目前构建了一个方法“hasRole(String role)”,它检查登录用户的角色,如果该方法返回 false,则抛出 NotAuthorizedException(自定义)。

用户详情

  @Override
  public Collection<? extends GrantedAuthority> getAuthorities() 

      List<GrantedAuthority> grantedAuthorities = null;

      System.out.print("Account role... ");
      System.out.println(account.getRole());

      if (account.getRole().equals("USER")) 
          GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_USER");
          grantedAuthorities = Arrays.asList(grantedAuthority);
      

      if (account.getRole().equals("ADMIN")) 
          GrantedAuthority grantedAuthorityUser = new SimpleGrantedAuthority("ROLE_USER");
          GrantedAuthority grantedAuthorityAdmin = new SimpleGrantedAuthority("ROLE_ADMIN");
          grantedAuthorities = Arrays.asList(grantedAuthorityUser, grantedAuthorityAdmin);
      

      return grantedAuthorities;
  

安全配置

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter 

    @Autowired
    private AuthFailure authFailure;

    @Autowired
    private AuthSuccess authSuccess;

    @Autowired
    private EntryPointUnauthorizedHandler unauthorizedHandler;

    @Autowired
    private UserDetailsServiceImpl userDetailsService;

    /*@Autowired
    public void configAuthBuilder(AuthenticationManagerBuilder builder) throws Exception 
        builder.userDetailsService(userDetailsService);
    */

    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception 
        return super.authenticationManagerBean();
    

    @Autowired
    @Override
    public void configure(AuthenticationManagerBuilder builder) throws Exception 
        builder.userDetailsService(userDetailsService);
    

  private CsrfTokenRepository csrfTokenRepository() 
    HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
    repository.setHeaderName("X-XSRF-TOKEN");
    return repository;
  

    @Override
    public void configure(HttpSecurity http) throws Exception 
      http.csrf().csrfTokenRepository(csrfTokenRepository())
        .and().exceptionHandling().authenticationEntryPoint(unauthorizedHandler)
        .and().formLogin().loginPage("/login").successHandler(authSuccess).failureHandler(authFailure)
        //.and().authorizeRequests().antMatchers("/rest/**").authenticated()
        //.and().authorizeRequests().antMatchers("/**").permitAll()
        .and().addFilterAfter(new CsrfHeaderFilter(), CsrfFilter.class);;
    

帐户控制器

  @Secured("ROLE_USER")
  @RequestMapping(method = RequestMethod.GET)
  public List<Account> getAllAccounts(@RequestParam(value = "mail", required = false) String mail) 

谢谢!

【问题讨论】:

请您告诉我们您的映射是什么样的?它是在控制器上全局定义的,还是你有任何用 @RequestMapping(...) 注释的方法? 我已经用@RestController 和@RequestMapping('rest/accounts') 注释了我的AccountController 类。我已在原始帖子中添加了此代码。然后我为每个方法分别设置@RequestMapping(例如@RequestMapping(value=/id, method=RequestMethod.GET) 您可以使用@EnableWebMvcSecurity 启用mvc 安全并重试吗? 【参考方案1】:

您可以通过 Spring HttpSecurity 使用 Controller 范围的安全性。尝试将此添加到您的配置方法中:

.antMatchers("rest/accounts*").hasRole("ADMIN")

如果您希望公开任何请求(真的吗?):

.anyRequest().permitAll()

当您从任何地方访问它时,您还可以在 UserDetailsS​​ervice 中保护您的 Methodinvocation for Example:

@Secured("ROLE_USER")
public getAllAccounts(...)...

只有这样你才需要注释你的 SecurityConfig:

@EnableGlobalMethodSecurity(securedEnabled = true)

在实践中,我们建议您在服务中使用方法安全性 层,用于控制对您的应用程序的访问,而不是完全依赖 关于使用在 Web 应用程序中定义的安全约束 等级。 URL 发生变化,很难考虑到所有 应用程序可能支持的可能 URL 以及请求可能如何 被操纵。您应该尝试限制自己使用一些 简单易懂的蚂蚁路径。总是尝试使用 一个“默认拒绝”的方法,你有一个包罗万象的通配符( / 或 ) 最后定义并拒绝访问。服务中定义的安全性 层更健壮且更难绕过,因此您应该始终 利用 Spring Security 的方法安全选项。

见:http://docs.spring.io/autorepo/docs/spring-security/4.0.0.CI-SNAPSHOT/reference/htmlsingle/#request-matching

【讨论】:

嗯。显然,控制器应该是完全安全的,是的。但对于其他 API,我希望 GET 请求保持公开状态,并保护 PUT/POST/DELETE 请求。我想我可以将我的 API 拆分为 /public/、/private/ 和 /admin/ 路由,然后使用 configure() 方法中的 HttpSecurity 正确保护它们。那应该行得通。但我仍然很好奇为什么我不能在我的控制器中使用 @Secured 注释。 :) 另外 - 你是对的,我可以使用 @Secured 保护我的服务类中的方法,这很有效。例如。当我在“getAllAccounts”上执行此操作时,安全性就会启动,我只能在以正确角色登录时获取数据。但是为什么我只能保护我的 Service 类方法,而不能保护我的 RestController?这是故意的吗?我发现了很多例子,人们也保护他们的控制器,所以认为这应该是可能的? 它是有意和推荐的。您可以在这里查看:docs.spring.io/autorepo/docs/spring-security/4.0.0.CI-SNAPSHOT/… 您要保护的方法是处理程序方法,由 Request(Mapping) 调用。如果您在控制器中有其他方法,您可以使用@Secured Annotation。 嘿 - 即使我设法通过保护服务类方法来解决这个问题,我仍然不明白为什么我不能保护我的控制器类中的方法(我的 GET/PUT/POST/DELETE 处理程序)。文档中没有任何内容说不应该这样做,而且我一如既往地在这个例子中看到很多例子。 :S @Joachim 实际上你可以使用 http.antMatchers(HttpMethod.POST, "/rest/accounts*").hasRole(... 管理方法【参考方案2】:

在这里,我想根据 sven.kwiotek 的上述正确答案添加一些内容。如果在ROLE表中你还想用“USER”、“ADMIN”……解决方法也很简单:

从数据库中获取角色时,不要忘记手动添加“ROLE_”前缀,例如,

List<GrantedAuthority> authorities = user.getRoles().stream().map(role -> 
    new SimpleGrantedAuthority("ROLE_" + role.getRole()))
    .collect(Collectors.toList());

然后您可以在控制器方法中安全地使用注解@Secured("ROLE_USER")

原因是org.springframework.security.access.vote.RoleVoter 类中的所有角色都应以ROLE_ 前缀开头。

【讨论】:

以上是关于无法在 Spring Security 中获取 @Secured Method Security 注释的主要内容,如果未能解决你的问题,请参考以下文章

无法在 Spring Security 登录事件侦听器中获取“记住我”用户的会话 ID

我无法获取在线用户列表是 spring security

使用 spring 4 获取“无法找到 XML 模式命名空间 [http://www.springframework.org/schema/security] 的 Spring NamespaceHa

获取 Spring Security 中的所有登录用户

资源服务器获取用户信息,java - Spring Security OAuth2资源服务器无法获取包含详细信息的主体 - 堆栈内存溢出...

资源服务器获取用户信息,java - Spring Security OAuth2资源服务器无法获取包含详细信息的主体 - 堆栈内存溢出...