我最近开始学习Spring Security,今天我踩到了这个基本的(我相信)问题:为什么我不能访问Servlet过滤器中的当前Principal,如下面所示:
package com.acme.test;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
@Component
public class TestFilter implements Filter {
/*
* (non-Javadoc)
*
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// TODO Auto-generated method stub
}
/*
* (non-Javadoc)
*
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
* javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication auth = securityContext.getAuthentication();
// auth is null here
chain.doFilter(request, response);
}
/*
* (non-Javadoc)
*
* @see javax.servlet.Filter#destroy()
*/
@Override
public void destroy() {
// TODO Auto-generated method stub
}
}
使用身份验证验证的身份验证对象auth = securityContext.getAuthentication(); 为空。虽然在MVC @Controller中使用上面的代码段工作得很好(如预期的那样)。
为什么会这样?
答案 0 :(得分:18)
在doFilter
内:
HttpServletRequest request = (HttpServletRequest) request;
HttpSession session = request.getSession(false);
SecurityContextImpl sci = (SecurityContextImpl) session.getAttribute("SPRING_SECURITY_CONTEXT");
if (sci != null) {
UserDetails cud = (UserDetails) sci.getAuthentication().getPrincipal();
// do whatever you need here with the UserDetails
}
希望这有帮助
答案 1 :(得分:8)
以下代码段可以运行并提供Principal
个实例:
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
Principal principal = req.getUserPrincipal();
if (principal != null) {
// do something with the Principal
}
chain.doFilter(request, response);
}
答案 2 :(得分:2)
您可以看到here,为了访问SecurityContext,安全过滤器必须首先出现。
如果您询问如何操作,则取决于您配置Web应用程序的方式。 在我的例子中,我使用Spring-Boot,基于Servlet-3配置样式,以及Java中的Spring上下文配置(无XML) 所以,我的配置如下所示:
@Configuration
@EnableWebMvc
@EnableWebMvcSecurity
public class WebCtxConfig extends WebMvcConfigurerAdapter {
@Autowired
ApplicationContext ctx;
@Bean
FilterRegistrationBean springSecurityFilter() {
FilterChainProxy o = (FilterChainProxy) ctx
.getBean(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME);
FilterRegistrationBean trVal = new FilterRegistrationBean();
trVal.setFilter(o);
trVal.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE + 1);
return trVal;
}
@Bean
public FilterRegistrationBean applicationContextIdFilter(final IThreadLifecycleManager threadLifecycleManager) {
FilterRegistrationBean retVal = new FilterRegistrationBean();
YourFilter filter = new YourFilter();
retVal.setFilter(filter);
retVal.setOrder(FilterRegistrationBean.HIGHEST_PRECEDENCE + 2);
return retVal;
}
}
请注意,通过设置顺序,您可以控制过滤器顺序。
答案 3 :(得分:2)
良好的旧web.xml部署描述符是确定过滤器顺序的简便方法。从Servlet 3.0规范:容器用于构建要应用于的过滤器链的顺序 特定请求URI如下:
简而言之,您必须将<filter-mapping>
替换为Spring安全性之后的过滤器。
同样来自同一规范文档:如果调用侦听器,servlet,过滤器的顺序对于 应用程序然后必须使用部署描述符。
答案 4 :(得分:0)
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication != null) {
if (authentication.getPrincipal() instanceof UserDetails) {
UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal();
return springSecurityUser.getUsername();
} else if (authentication.getPrincipal() instanceof String) {
return (String) authentication.getPrincipal();
}
}
return null;