当前位置: 首页 > 知识库问答 >
问题:

将Spring Security全局方法安全性与KeyClope集成

松俊才
2023-03-14

我在使用Spring Security的前/后授权注释和与Keycloak集成的Servlet API时遇到了问题。我调查了很多文章、教程和以下问题,但没有进一步的运气:

  • 使用KeyClope在servlet应用程序中获取用户角色
  • Spring Boot Key斗篷-如何获得分配给用户的角色列表
  • 将Spring Security注释与KeyClope一起使用
  • Spring Boot Spring Security分层角色
  • 如何向Spring Boot项目添加基于方法的安全性
  • 使用Spring Security Java Config配置DefaultMethodSecurityExpressionHandler
  • 基于SpringBoot方法的分层角色安全:需要ServletContext

我想要的只是删除ROLES_前缀,使用分层角色和一种舒适的方式来检索用户的角色。

到目前为止,我可以在控制器中检索这样的层次角色,但不能使用注释:

@Controller
class HomeController {

    @Autowired
    AccessToken token

    @GetMapping('/')
    def home(Authentication auth, HttpServletRequest request) {
        // Role 'admin' is defined in Keycloak for this application
        assert token.getResourceAccess('my-app').roles == ['admin']
        // All effective roles are mapped
        assert auth.authorities.collect { it.authority }.containsAll(['admin', 'author', 'user'])

        // (!) But this won't work:
        assert request.isUserInRole('admin')
    }

    // (!) Leads to a 403: Forbidden
    @GetMapping('/sec')
    @PreAuthorize("hasRole('admin')") {
        return "Hello World"
    }

}

我猜,@PreAuthorize注释不起作用,因为Servlet方法不成功。

在KeyCloak和Spring中只有三个角色-管理员、作者、用户定义:

enum Role {
    USER('user'),
    AUTHOR('author'),
    ADMIN('admin')

    final String id

    Role(String id) {
        this.id = id
    }

    @Override
    String toString() {
        id
    }
}

密钥斗篷配置

在删除@EnableGlobalomeodSecurity注释后,此Web安全揭示了创建名为'resourceHandlerMap'的bean的错误,该错误是由No ServletContext set错误引起的-没有线索,这是从哪里来的!

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    /**
     * Registers the KeycloakAuthenticationProvider with the authentication manager.
     */
    @Autowired
    void configureGlobal(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(keycloakAuthenticationProvider().tap { provider ->
            // Assigns the Roles via Keycloaks role mapping
            provider.grantedAuthoritiesMapper = userAuthoritiesMapper
        })
    }

    @Bean
    RoleHierarchyImpl getRoleHierarchy() {
        new RoleHierarchyImpl().tap {
            hierarchy = "$Role.ADMIN > $Role.AUTHOR > $Role.USER"
        }
    }

    @Bean
    GrantedAuthoritiesMapper getUserAuthoritiesMapper() {
        new RoleHierarchyAuthoritiesMapper(roleHierarchy)
    }

    SecurityExpressionHandler<FilterInvocation> expressionHandler() {
        // Removes the prefix
        new DefaultWebSecurityExpressionHandler().tap {
            roleHierarchy = roleHierarchy
            defaultRolePrefix = null
        }
    }

    // ...

    @Bean
    @Scope(scopeName = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
    AccessToken accessToken() {
        def request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()
        def authToken = (KeycloakAuthenticationToken) request.userPrincipal
        def securityContext = (KeycloakSecurityContext) authToken.credentials

        return securityContext.token
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        super.configure(http)
        http
            .authorizeRequests()
            .expressionHandler(expressionHandler())
            // ...
    }

}

全局方法安全配置

我需要显式地允许allow bean definition overriding,因为否则我得到了一个bean,它的名称已经定义了错误,这表明我完全失去了对整个情况的控制,不知道发生了什么。

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
class GlobalMethodSecurityConfig extends GlobalMethodSecurityConfiguration {

    @Autowired
    RoleHierarchy roleHierarchy

    @Override
    protected MethodSecurityExpressionHandler createExpressionHandler() {
        ((DefaultMethodSecurityExpressionHandler)super.createExpressionHandler()).tap {
            roleHierarchy = roleHierarchy
            defaultRolePrefix = null
        }
    }
}

还有其他重要的配置吗?非常感谢你的帮助!


共有2个答案

林星华
2023-03-14

除了(docs.spring.io)中提供的建议禁用角色前缀,以及M.Deinum提供的建议外,在使用KeyDopperWebSecurity配置适配器时还需要再做一次修改

在configureGlobal方法中,grantedAuthoritiesMapper bean是在bean keyDopperAuthenticationProvider中设置的。在grantedAuthoritiesMapper中,前缀可以设置为任何您想要的值,其中默认值为“角色”。

代码如下:

    @Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider();

    SimpleAuthorityMapper grantedAuthoritiesMapper = new SimpleAuthorityMapper();
    grantedAuthoritiesMapper.setPrefix("");
    keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(grantedAuthoritiesMapper);
    auth.authenticationProvider(keycloakAuthenticationProvider);
}

这个解决方案对我有效。

司空叶五
2023-03-14

正如M.Deinum所指出的,必须使用BeanPostProcessor在多个位置删除defaultRolePrefix,这在(docs.spring.io)Disable ROLE_uprefication中进行了解释。

这种方法对我来说似乎不太干净,所以我写了一个自定义的AuthoritiesMapper来实现从Keycloak映射层次角色,而不需要将它们重命名为ROLE_Spring标准。首先,对Roles枚举进行了修改,以符合应用程序范围内的标准:

enum Role {
    USER('ROLE_USER'),
    AUTHOR('ROLE_AUTHOR'),
    ADMIN('ROLE_ADMIN')

    // ...
}

其次,我用前缀层次化实现替换了RoleHierarchyAuthoritiesMapper

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter {

    // ..

    // Replaces the RoleHierarchyAuthoritiesMapper
    @Bean
    GrantedAuthoritiesMapper getUserAuthoritiesMapper() {
        new PrefixingRoleHierarchyAuthoritiesMapper(roleHierarchy)
    }

}
class PrefixingRoleHierarchyAuthoritiesMapper extends RoleHierarchyAuthoritiesMapper {

        String prefix = 'ROLE_'

        PrefixingRoleHierarchyAuthoritiesMapper(RoleHierarchy roleHierarchy) {
            super(roleHierarchy)
        }

        @Override
        Collection<? extends GrantedAuthority> mapAuthorities(Collection<? extends GrantedAuthority> authorities) {
            def prefixedAuthorities = authorities.collect { GrantedAuthority originalAuthority ->
                new GrantedAuthority() {
                    String authority = "${prefix}${originalAuthority.authority}".toUpperCase()
                }
            }

            super.mapAuthorities(prefixedAuthorities)
        }
    }

最后,我摆脱了GlobalFarodSecurityConfig

 类似资料:
  • 我在尝试在Spring Boot应用程序中启用全局方法安全性时遇到了一些问题。或多或少我有这样的配置: @Secure注释在服务中工作正常,但在控制器中不行,所以我读到这里(http://docs.spring.io/spring-security/site/faq/faq.html#faq-method-security-in-web-context)我认为这是因为方法安全性只在根应用程序上下文

  • 问题内容: 最近,我遇到了Python pickle和cPickle模块的安全性问题。显然,除非您将find_class方法作为基本修改来覆盖以获得更多的安全性,否则在pickle中并没有实现真正的安全性措施。但是我经常听到JSON更安全。 谁能详细说明一下?为什么JSON比pickle更加安全? 非常感谢!标记 问题答案: json更安全,因为它从根本上更加有限。唯一的蟒蛇类型的JSON文档可以

  • Kuberentes 支持多租户,这就需要对集群的安全性进行管理。

  • 全局属性 全局属性通过 fis.set 设置,通过 fis.get 获取; 内置的默认配置 var DEFAULT_SETTINGS = { project: { charset: 'utf8', md5Length: 7, md5Connector: '_', files: ['**'], ignore: ['node_modules/**', 'ou

  • 1.远程执行命令 1.1 危险命令检测. gossh将危险的命令放到黑名单中,一旦远程执行危险命令,会自动退出,通过指定-f参数强制执行。危险命令目前收录如下: "mount", "umount", "rm", "mkfs", "mkfs.ext3", "make.ext2", "make.ext4", "make2fs", "shutdown", "reboot", "init", "dd"

  • 当我使用security.basic.enabled=false在具有以下依赖项的Spring Boot项目上禁用安全性时: 为了修复此异常,我必须添加属性-management.security.enabled=false。我的理解是,当执行器在类路径中时,应该将security.basic.enabled=false和management.security.enabled=false设置为禁用