Grails Spring Security:使用目标URL登录会跳过验证工作流程 [英] Grails Spring Security: Logging in with a target URL skips post authentication workflow
问题描述
在我的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
- 用户通过
http:// localhost:8080 / my-app /
或http:// localhost:8080 / my-app / login / auth
- 她输入有效的登录ID和密码并继续。
- 访问重定向到AdminController的MyAuthSuccessHandler,并考虑授予此用户的角色。
- 创建UserSessionBean并将其存储在会话中
- 用户被带到应用程序主页
我也通过扩展来编写自定义的 MyUserDetailsService
code> GormUserDetailsService 在上述流程中正确访问。
问题情景:
考虑一个用户在应用程序中直接访问受保护的资源(在这种情况下,控制器由 @Secured
注释保护)。
- 用户点击
http:// localhost:8080 / my-app / inbox / index
- 应用程序将她重定向到
http:// localhost:8080 / my-app / login / auth
- 用户输入有效的登录标识并密码
- 用户转到
http:// localhost:8080 / my-app / inbox / index
MyAuthSuccessHandler
会在此过程中被完全跳过,因此我的 UserSessionBean 未在创建 UserSessionBean 的地方进一步使用时导致错误。
问题:
- 在问题场景中,应用程序是否跳过
MyAuthSuccessHandler
它会在登录时重定向? - 即使目标URL存在,我们是否可以强制进程始终通过
MyAuthSuccessHandler
? li> - 如果对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:
- User comes to the app via either
http://localhost:8080/my-app/
ORhttp://localhost:8080/my-app/login/auth
- She enters her valid login id and password and proceeds.
- The app internally accesses MyAuthSuccessHandler which redirects to AdminController considering the Role granted to this User.
- The UserSessionBean is created and stored it in the session
- User is taken to the app home page
I have also written a custom
MyUserDetailsService
by extendingGormUserDetailsService
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.
- User clicks
http://localhost:8080/my-app/inbox/index
- App redirects her to
http://localhost:8080/my-app/login/auth
- User enters her valid login id and password
- 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:
- In the problem scenario, does the app skip the
MyAuthSuccessHandler
because there is a target URL for it to redirect to upon login?- Can we force the process to always pass through
MyAuthSuccessHandler
even with the target URL present?- 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屋!