【问题标题】:Spring security added prefix "ROLE_" to all roles name?Spring Security 为所有角色名称添加了前缀“ROLE_”?
【发布时间】:2016-01-17 06:11:51
【问题描述】:

我的网络安全配置中有此代码:

 @Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .authorizeRequests()
            .antMatchers("/api/**")
            .hasRole("ADMIN")
            .and()
            .httpBasic().and().csrf().disable();

}

所以我在我的数据库中添加了一个具有“ADMIN”角色的用户,当我尝试用这个用户登录时,我总是得到 403 错误,然后我为 spring 启用了日志,我发现了这一行:

2015-10-18 23:13:24.112 DEBUG 4899 --- [nio-8080-exec-1] o.s.s.w.a.i.FilterSecurityInterceptor    : Secure object: FilterInvocation: URL: /api/user/login; Attributes: [hasRole('ROLE_ADMIN')]

为什么 Spring Security 正在寻找“ROLE_ADMIN”而不是“ADMIN”?

【问题讨论】:

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


【解决方案1】:

Spring security 默认添加前缀“ROLE_”。

如果您想删除或更改此内容,请查看

How to change role from interceptor-url?

编辑:也发现了这个: Spring Security remove RoleVoter prefix

【讨论】:

  • 只是一个问题,如果我在@Secured注解中添加角色,Spring是否默认添加ROLE_?就像如果我添加@Secured("abc"),Spring 会检查 ROLE_abc 还是只检查 abc?
  • @SajibAcharya 您可以更改默认的ROLE_。请看stackoverflow.com/questions/38134121/…
【解决方案2】:

在 Spring 4 中,org.springframework.security.access.expression.SecurityExpressionRoot 类中定义了两个方法 hasAuthority()hasAnyAuthority()。这两种方法只检查您的自定义角色名称没有添加ROLE_ 前缀。定义如下:

public final boolean hasAuthority(String authority) {
    return hasAnyAuthority(authority);
}
public final boolean hasAnyAuthority(String... authorities) {
    return hasAnyAuthorityName(null, authorities);
}
private boolean hasAnyAuthorityName(String prefix, String... roles) {
    Set<String> roleSet = getAuthoritySet();

    for (String role : roles) {
        String defaultedRole = getRoleWithDefaultPrefix(prefix, role);
        if (roleSet.contains(defaultedRole)) {
            return true;
        }
    }

    return false;
}
private static String getRoleWithDefaultPrefix(String defaultRolePrefix, String role) {
    if (role == null) {
        return role;
    }
    if (defaultRolePrefix == null || defaultRolePrefix.length() == 0) {
        return role;
    }
    if (role.startsWith(defaultRolePrefix)) {
        return role;
    }
    return defaultRolePrefix + role;
}

示例用法:

<http auto-config="false" use-expressions="true" pattern="/user/**"
      entry-point-ref="loginUrlAuthenticationEntryPoint">
    <!--If we use hasAnyAuthority, we can remove ROLE_ prefix-->
    <intercept-url pattern="/user/home/yoneticiler" access="hasAnyAuthority('FULL_ADMIN','ADMIN')"/>
    <intercept-url pattern="/user/home/addUser" access="hasAnyAuthority('FULL_ADMIN','ADMIN')"/>
    <intercept-url pattern="/user/home/addUserGroup" access="hasAuthority('FULL_ADMIN')"/>
    <intercept-url pattern="/user/home/deleteUserGroup" access="hasAuthority('FULL_ADMIN')"/>
    <intercept-url pattern="/user/home/**" access="hasAnyAuthority('FULL_ADMIN','ADMIN','EDITOR','NORMAL')"/>
    <access-denied-handler error-page="/403"/>
    <custom-filter position="FORM_LOGIN_FILTER" ref="customUsernamePasswordAuthenticationFilter"/>
    <logout logout-url="/user/logout"
            invalidate-session="true"
            logout-success-url="/user/index?logout"/>
    <!-- enable csrf protection -->
    <csrf/>
</http>   <beans:bean id="loginUrlAuthenticationEntryPoint"
            class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
    <beans:constructor-arg value="/user"/>
</beans:bean>

【讨论】:

    【解决方案3】:

    正如@olyanren 悲伤的那样,您可以在 Spring 4 中使用 hasAuthority() 方法而不是 hasRole()。我正在添加 JavaConfig 示例:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        .authorizeRequests()
        .antMatchers("/api/**")
        .access("hasAuthority('ADMIN')")
        .and()
        .httpBasic().and().csrf().disable();
    }
    

    【讨论】:

      【解决方案4】:

      您可以创建一个映射器以在所有角色的开头添加ROLE_

      @Bean
      public GrantedAuthoritiesMapper authoritiesMapper() {
          SimpleAuthorityMapper mapper = new SimpleAuthorityMapper();
          mapper.setPrefix("ROLE_"); // this line is not required 
          mapper.setConvertToUpperCase(true); // convert your roles to uppercase
          mapper.setDefaultAuthority("USER"); // set a default role
      
          return mapper;
      }
      

      您应该将映射器添加到您的提供程序:

      @Bean
      public DaoAuthenticationProvider authenticationProvider() {
          DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
          // your config ...
          provider.setAuthoritiesMapper(authoritiesMapper());
      
          return provider;
      }
      

      【讨论】:

        【解决方案5】:

        _ROLE 前缀被 spring security 用来标识它是一个角色。一个角色有一组权限,也就是权限,这些权限为一个角色定义了不同的权限。 例如:- EDIT_PROFILE、DELETE_PROFILE

        您可以定义角色和权限,如果您要定义角色,则必须以“ROLE_”为前缀

        在您的情况下,您正在寻找一个角色,因此默认情况下,spring security 会寻找一个以“ROLE_”为前缀的字符串。

        【讨论】:

          猜你喜欢
          • 2015-07-20
          • 2012-01-09
          • 2022-01-10
          • 2014-01-14
          • 2020-06-10
          • 2016-11-03
          • 1970-01-01
          • 2012-04-26
          • 2020-07-01
          相关资源
          最近更新 更多