无法获得在 Spring 安全中工作的 @Secured 方法安全注释

Can not get the @Secured Method Security annotations working in Spring Security

我做了很多研究,对我来说一切看起来都是正确的...但我无法让它工作!有人知道吗?

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

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

这可能吗?

仅供参考,作为一种解决方法,我目前构建了一个方法 "hasRole(String role)",它检查登录用户的角色,如果方法 returns 为假,则抛出 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) {

谢谢!

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

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

如果您希望任何请求成为 public(真的吗?):

.anyRequest().permitAll()

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

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

只有这样,您才需要使用以下内容注释您的 SecurityConfig:

@EnableGlobalMethodSecurity(securedEnabled = true)

In practice we recommend that you use method security at your service layer, to control access to your application, and do not rely entirely on the use of security constraints defined at the web-application level. URLs change and it is difficult to take account of all the possible URLs that an application might support and how requests might be manipulated. You should try and restrict yourself to using a few simple ant paths which are simple to understand. Always try to use a"deny-by-default" approach where you have a catch-all wildcard ( / or ) defined last and denying access. Security defined at the service layer is much more robust and harder to bypass, so you should always take advantage of Spring Security’s method security options.

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

在此,我想根据sven.kwiotek的上述正确答案补充一些内容。如果在ROLEtable中你还想用"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 class中所有角色都应该以ROLE_前缀开头。