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

Posted

技术标签:

【中文标题】Grails with SpringSecurity,检查当前用户是不是可以访问控制器/动作【英文标题】:Grails with SpringSecurity, check if the current user can access controller / actionGrails with SpringSecurity,检查当前用户是否可以访问控制器/动作 【发布时间】:2011-01-19 08:58:37 【问题描述】:

我目前正在为我的应用程序开发一个菜单,该菜单应该能够仅显示当前用户可以访问的控制器(在数据库中定义的请求图)。

如何检查当前用户是否有权访问特定的控制器和操作?

【问题讨论】:

【参考方案1】:

不确定最初提出此问题时的情况,但现在您可以使用 SpringSecurityUtils.ifAllGranted() 检查用户是否处于特定角色中,该字符串采用逗号分隔的角色列表。如果当前用户属于所有用户,则返回true。

if(SpringSecurityUtils.ifAllGranted('ROLE_ADMIN,ROLE_USER')) 

显然,如果您只需要一个角色,您可以简单地将其传递给函数。 SpringSecurityUtils 也有 ifAnyGrantedifNotGranted 等方法,所以它应该适用于你想要完成的任何事情。

SpringSecurityUtils 是一个静态 API,因此您无需创建名为 springSecurityUtils 或类似名称的私有成员。

【讨论】:

【参考方案2】:

查看视图中的角色: Spring安全插件提供ifAllGranted、ifAnyGranted、ifNoneGranted等标签来检查角色

例如,检查登录用户的管理员角色:

<sec:ifLoggedIn>
    <sec:ifAllGranted roles="ROLE_ADMIN">
        Admin resource
     </sec:ifAllGranted>
</sec:ifLoggedIn>

(在 grails-2.2.2 和 springSecurityCorePlugin-1.2.7.3 中测试)

【讨论】:

...然后还有&lt;sec:ifAnyGranted roles="ROLE_ADMIN, ROLE_SUPER_ADMIN"&gt;【参考方案3】:

这个问题已经很老了,但我想我至少会发布一个似乎适用于 Grails 2.0 的答案。如果您使用的是 spring 安全插件,则包含一个名为 grails.plugins.springsecurity.SecurityTagLib 的标签库。

标签库有一个受保护的方法,hasAccess(),它可以采用与 g:link 标签相同的参数映射。因此,如果您扩展 SecurityTagLib,您可以调用 hasAccess() 并获得您想要的行为。为什么不将其外部化到可以注入的服务中,我无法理解,因为该功能似乎满足了明显的需求。

我们用它来包装g:link标签,只生成一个用户可以访问目标页面的链接:

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

【讨论】:

包装 g:link 也是我们所做的。顺便说一句,Groovy 忽略 protected 甚至 private,因此您只需注入 SecurityTagLib 的实例并调用它。 我不确定回答时的情况,但现在通过 'SpringSecurityUtils` 公开了此功能。 @mattforsythe 它到底暴露在哪里? docs 和 source code 都没有提到任何可以接受带有 controlleraction(或 url)参数的映射并返回布尔值的方法,这就是 hasAccess() 所做的。 @Tobia 嗯......你似乎是对的。我不确定一年前我写那条评论时在看什么。但看起来&lt;sec:access&gt; 会为您执行此操作。但这假设您在 GSP 和 Groovy 代码中。 @Victor Sergienko 好建议!我用SecurityTagLib securityTagLib = (SecurityTagLib)Holders.grailsApplication.mainContext.getBean('grails.plugins.springsecurity.SecurityTagLib')注入了!【参考方案4】: org.grails.plugins.springsecurity.service.AuthenticateService authenticateService = new org.grails.plugins.springsecurity.service.AuthenticateService() def isAdmin = authenticateService.ifAllGranted('ROLE_ADMIN') 如果(isAdmin) println '我是管理员'

【讨论】:

【参考方案5】:

我不确定在 Groovy 中,但在 Java 中(所以我也认为是 Groovy...)你可以这样做(减去 NPE 检查):

GrantedAuthority[] authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities();
boolean isAdmin = false;
for(GrantedAuthority authority : authorities) 
    String role = authority.getAuthority();
    if(role != null && role.equals("ROLE_ADMIN")) 
        isAdmin = true;
        break;
    

至于是否支持该操作,您必须调用 RequestMap 服务来获取映射的角色,并查看它是否包含找到的用户角色。

【讨论】:

感谢您的代码,但我认为这就是 ifAnyGranted 所做的... 有趣的部分是这个“RequestMap 服务”——您有更多关于它的信息吗?我用谷歌找不到任何东西...【参考方案6】:

据我所知,似乎没有一种简单的方法可以做到这一点。

您可以通过执行以下操作注入 grails AuthenticatedVetoableDecisionManager 的实例,它是 spring 的 AbstractAccessDecisionManager 的一个具体类:

def accessDecisionManager

这有一个“决定”方法,它需要 3 个参数

decide(Authentication authentication, Object object, ConfigAttributeDefinition config)

这可能是您需要调用并传递正确内容的方法,以确定具有身份验证凭据的用户是否可以访问该“对象”(看起来通常是请求/响应)。一些额外的挖掘可能会证明这里可行。

短期而言,使用 ifAnyGranted taglib 可能更容易,正如另一张海报提到的那样。

【讨论】:

谢谢,我会在这个方向寻找解决方案。无论如何,我想使用 ifAnyGranted taglib,但是我仍然需要弄清楚哪些角色适用于当前情况,这意味着,找到一种方法从我的 RequestMap 中获取特定控制器/操作的角色。 【参考方案7】:

在处理视图和标签库中的权限时,您可以使用插件提供的AuthorizeTagLib。

例如,如果您不希望未经身份验证的用户在列表中显示菜单项,则可以使用:

<g:isLoggedIn>
  <li>Restricted Link</li>
</g:isLoggedIn>

如果您定义了更具体的角色并且这些角色与您的控制器/操作请求映射相关联,您可以使用其他标签,例如:

<g:ifAllGranted role="ROLE_ADMINISTRATOR">
  <li>Administrator Link</li>
</g:ifAllGranted>

根据我的经验,目前还没有一种将请求映射与您的标记相关联的好方法 - 我认为您将不得不使用上述一些标签来限制对特定 GSP 中内容的访问。

我认为 Burt Beckwith 未来对插件进行了修改(目前正在提供beta version),该插件集成了一些 ACL 东西,将来可能会更好地解决这个问题,但就目前而言,我认为最好的方法是一个混合请求映射 + GSP 标签一个。

【讨论】:

我见过那个 TagLib,但它并没有真正解决我的问题。也许我可以使用 ifAllGranted 或 ifAnyGranted 方法,如果有办法将控制器和操作与我的 RequestMap 中的条目相匹配...有谁知道这是怎么做到的?【参考方案8】:

你必须配置文件config/SecurityConfig.groovy(如果它不存在,创建它,这会覆盖默认的安全配置)

添加此条目:

requestMapString = """\
            CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON
            PATTERN_TYPE_APACHE_ANT
            /=IS_AUTHENTICATED_REMEMBERED
            /login/auth=IS_AUTHENTICATED_ANONYMOUSLY
            /login/authajax=IS_AUTHENTICATED_ANONYMOUSLY
            /login/authfail=IS_AUTHENTICATED_ANONYMOUSLY 
            /js/**=IS_AUTHENTICATED_ANONYMOUSLY
            /css/**=IS_AUTHENTICATED_ANONYMOUSLY
            /images/**=IS_AUTHENTICATED_ANONYMOUSLY
            /plugins/**=IS_AUTHENTICATED_ANONYMOUSLY
            /**=IS_AUTHENTICATED_REMEMBERED
          """

这意味着您必须登录才能进入该站点。但是所有资源(css、js、图像等)都无需身份验证即可访问。

如果您想要特定角色,只需输入特定控制器: 例如,对于 UserController:

    /user/**=ROLE_ADMIN
    /role/**=ROLE_ADMIN 

欲了解更多信息:http://www.grails.org/AcegiSecurity+Plugin+-+Securing+URLs

问候

【讨论】:

对不起,如果我的问题被误解了,我已经使用 RequestMap(不在 SecurityConfig.groovy 中,而是使用数据库表)保护了我的控制器,所有这些都完美无缺。我的问题是,如何检查当前用户是否有权访问某个控制器和操作。我是这样想的: if (currentUserHasAccess(controller, action)) do_some_stuff

以上是关于Grails with SpringSecurity,检查当前用户是不是可以访问控制器/动作的主要内容,如果未能解决你的问题,请参考以下文章

让 Grails 控制器更干燥?

Spring Security 是不是具有执行“hasAnyRole”的 AND 版本的“hasAllRole”

Grails 2.4.4 中的 Spring Security 插件问题

圣杯。 JSON。他的方法?

在Spring MVC中管理HTML资源(CSS,JS文件)

Grails:Grails3:doWithWebDescriptor?