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
也有 ifAnyGranted
、ifNotGranted
等方法,所以它应该适用于你想要完成的任何事情。
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 中测试)
【讨论】:
...然后还有<sec:ifAnyGranted roles="ROLE_ADMIN, ROLE_SUPER_ADMIN">
【参考方案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 都没有提到任何可以接受带有 controller
和 action
(或 url
)参数的映射并返回布尔值的方法,这就是 hasAccess()
所做的。
@Tobia 嗯......你似乎是对的。我不确定一年前我写那条评论时在看什么。但看起来<sec:access>
会为您执行此操作。但这假设您在 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,检查当前用户是不是可以访问控制器/动作的主要内容,如果未能解决你的问题,请参考以下文章
Spring Security 是不是具有执行“hasAnyRole”的 AND 版本的“hasAllRole”
Grails 2.4.4 中的 Spring Security 插件问题