我使用以下代码进行身份验证:
@PreAuthorize("isAnonymous()")
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String doLogin(HttpServletRequest request) {
try {
Authentication req = new UsernamePasswordAuthenticationToken(request.getParameter("name"),
request.getParameter("password"));
Authentication result = authenticationManager.authenticate(req);
SecurityContextHolder.getContext().setAuthentication(result);
logger.debug("Success login");
logger.debug(SecurityContextHolder.getContext().getAuthentication());
return "index";
} catch (AuthenticationException e) {
e.printStackTrace();
logger.debug("ACHTUNG! Success failed");
return "index";
}
}
我可以登录,它有效。我在日志中看到非空的身份验证对象。
然后,我尝试浏览这样的安全页面:
@PreAuthorize("hasRole('user')")
@RequestMapping(value = "/user", method = RequestMethod.GET)
public String user(ModelMap modelMap) {
modelMap.addAttribute("user", SecurityContextHolder.getContext().getAuthentication().getCredentials().toString());
return "index";
}
并且由于getAuthentication()引发NullPointerException。
当我使用SecurityContextHolder.MODE_INHERITABLETHREADLOCAL和SecurityContextHolder.MODE_INHERITABLETHREADLOCAL而不是使用SecurityContextHolder.MODE_GLOBAL时,会发生这种情况。
我究竟做错了什么?我不需要SecurityContextHolder的MODE_GLOBAL行为。
UPD:有时会出现问题,有时不在同一会话中。
最佳答案
通过记录以下内容,确保每次在您的请求中安全过滤器都在运行:
request.getAttribute("__spring_security_scpf_applied");
不要。除非您完全知道自己在做什么,否则不要替换SecurityContextHolderStrategy。它与基于ThreadLocal查找SecurityContext有关。因此,除非您使用一个非常奇怪的Servlet容器,否则默认值几乎总是正确的。
您还需要为您的请求路径设置拦截器。 @PreAuthorize仅适用于方法调用http://static.springsource.org/spring-security/site/docs/3.0.x/reference/el-access.html,这不是您想要的。
相反,您在安全应用程序上下文中需要以下内容:
<http> ...
<intercept-url pattern="/user**" access="hasRole('user')" />
</http>