Grails 检查特定控制器操作的角色访问

Posted

技术标签:

【中文标题】Grails 检查特定控制器操作的角色访问【英文标题】:Grails check role access for specific controller action 【发布时间】:2014-08-24 07:25:24 【问题描述】:

我需要根据用户是否可以访问(通过角色定义)特定控制器/操作来显示/隐藏操作按钮。我正在使用 Spring Security 插件。

我的目标是为每个控制器的每个方法使用注释 @Secured("ROLE_..."),我正在寻找一种方法来检查,在调用操作之前,如果用户有权访问这个具体的动作。我猜有办法检查这一点,因为注释带来了信息,但我找不到任何解决方案。

在这个例子中,我试图找到 HASACCESS 方法:

带有@Secured注解的控制器

    class MyExampleController

      @Secured("ROLE_ADMIN")
      def myMethod() do stuff.. 

    

要包含链接的 html 代码

    <role:link controller="myExample" action="myMethod">Action</role:link>

还有我的 tagLib 角色

    class RoleTagLib 
     static namespace = "role"

      def link = attrs, body ->
        User user = (User) springSecurityService.currentUser          
        if(HASACCESS(user, attrs.controller, attrs.action))
          out << g.link(attrs, body)
        
      
    

我在this thread 中找到了包含在 SecurityTagLib 中的“hasAccess()”方法,但该方法受到保护,即使我用我的扩展 SecurityTagLib,此方法的调用也会返回“没有方法签名...” .我认为它使用了 Config.groovy 中定义的 interceptUrlMap 而不是注释。

编辑:我成功扩展了安全 tagLib 并使用了“hasAccess”方法,但它似乎只使用了 Config.groovy 中包含的 interceptUrlMap,并不关心我放在控制器中的注释。

【问题讨论】:

【参考方案1】:

使用

<sec:ifAllGranted roles="ROLE_ADMIN,ROLE_SUPERVISOR">
  secure stuff here
</sec:ifAllGranted>

<sec:ifAnyGranted roles="ROLE_ADMIN,ROLE_SUPERVISOR">
    secure stuff here
</sec:ifAnyGranted>

根据Spring Security Core Grails plugin documentation。

或者简单地将 Spring 安全核心标签库与您的标签库一起使用。

class RoleTagLib 
  static namespace = "role"

  SpringSecurityService springSecurityService

  def link =  attrs, body ->
    User user = (User) springSecurityService.currentUser          
    sec.ifAnyGranted(roles: 'ROLE_ADMIN,ROLE_SUPERVISOR')
      out << g.link(attrs, body)
    
  

【讨论】:

是的,SecurityTagLib 带来了这种检查角色的方式,但我尝试找到一种更“集中”且更轻松的方式来调整我的 .gsp 文件。我不想为每个 g:link 标签都放置这些测试,我想简单地将 g:link 替换为我的角色:link。 啊,我明白了。那么你是否尝试过简单地包装spring security taglib? 是的,我已经尝试过(根据我在帖子中提到的另一个线程),但我无法成功。似乎安全 tagLib 中的“hasAccess”方法使用 Config.groovy 中定义的interceptUrlMap 而不是注释,因为 sec:ifAnyGranted 通过阻止访问来工作,而“hasAccess”方法授予访问它应该阻止......它会强制我逐个 URL 定义每个特定角色允许的每次访问。【参考方案2】:

好的,我找到了解决方案。 SecurityTagLib 中的“hasAccess”方法基于 Config.groovy 中的 grails.plugins.springsecurity.securityConfigType。我的初始值是 SecurityConfigType.InterceptUrlMap 然后我会定义每个可访问的 url 并指定哪个角色可以在 grails.plugins.springsecurity.interceptUrlMap

解决办法是把它改成SecurityConfigType.Annotation,把interceptUrlMap修改成staticRules。然后方法“hasAccess”基于控制器中定义的注解,可以正确隐藏我的tagLib从SecurityTagLib包装的内容。

Config.groovy中有代码

    grails.plugins.springsecurity.securityConfigType = SecurityConfigType.Annotation
    grails.plugins.springsecurity.staticRules = [
      ... your rules ... for example:
      '/**': ['ROLE_ADMIN_ACCESS'] 
    ]

我的tagLib的代码

    class RoleTagLib extends SecurityTagLib 

        static namespace = "role"

        def link =  attrs, body ->
            if (hasAccess(attrs.clone(), "link")) 
                out << g.link(attrs, body)
            
        
    

我使用它来显示或隐藏我的 .gsp 文件中的任何链接,基于为每个控制器的每个操作放置的 @Secured 注释

    <role:link controller="myController" action="myAction">
      Action
    </role:link>

【讨论】:

如果你使用命名空间sec.,那么你不需要扩展SecurityTagLib。 if (sec.hasAccess(attrs.clone(), "true")) ... 至少对我有用。此外,使用字符串 true 可以清楚地表明任何非空字符串都可以。【参考方案3】:

这适用于 Grails 2.3

要检查来自另一个控制器或服务的操作访问,请执行以下操作:

@Secured(["ONE_OF_MY_ROLES"])
class SomeController 

    SecurityTagLib securityTagLib = (SecurityTagLib)Holders.grailsApplication.mainContext.getBean('grails.plugins.springsecurity.SecurityTagLib')

    def show() 
        def access = securityTagLib.hasAccess([controller: 'product', action: 'show'], 'access')
    

【讨论】:

以上是关于Grails 检查特定控制器操作的角色访问的主要内容,如果未能解决你的问题,请参考以下文章

Grails Spring Security UI、用户和​​角色管理访问

Grails with SpringSecurity,检查当前用户是不是可以访问控制器/动作

如何限制grails shiro security中的操作

基于角色的访问控制

Grails Spring 安全性

调用控制器操作时 Grails 视图挂起