【问题标题】:Using Java config with Spring Security for annotation-based role checks and Basic HTTP Auth使用带有 Spring Security 的 Java 配置进行基于注释的角色检查和基本 HTTP Auth
【发布时间】:2014-11-25 13:17:00
【问题描述】:

我正在尝试在我的一个控制器上完成基于注释的(使用@PreAuthorize)权限检查。我正在使用 Java 配置,并且有一个 SecurityConfig 类扩展 WebSecurityConfigurerAdapter

我还使用基本 HTTP 身份验证来获取需要授权的方法。

但是 - 问题是,我希望 SecurityConfig 确定哪些方法需要使用 antPattern() 或类似的身份验证。这就是注释的用途!

如何配置我的SecurityConfig 类,以便它正确使用HTTP Basic 身份验证和配置的AuthenticationManager 用于具有@PreAuthorize 的方法,并允许匿名访问的控制器方法是否附加了任何安全注释?

当我尝试这个时(尝试 #1):

@Configuration
@EnableWebSecurity
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
    }

    @Autowired
    public void registerGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("craig").password("craigpass").roles("USER");
    }
}

我未受保护的方法失败:

Full authentication is required to access this resource

而我的受保护(但经过正确验证)测试失败:

Error: Expected CSRF token not found. Has your session expired?

当我尝试这个时(尝试 #2):

@Configuration
@EnableWebSecurity
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public void registerGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("craig").password("craigpass").roles("USER");
    }
}

我的未受保护方法失败并显示302 状态代码,并重定向到/login,而我的受保护/身份验证方法失败并显示:

Error: Expected CSRF token not found. Has your session expired?

当我尝试这个时(尝试 #3):

@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests().anyRequest().authenticated().and().httpBasic();
    }

    @Autowired
    public void registerGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("craig").password("craigpass").roles("USER");
    }
}

我的身份验证方法可以正常工作。 (呜呼!)但是,我的不受保护的方法因401 而失败,因为我的HttpSecurity 似乎已配置为在您通过身份验证时允许访问 - 无论控制器方法是否带有注释@PreAuthorize.

当我尝试这个时(尝试 #4):

@Configuration
@EnableWebSecurity
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests().anyRequest().permitAll();
    }

    @Autowired
    public void registerGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("craig").password("craigpass").roles("USER");
    }
}

我未受保护的方法正常工作(允许访问),但我的身份验证方法(无论它们是否具有正确的 HTTP 身份验证)失败,状态码为 403

Error: Access Denied

我的身份验证测试方法使用 403 失败并使用 MockMvc 并使用标头发送请求:

{Content-Type=[application/json], Accept=[application/json], Authorization=[Basic Y3JhaWc6Y3JhaWdwYXNz]}

我已经解码和验证的,以及带有方法POST的URL/api/item,它应该针对相应的方法:

@RequestMapping(value = "/api/item", method = { RequestMethod.POST })
@PreAuthorize("hasRole('ROLE_USER')")
public void postNewItem(HttpServletRequest request, HttpServletResponse response) {
    ...
}

【问题讨论】:

    标签: java spring spring-mvc authentication spring-security


    【解决方案1】:

    我做过类似的事情,唯一的区别是我有一些非常定制的身份验证方法。如果您只想检查用户角色,则应在控制器方法上使用 @Secured 而不是 @PreAuthorize,例如

    @Secured({"ROLE_SOMEROLE"})
    public void doSomething(...) {
    }
    

    角色在AuthenticationProvider 中设置为SimpleGrantedAuthorityUsernamePasswordAuthenticationToken 的列表。 下面是配置类:

    @Configuration
    @EnableWebMvcSecurity
    @EnableGlobalMethodSecurity(securedEnabled=true)
    public class SecurityConfig  extends WebSecurityConfigurerAdapter {
    
    @Autowired
    private AuthenticationProvider authProvider;
    
    @Autowired
    private AuthenticationEntryPoint authenticationEntryPoint;
    
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.authenticationProvider(authProvider);
    }
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // Had some other calls for CORS ajax requests.
        http.authorizeRequests()
                .antMatchers("/logout")
                .permitAll()
                .anyRequest()
                .authenticated()
                .and()
                .httpBasic()
                .authenticationEntryPoint(authenticationEntryPoint)
                .csrf()
                .disable();
    }
    
    }
    

    如果您的方法使用@Secured 注释并且当前用户没有指定角色,则客户端将收到403 响应,否则请求将通过。如果您尝试运行单元测试,您可以在您的 bean 上使用 @Profile('test') 并将 AuthenticationProvider 与硬编码数据一起使用。这是关于这种方法的帖子: https://spring.io/blog/2011/02/14/spring-3-1-m1-introducing-profile/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-10
      • 2021-01-27
      • 1970-01-01
      • 2014-05-26
      • 2016-10-14
      • 2019-08-08
      • 2020-12-18
      • 2020-06-16
      相关资源
      最近更新 更多