我比上次更深入地检查了该主题,发现您必须确定用户是否在控制器中由您自己进行身份验证。Row Winch(Spring Security 开发人员)在这里说:
Spring Security 不知道您的应用程序的内部结构(即,如果您想根据用户是否登录来使您的登录页面灵活)。要在请求登录页面并且用户登录时显示您的主页,请使用SecurityContextHolder
登录页面(或其控制器)并将用户重定向或转发到主页。
因此,解决方案将确定用户请求/auth/login
是否是匿名的,如下所示。
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>
添加到applicationContext.xml bean 定义:
<bean id="securityContextAccessor"
class="com.example.spring.security.SecurityContextAccessorImpl" />
这是类
public final class SecurityContextAccessorImpl
implements 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
接口。)
最后但并非最不重要的重定向控制器中的逻辑:
@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;
}
}
}
定义defaultTargetUrl
String bean 似乎是一个 hack,但我没有更好的方法不硬编码 url...(实际上在我们的项目中,我们使用<util:constant>
包含静态 final String 字段的类。)但它毕竟有效。