如何使 Grails 的 Spring 安全核心根据访问被拒绝的原因呈现不同的页面
How to make Grails's Spring Security Core render a different page depending on the reason why access was denied
我是 运行 使用 Spring 安全核心插件的 Grails 应用程序。
当一个已经登录的用户尝试访问一个页面而不访问它时,总是调用在 UrlMappings.groovy 中配置为 403
的相同操作。
我一直在努力让我的应用程序根据拒绝访问的原因呈现不同的页面。例如:如果需要 IS_AUTHENTICATED_FULLY
我想将用户重定向到一个他可以重新验证的表单。如果需要特定角色但不存在,我想将用户重定向到他可以请求此角色的页面。等等...
有人知道如何存档吗?
==============================更新============== ====================
我试图通过 docs 中描述的 onAuthorizationEvent
回调解决问题。不幸的是,无论触发它的规则如何,事件参数始终相同。
至少我可以访问被拒绝访问的 URI。有没有办法从 URI 获取安全规则,以便我可以与当前用户的角色和状态进行比较并找出缺少的内容?那也许可以解决问题。
也许在那里创建控制器和访问异常?
static mappings = {
//....
"403"(controller:'error', action:'error403')
//......
}
class ErrorController {
def error403() {
def message = request.exception?.cause?.message; //access message and render right view
}
}
通过互联网进行了长时间的研究后,终于根据@yariash 的回复和 this post:
中的一些想法使其工作
import org.springframework.context.ApplicationListener;
import org.springframework.security.access.event.AuthorizationFailureEvent
import org.springframework.security.authentication.RememberMeAuthenticationToken;
class AuthorizationFailureEventListener
implements ApplicationListener<AuthorizationFailureEvent> {
@Override
public void onApplicationEvent(AuthorizationFailureEvent e) {
def attributes = e.getConfigAttributes()
if(!attributes) {
return
}
def authentication = e.getAuthentication()
def requiredAuthorities = attributes?.collect { it.getAttribute() }
def userAuthorities = authentication.getAuthorities().collect { it.getAuthority() }
def missingAuthorities = requiredAuthorities - userAuthorities
if(requiredAuthorities.contains('IS_AUTHENTICATED_FULLY') &&
!(authentication instanceof RememberMeAuthenticationToken)) {
requiredAuthorities.remove('IS_AUTHENTICATED_FULLY')
}
e.getSource().getRequest().setAttribute("MISSING_AUTHORITIES", missingAuthorities);
}
}
然后将此侦听器作为 bean 包括在内:
beans = {
//...
authorizationFailureEventListener(AuthorizationFailureEventListener) { bean ->
bean.autowire = "byName"
}
//...
}
终于在我的错误控制器中:
static mappings = {
//....
"403"(controller:'error', action:'error403')
//......
}
class ErrorController {
def error403() {
def missingAuthorities = request.getAttribute("MISSING_AUTHORITIES")
// Render the right view based on the missing authorities
}
}
我是 运行 使用 Spring 安全核心插件的 Grails 应用程序。
当一个已经登录的用户尝试访问一个页面而不访问它时,总是调用在 UrlMappings.groovy 中配置为 403
的相同操作。
我一直在努力让我的应用程序根据拒绝访问的原因呈现不同的页面。例如:如果需要 IS_AUTHENTICATED_FULLY
我想将用户重定向到一个他可以重新验证的表单。如果需要特定角色但不存在,我想将用户重定向到他可以请求此角色的页面。等等...
有人知道如何存档吗?
==============================更新============== ====================
我试图通过 docs 中描述的 onAuthorizationEvent
回调解决问题。不幸的是,无论触发它的规则如何,事件参数始终相同。
至少我可以访问被拒绝访问的 URI。有没有办法从 URI 获取安全规则,以便我可以与当前用户的角色和状态进行比较并找出缺少的内容?那也许可以解决问题。
也许在那里创建控制器和访问异常?
static mappings = {
//....
"403"(controller:'error', action:'error403')
//......
}
class ErrorController {
def error403() {
def message = request.exception?.cause?.message; //access message and render right view
}
}
通过互联网进行了长时间的研究后,终于根据@yariash 的回复和 this post:
中的一些想法使其工作import org.springframework.context.ApplicationListener;
import org.springframework.security.access.event.AuthorizationFailureEvent
import org.springframework.security.authentication.RememberMeAuthenticationToken;
class AuthorizationFailureEventListener
implements ApplicationListener<AuthorizationFailureEvent> {
@Override
public void onApplicationEvent(AuthorizationFailureEvent e) {
def attributes = e.getConfigAttributes()
if(!attributes) {
return
}
def authentication = e.getAuthentication()
def requiredAuthorities = attributes?.collect { it.getAttribute() }
def userAuthorities = authentication.getAuthorities().collect { it.getAuthority() }
def missingAuthorities = requiredAuthorities - userAuthorities
if(requiredAuthorities.contains('IS_AUTHENTICATED_FULLY') &&
!(authentication instanceof RememberMeAuthenticationToken)) {
requiredAuthorities.remove('IS_AUTHENTICATED_FULLY')
}
e.getSource().getRequest().setAttribute("MISSING_AUTHORITIES", missingAuthorities);
}
}
然后将此侦听器作为 bean 包括在内:
beans = {
//...
authorizationFailureEventListener(AuthorizationFailureEventListener) { bean ->
bean.autowire = "byName"
}
//...
}
终于在我的错误控制器中:
static mappings = {
//....
"403"(controller:'error', action:'error403')
//......
}
class ErrorController {
def error403() {
def missingAuthorities = request.getAttribute("MISSING_AUTHORITIES")
// Render the right view based on the missing authorities
}
}