如果用户在登录后访问登录页面,如何重定向到主页? [英] How to redirect to the homepage if the user accesses the login page after being logged in?
问题描述
这是我的春季安全配置:
< http pattern =/ auth /登录security =none/>
< http pattern =/ auth / loginFailedsecurity =none/>
< http pattern =/ resources / **security =none/>
< http auto-config =trueaccess-decision-manager-ref =accessDecisionManager>
< intercept-url pattern =/ auth / logoutaccess =permitAll/>
< intercept-url pattern =/ admin / **access =ADMINISTRATIVE_ACCESS/>
< intercept-url pattern =/ **access =XYZ_ACCESS/>
< form-login
login-page =/ auth / login
authentication-failure-url =/ auth / loginFailed
authentication-success -handler-ref =authenticationSuccessHandler/>
< logout logout-url =/ auth / logoutlogout-success-url =/ auth / login/>
< / http>
authenticationSuccessHandler
扩展 SavedRequestAwareAuthenticationSuccessHandler
确保将用户重定向到他最初请求的页面。
但是,因为 / auth / login
标记为 security =none
,如果用户在登录后访问登录页面,我无法成功将用户重定向到主页in。我相信这是正确的用户体验。
我也尝试了以下内容,但 Principal
对象始终是 null
,大概是因为 security =none
属性。
< pre class =lang-java prettyprint-override>
@RequestMapping(value =/ auth / login,method = GET)
public String showLoginForm(HttpServletRequest request,Principal principal){
I f(校长!= null){
returnredirect:/;
}
返回登录;
}
我查看过主题比上次更深刻,发现你必须确定用户是否在控制器中自己进行了身份验证。 Row Winch(Spring Security dev)在这里说:
Spring Security不知道您的应用程序的内部结构
(即如果你想要的话)根据用户是否登录用户
,使登录页面变为flex。要在登录页面请求
并且用户已登录时显示您的主页,请使用
中的SecurityContextHolder
登录页面(或其控制器)并将用户重定向或转发到
主页。
因此解决方案将确定用户是否请求 / auth / login
是匿名的,如下所示。
applicationContext-security.xml :
< http auto-config =trueuse-expressions =true
access-decision-manager-ref =accessDecisionManager>
< intercept-url pattern =/ auth / loginaccess =permitAll/>
< intercept-url pattern =/ auth / logoutaccess =permitAll/>
< intercept-url pattern =/ admin / **access =ADMINISTRATIVE_ACCESS/>
< intercept-url pattern =/ **access =XYZ_ACCESS/>
< form-login login-page =/ auth / login
authentication-failure-url =/ auth / loginFailed
authentication-success-handler-ref =authenticationSuccessHandler/>
< logout logout-url =/ auth / logoutlogout-success-url =/ auth / login/>
< / http>
< beans:bean id =defaultTargetUrlclass =java.lang.String>
< beans:constructor-arg value =/ content/>
< / beans:bean>
< beans:bean id =authenticationTrustResolver
class =org.springframework.security.authentication.AuthenticationTrustResolverImpl/>
< beans:bean id =authenticationSuccessHandler
class =com.example.spring.security.MyAuthenticationSuccessHandler>
< beans:property name =defaultTargetUrlref =defaultTargetUrl/>
< / beans:bean>
添加到 applicationContext.xml bean定义:
< bean id =securityContextAccessor
class =com.example.spring.security.SecurityContextAccessorImpl />
这是类
public final class SecurityContextAccessorImpl
实现SecurityContextAccessor {
@Autowired
private AuthenticationTrustResolver authenticationTrustResolver;
@Override
public boolean isCurrentAuthenticationAnonymous(){
final authentication authentication =
SecurityContextHolder.getContext()。getAuthentication();
return authenticationTrustResolver.isAnonymous(authentication);
}
}
实现简单的界面
public interface SecurityContextAccessor {
boolean isCurrentAuthenticationAnonymous();
}
( SecurityContextHolder
访问代码与控制器分离,我按照此答案的建议,因此 SecurityContextAccessor
interface。)
最后但并非最不重要的是控制器中的重定向逻辑:
@Controller
@RequestMapping(/ auth)
public class AuthController {
@Autowired
SecurityContextAccessor securityContextAccessor;
@Autowired
@Qualifier(defaultTargetUrl)
private String defaultTargetUrl;
@RequestMapping(value =/ login,method = RequestMethod.GET)
public String login(){
if(securityContextAccessor.isCurrentAuthenticationAnonymous()){
返回登录;
} else {
returnredirect:+ defaultTargetUrl;
}
}
}
定义 defaultTargetUrl
String bean看起来像是一个hack,但我没有更好的方法来硬编码url ...(实际上在我们的项目中我们使用 < util:constant>
,包含静态最终字符串字段的类。)但它毕竟有效。
Here is my spring security config:
<http pattern="/auth/login" security="none" />
<http pattern="/auth/loginFailed" security="none" />
<http pattern="/resources/**" security="none" />
<http auto-config="true" access-decision-manager-ref="accessDecisionManager">
<intercept-url pattern="/auth/logout" access="permitAll"/>
<intercept-url pattern="/admin/**" access="ADMINISTRATIVE_ACCESS"/>
<intercept-url pattern="/**" access="XYZ_ACCESS"/>
<form-login
login-page="/auth/login"
authentication-failure-url="/auth/loginFailed"
authentication-success-handler-ref="authenticationSuccessHandler" />
<logout logout-url="/auth/logout" logout-success-url="/auth/login" />
</http>
The authenticationSuccessHandler
extends the SavedRequestAwareAuthenticationSuccessHandler
ensuring that the user is redirected to the page he originally requested.
However, since /auth/login
is marked as security="none"
, I am unable to successfully redirect the user to the homepage if he accesses the login page after being logged in. I believe this is the right user experience too.
I tried the below too but the Principal
object is always null
, presumably because of the security="none"
attribute again.
@RequestMapping(value = "/auth/login", method = GET)
public String showLoginForm(HttpServletRequest request, Principal principal) {
if(principal != null) {
return "redirect:/";
}
return "login";
}
I've checked the topic more deeply than last time and found that you have to determine if user is authenticated by yourself in controller. Row Winch (Spring Security dev) says here:
Spring Security is not aware of the internals of your application (i.e. if you want to make your login page flex based upon if the user is logged in or not). To show your home page when the login page is requested and the user is logged in use the
SecurityContextHolder
in the login page (or its controller) and redirect or forward the user to the home page.
So solution would be determining if user requesting /auth/login
is anonymous or not, something like below.
applicationContext-security.xml:
<http auto-config="true" use-expressions="true"
access-decision-manager-ref="accessDecisionManager">
<intercept-url pattern="/auth/login" access="permitAll" />
<intercept-url pattern="/auth/logout" access="permitAll" />
<intercept-url pattern="/admin/**" access="ADMINISTRATIVE_ACCESS" />
<intercept-url pattern="/**" access="XYZ_ACCESS" />
<form-login login-page="/auth/login"
authentication-failure-url="/auth/loginFailed"
authentication-success-handler-ref="authenticationSuccessHandler" />
<logout logout-url="/auth/logout" logout-success-url="/auth/login" />
</http>
<beans:bean id="defaultTargetUrl" class="java.lang.String">
<beans:constructor-arg value="/content" />
</beans:bean>
<beans:bean id="authenticationTrustResolver"
class="org.springframework.security.authentication.AuthenticationTrustResolverImpl" />
<beans:bean id="authenticationSuccessHandler"
class="com.example.spring.security.MyAuthenticationSuccessHandler">
<beans:property name="defaultTargetUrl" ref="defaultTargetUrl" />
</beans:bean>
Add to applicationContext.xml bean definition:
<bean id="securityContextAccessor"
class="com.example.spring.security.SecurityContextAccessorImpl" />
which is class
public final class SecurityContextAccessorImpl
implements SecurityContextAccessor {
@Autowired
private AuthenticationTrustResolver authenticationTrustResolver;
@Override
public boolean isCurrentAuthenticationAnonymous() {
final Authentication authentication =
SecurityContextHolder.getContext().getAuthentication();
return authenticationTrustResolver.isAnonymous(authentication);
}
}
implementing simple interface
public interface SecurityContextAccessor {
boolean isCurrentAuthenticationAnonymous();
}
(SecurityContextHolder
accessing code is decoupled from controller, I followed suggestion from this answer, hence SecurityContextAccessor
interface.)
And last but not least redirect logic in controller:
@Controller
@RequestMapping("/auth")
public class AuthController {
@Autowired
SecurityContextAccessor securityContextAccessor;
@Autowired
@Qualifier("defaultTargetUrl")
private String defaultTargetUrl;
@RequestMapping(value = "/login", method = RequestMethod.GET)
public String login() {
if (securityContextAccessor.isCurrentAuthenticationAnonymous()) {
return "login";
} else {
return "redirect:" + defaultTargetUrl;
}
}
}
Defining defaultTargetUrl
String bean seems like a hack, but I don't have better way not to hardcode url... (Actually in our project we use <util:constant>
with class containing static final String fields.) But it works after all.
这篇关于如果用户在登录后访问登录页面,如何重定向到主页?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!