Grails Spring Security:使用目标URL登录会跳过验证工作流程 [英] Grails Spring Security: Logging in with a target URL skips post authentication workflow

查看:425
本文介绍了Grails Spring Security:使用目标URL登录会跳过验证工作流程的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的grails应用程序中,我通过编写定制auth成功处理程序(在resources.groovy中)来定制后授权工作流程,如下所示。
$ b

  authenticationSuccessHandler(MyAuthSuccessHandler){
def conf = SpringSecurityUtils.securityConfig
requestCache = ref('requestCache' )
defaultTargetUrl = conf.successHandler.defaultTargetUrl
alwaysUseDefaultTargetUrl = conf.successHandler.alwaysUseDefault
targetUrlParameter = conf.successHandler.targetUrlParameter
useReferer = conf.successHandler.useReferer
redirectStrategy = ref('redirectStrategy')
superAdminUrl =/ admin / processSuperAdminLogin
adminUrl =/ admin / processAdminLogin
userUrl =/ admin / processUserLogin
}

正如您可以从上面的闭包中的最后三行中所看到的,取决于授予登录用户的角色我将她重定向到在 AdminController 中分别执行的操作,在该会话中创建并存储自定义的UserSessionBean。



它适用于我的应用程序中的常规登录案例:
$ b


  1. 用户通过 http:// localhost:8080 / my-app / http:// localhost:8080 / my-app / login / auth

  2. 她输入有效的登录ID和密码并继续。

  3. 访问重定向到AdminController的MyAuthSuccessHandler,并考虑授予此用户的角色。

  4. 创建UserSessionBean并将其存储在会话中
  5. 用户被带到应用程序主页

我也通过扩展来编写自定义的 MyUserDetailsS​​ervice code> GormUserDetailsS​​ervice 在上述流程中正确访问。



问题情景:

考虑一个用户在应用程序中直接访问受保护的资源(在这种情况下,控制器由 @Secured 注释保护)。


  1. 用户点击 http:// localhost:8080 / my-app / inbox / index

  2. 应用程序将她重定向到 http:// localhost:8080 / my-app / login / auth

  3. 用户输入有效的登录标识并密码

  4. 用户转到 http:// localhost:8080 / my-app / inbox / index

MyAuthSuccessHandler 会在此过程中被完全跳过,因此我的 UserSessionBean 未在创建 UserSessionBean 的地方进一步使用时导致错误。



问题:


  1. 在问题场景中,应用程序是否跳过 MyAuthSuccessHandler 它会在登录时重定向?

  2. 即使目标URL存在,我们是否可以强制进程始终通过 MyAuthSuccessHandler
  3. li>
  4. 如果对2的答案是否定的,那么ho是否有其他选择? w和 UserSessionBean 仍然可以创建的位置


解决方案

您可以实现自定义的eventListener来处理登录后过程,而不会中断原始用户请求的url。



在config.groovy中,插入一个配置项:

  grails .plugins.springsecurity.useSecurityEventListener = true 

在resources.groovy中,添加一个这样的bean: / p>

  import com.yourapp.auth.LoginEventListener 
beans = {
loginEventListener(LoginEventListener)
}

然后像这样在src / groovy中创建一个eventListener:

  package com.yourapp.auth 
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent
导入org.springframework.web.context.request.RequestContextHolder作为RCH

类LoginEventListener实现
ApplicationListener< ; InteractiveAuthenticationSuccessEvent> {

//处理成功登录
void onApplicationEvent(InteractiveAuthenticationSuccessEvent event){
User.withTransaction {
def user = User.findByUsername(event.authentication.principal .username)
def adminRole = Role.findByAuthority('ROLE_ADMIN')
def userRole = Role.findByAuthority('ROLE_USER')
def session = RCH.currentRequestAttributes()。session // get httpSession
session.user = user $ b $ if if(user.authorities.contains(adminRole)){
processAdminLogin()
}
else if(user.authorities.contains (userRole)){
processUserLogin()
}
}
}

private void processAdminLogin(){//移动admin / processAdminLogin here
.....
}

private void processUserLogin(){//移动admin / processUserLogin here
.....
}
}



完成。


In my grails app I have customized the post authorization workflow by writing a custom auth success handler (in resources.groovy) as shown below.

authenticationSuccessHandler (MyAuthSuccessHandler) {
    def conf = SpringSecurityUtils.securityConfig
    requestCache = ref('requestCache')
    defaultTargetUrl = conf.successHandler.defaultTargetUrl
    alwaysUseDefaultTargetUrl = conf.successHandler.alwaysUseDefault
    targetUrlParameter = conf.successHandler.targetUrlParameter
    useReferer = conf.successHandler.useReferer
    redirectStrategy = ref('redirectStrategy')
    superAdminUrl = "/admin/processSuperAdminLogin"
    adminUrl = "/admin/processAdminLogin"
    userUrl = "/admin/processUserLogin"
}

As you can from the last three lines in the closure above, depending on the Role granted to the logging in User I am redirecting her to separate actions within the AdminController where a custom UserSessionBean is created and stored in the session.

It works fine for a regular login case which in my app is like so:

  1. User comes to the app via either http://localhost:8080/my-app/ OR http://localhost:8080/my-app/login/auth
  2. She enters her valid login id and password and proceeds.
  3. The app internally accesses MyAuthSuccessHandler which redirects to AdminController considering the Role granted to this User.
  4. The UserSessionBean is created and stored it in the session
  5. User is taken to the app home page

I have also written a custom MyUserDetailsService by extending GormUserDetailsService which is correctly accessed in the above flow.

PROBLEM SCENARIO:
Consider a user directly accessing a protected resource (in this case the controller is secured with @Secured annotation) within the app.

  1. User clicks http://localhost:8080/my-app/inbox/index
  2. App redirects her to http://localhost:8080/my-app/login/auth
  3. User enters her valid login id and password
  4. User is taken to http://localhost:8080/my-app/inbox/index

The MyAuthSuccessHandler is skipped entirely in this process and hence my UserSessionBean is not created leading to errors upon further use in places where the UserSessionBean is accessed.

QUESTIONS:

  1. In the problem scenario, does the app skip the MyAuthSuccessHandler because there is a target URL for it to redirect to upon login?
  2. Can we force the process to always pass through MyAuthSuccessHandler even with the target URL present?
  3. If the answer to 2 is no, is there an alternative as to how and where the UserSessionBean can still be created?

解决方案

You can implement a customized eventListener to handle the post-login process, without disrupting the original user requested url.

In config.groovy, insert a config item:

grails.plugins.springsecurity.useSecurityEventListener = true

In you resources.groovy, add a bean like this:

import com.yourapp.auth.LoginEventListener
beans = {
    loginEventListener(LoginEventListener)
}

And create a eventListener in src/groovy like this:

package com.yourapp.auth
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.InteractiveAuthenticationSuccessEvent
import org.springframework.web.context.request.RequestContextHolder as RCH

class LoginEventListener implements
    ApplicationListener<InteractiveAuthenticationSuccessEvent> {    

    //deal with successful login    
    void onApplicationEvent(InteractiveAuthenticationSuccessEvent event) {
        User.withTransaction { 
            def user = User.findByUsername(event.authentication.principal.username)
                    def adminRole = Role.findByAuthority('ROLE_ADMIN')
                    def userRole = Role.findByAuthority('ROLE_USER')
                    def session = RCH.currentRequestAttributes().session      //get httpSession
                    session.user = user
                    if(user.authorities.contains(adminRole)){
                        processAdminLogin()
                    }
                    else if(user.authorities.contains(userRole)){
                        processUserLogin()
                    }
        }
    }

    private void processAdminLogin(){    //move admin/processAdminLogin here
          .....
    }

    private void processUserLogin(){    //move admin/processUserLogin here
          .....
    }
}

Done.

这篇关于Grails Spring Security:使用目标URL登录会跳过验证工作流程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆