如何在Spring中获得会话对象?
我对Spring和Spring的安全性比较陌生。
我试图编写一个程序,我需要使用Spring安全性在服务器端validation用户,
我想出了以下几点:
public class CustomAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider{ @Override protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException { System.out.println("Method invoked : additionalAuthenticationChecks isAuthenticated ? :"+usernamePasswordAuthenticationToken.isAuthenticated()); } @Override protected UserDetails retrieveUser(String username,UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { System.out.println("Method invoked : retrieveUser"); //so far so good, i can authenticate user here, and throw exception if not authenticated!! //THIS IS WHERE I WANT TO ACCESS SESSION OBJECT } }
我的用例是,当用户通过身份validation时,我需要放置一个属性,如:
session.setAttribute("userObject", myUserObject);
myUserObject是一些类的对象,我可以通过多个用户请求访问我的服务器代码。
你的朋友在这里是org.springframework.web.context.request.RequestContextHolder
// example usage public static HttpSession session() { ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); return attr.getRequest().getSession(true); // true == allow create }
这将由标准的spring mvc dispatch servlet填充,但是如果您使用的是不同的web框架,您可以在web.xml
添加org.springframework.web.filter.RequestContextFilter
作为filter来pipe理持有者。
编辑 :只是作为一个侧面的问题你究竟在做什么,我不知道你应该需要访问UserDetailsService
的retieveUser
方法中的HttpSession
。 Spring的安全性将把UserDetails对象放在会话中为你任何方式。 它可以通过访问SecurityContextHolder
来获取:
public static UserDetails currentUserDetails(){ SecurityContext securityContext = SecurityContextHolder.getContext(); Authentication authentication = securityContext.getAuthentication(); if (authentication != null) { Object principal = authentication.getPrincipal(); return principal instanceof UserDetails ? (UserDetails) principal : null; } return null; }
既然你使用的是Spring,那就坚持Spring吧,不要像其他职位那样破解它。
春季手册说:
出于安全目的,您不应该直接与HttpSession进行交互。 没有理由这么做 – 总是使用SecurityContextHolder来代替。
build议访问会话的最佳做法是:
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); if (principal instanceof UserDetails) { String username = ((UserDetails)principal).getUsername(); } else { String username = principal.toString(); }
这里的关键是Spring和Spring Security为你提供了各种各样的好东西,比如Session Fixation Prevention。 这些事情假设你正在使用Spring框架,因为它被devise为使用。 因此,在您的servlet中,使其具有上下文感知,并像上例那样访问会话。
如果您只需要在会话范围内存储一些数据,请尝试像本示例那样创build一些会话范围的bean,并让autowire发挥它的魔力。 🙂
事实上,即使会话在HttpSessionLisener上被销毁,您也可以通过执行以下操作来访问会话中的信息:
public void sessionDestroyed(HttpSessionEvent hse) { SecurityContextImpl sci = (SecurityContextImpl) hse.getSession().getAttribute("SPRING_SECURITY_CONTEXT"); // be sure to check is not null since for users who just get into the home page but never get authenticated it will be if (sci != null) { UserDetails cud = (UserDetails) sci.getAuthentication().getPrincipal(); // do whatever you need here with the UserDetails } }
或者你也可以访问任何你有HttpSession对象可用的信息,如:
SecurityContextImpl sci = (SecurityContextImpl) session().getAttribute("SPRING_SECURITY_CONTEXT");
最后假设你有这样的事情:
HttpSession sesssion = ...; // can come from request.getSession(false);
我尝试使用下一个代码并且非常出色
import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; /** * Created by jaime on 14/01/15. */ @Controller public class obteinUserSession { @RequestMapping(value = "/loginds", method = RequestMethod.GET) public String UserSession(ModelMap modelMap) { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); String name = auth.getName(); modelMap.addAttribute("username", name); return "hellos " + name; }
我做了我自己的工具。 它是方便的。 🙂
package samples.utils; import java.util.Arrays; import java.util.Collection; import java.util.Locale; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import javax.sql.DataSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoUniqueBeanDefinitionException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.MessageSource; import org.springframework.core.convert.ConversionService; import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.ui.context.Theme; import org.springframework.util.ClassUtils; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.support.WebApplicationContextUtils; import org.springframework.web.servlet.LocaleResolver; import org.springframework.web.servlet.ThemeResolver; import org.springframework.web.servlet.support.RequestContextUtils; /** * SpringMVC通用工具* * @author 应卓(yingzhor@gmail.com) * */ public final class WebContextHolder { private static final Logger LOGGER = LoggerFactory.getLogger(WebContextHolder.class); private static WebContextHolder INSTANCE = new WebContextHolder(); public WebContextHolder get() { return INSTANCE; } private WebContextHolder() { super(); } // -------------------------------------------------------------------------------------------------------------- public HttpServletRequest getRequest() { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); return attributes.getRequest(); } public HttpSession getSession() { return getSession(true); } public HttpSession getSession(boolean create) { return getRequest().getSession(create); } public String getSessionId() { return getSession().getId(); } public ServletContext getServletContext() { return getSession().getServletContext(); // servlet2.3 } public Locale getLocale() { return RequestContextUtils.getLocale(getRequest()); } public Theme getTheme() { return RequestContextUtils.getTheme(getRequest()); } public ApplicationContext getApplicationContext() { return WebApplicationContextUtils.getWebApplicationContext(getServletContext()); } public ApplicationEventPublisher getApplicationEventPublisher() { return (ApplicationEventPublisher) getApplicationContext(); } public LocaleResolver getLocaleResolver() { return RequestContextUtils.getLocaleResolver(getRequest()); } public ThemeResolver getThemeResolver() { return RequestContextUtils.getThemeResolver(getRequest()); } public ResourceLoader getResourceLoader() { return (ResourceLoader) getApplicationContext(); } public ResourcePatternResolver getResourcePatternResolver() { return (ResourcePatternResolver) getApplicationContext(); } public MessageSource getMessageSource() { return (MessageSource) getApplicationContext(); } public ConversionService getConversionService() { return getBeanFromApplicationContext(ConversionService.class); } public DataSource getDataSource() { return getBeanFromApplicationContext(DataSource.class); } public Collection<String> getActiveProfiles() { return Arrays.asList(getApplicationContext().getEnvironment().getActiveProfiles()); } public ClassLoader getBeanClassLoader() { return ClassUtils.getDefaultClassLoader(); } private <T> T getBeanFromApplicationContext(Class<T> requiredType) { try { return getApplicationContext().getBean(requiredType); } catch (NoUniqueBeanDefinitionException e) { LOGGER.error(e.getMessage(), e); throw e; } catch (NoSuchBeanDefinitionException e) { LOGGER.warn(e.getMessage()); return null; } } }
如果你需要的只是用户的详细信息,对于Spring版本4.x,你可以使用Spring提供的@AuthenticationPrincipal
和@EnableWebSecurity
标签,如下所示。
安全configuration类:
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { ... }
控制器方法:
@RequestMapping("/messages/inbox") public ModelAndView findMessagesForUser(@AuthenticationPrincipal User user) { ... }