java无状态登录实现方式之ThreadLocal+Cookie
Posted lxjshuju
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java无状态登录实现方式之ThreadLocal+Cookie相关的知识,希望对你有一定的参考价值。
注:本文提到的无状态指的是无需session完毕认证、取用户封装信息。
无状态的优点:
1。多应用单点登录:在多应用的时候仅仅需在登录server登录后。各子应用无需再次登录。
2。多server集群:无需制作会话共享的缓存就可以实现。
此方案的缺点:
1,依赖于cookie,尽管如今主流浏览器都支持cookie。
2。单点登录须要各子应用属于同一主域名下(跨主域名无法实现)。
实现原理:
登录时封装用户信息,并将用户信息通过序列化加密写到用户cookie。当用户下次请求应用server时,过滤器将用户信息取到反解密反序列化后放入ThreadLocal中,利用ThreadLocal的线程安全特性,之后操作取到用户信息。
用户封装信息类
package com.xxx.commons.framework.bean; import java.io.Serializable; public class Principal implements Serializable { private static final long serialVersionUID = -1373760761780840081L; private Long id; private String username; private Integer userType; private Long pharmacyId; private Long saleManId; private Long ydId; private String name; public Principal(Long id, String username,Integer userType,Long pharmacyId,Long saleManId,Long ydId,String name) { this.id = id; this.username = username; this.userType = userType; this.pharmacyId = pharmacyId; this.saleManId = saleManId; this.ydId = ydId; this.setName(name); } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } @Override public String toString() { return username; } public Integer getUserType() { return userType; } public void setUserType(Integer userType) { this.userType = userType; } /** * @return pharmacyId * */ public Long getPharmacyId() { return pharmacyId; } /** * @param pharmacyId * */ public void setPharmacyId(Long pharmacyId) { this.pharmacyId = pharmacyId; } /** * @return saleManId * */ public Long getSaleManId() { return saleManId; } /** * @param saleManId * */ public void setSaleManId(Long saleManId) { this.saleManId = saleManId; } /** * @return ydId * */ public Long getYdId() { return ydId; } /** * @param ydId * */ public void setYdId(Long ydId) { this.ydId = ydId; } /** * get name * @return the name * */ public String getName() { return name; } /** * set name * @param name * */ public void setName(String name) { this.name = name; } }
/** * Copyright RH Corporation 2014 版权全部 * Created 2014年12月18日 下午1:24:27 * @version V1.0 */ package com.xxx.commons.framework.utils; import com.xxx.commons.framework.bean.Principal; /** * 加入类描写叙述 * @author ElongDeo * @version 1.0 * Created 2014年12月18日 下午1:24:27 */ public class UserUtil { public static final ThreadLocal<Principal> principal = new ThreadLocal<Principal>(); public static Principal getUserPrincipal(){ Principal principal = UserUtil.principal.get(); return principal; } public static String getUserName(){ String userName = ""; Principal principal = getUserPrincipal(); if(principal!=null){ userName = principal.getUsername(); } return userName; } public static String getName(){ String name = ""; Principal principal = getUserPrincipal(); if(principal!=null){ name = principal.getName(); } return name; } public static Long getUserId(){ Long userId = null; Principal principal = getUserPrincipal(); if(principal!=null){ userId = principal.getId(); } return userId; } public static Integer getUserType(){ Integer userType = null; Principal principal = getUserPrincipal(); if(principal!=null){ userType = principal.getUserType(); } return userType; } public static Long getPharmacyId(){ Long pharmacyId = null; Principal principal = getUserPrincipal(); if(principal!=null){ pharmacyId = principal.getPharmacyId(); } return pharmacyId; } public static Long getSaleManId(){ Long saleManId = null; Principal principal = getUserPrincipal(); if(principal!=null){ saleManId = principal.getSaleManId(); } return saleManId; } public static Long getYdId(){ Long ydId = null; Principal principal = getUserPrincipal(); if(principal!=null){ ydId = principal.getYdId(); } return ydId; } public static Long getBuyerId(){ Long buyerId = null; Integer userType = getUserType(); if(userType != null && userType > Constants.USER_ADMIN_TYPE){ if(userType.equals(Constants.USER_PHARMARY_TYPE)){ buyerId = getPharmacyId(); }else{ buyerId = getYdId(); } } return buyerId; } public static String getCartYn(){ String cartYn = "no"; Integer userType = getUserType(); if(userType > Constants.USER_ADMIN_TYPE){ cartYn = "yes"; } return cartYn; } }
cookies工具类(用来封装/解析用户信息)
/** * CookieUtils.java Copyright ? 2008-2013 lefeng.com Inc. All Rights Reserved. */ package com.xxx.commons.framework.utils; import java.util.HashMap; import java.util.Map; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.codec.binary.Base64; import com.xxx.commons.framework.bean.Principal; import com.xxx.commons.items.PropertiesFileLoader; /** * <pre> * <P>Author : ElongDeo</P> * <P>Date : 2014-3-10 </P> * <P>Cookie操作辅助类</P> * </pre> */ public class CookieUtils { public static String DOMAIN = ".xxx.com"; public static final String COOKIE_TOKEN_LOGIN = "xxx_token"; public static final String COOKIE_USER_INFO = "xxx_user"; static { PropertiesFileLoader instance = PropertiesFileLoader.getInstance(); DOMAIN = instance.getProerties("config/user.properties","domain"); } /** * 设置cookie * @param response * @param name cookie名字 * @param value cookie值 * @param maxAge cookie生命周期 以秒为单位 */ public static void addCookie(HttpServletResponse response,String name,String value,int maxAge, String domain){ Cookie cookie = new Cookie(name,value); cookie.setDomain(domain); cookie.setPath("/"); if(maxAge>0) cookie.setMaxAge(maxAge); response.addCookie(cookie); } /** * 依据名字获取cookie * @param request * @param name cookie名字 * @return */ public static Cookie getCookieByName(HttpServletRequest request,String name){ Map<String,Cookie> cookieMap = readCookieMap(request); if(cookieMap.containsKey(name)){ Cookie cookie = (Cookie)cookieMap.get(name); return cookie; }else{ return null; } } /** * 将cookie封装到Map里面 * @param request * @return */ public static Map<String,Cookie> readCookieMap(HttpServletRequest request){ Map<String,Cookie> cookieMap = new HashMap<String,Cookie>(); Cookie[] cookies = request.getCookies(); if(null!=cookies){ for(Cookie cookie : cookies){ cookieMap.put(cookie.getName(), cookie); } } return cookieMap; } public static Principal getPrincipal(HttpServletRequest request) { Cookie cookie = getCookieByName(request, COOKIE_USER_INFO); if (cookie != null && !"".equals(cookie.getValue())) { try { return (Principal) SerializeUtils.deserialize(Base64.decodeBase64(cookie.getValue())); } catch (Exception e) { e.printStackTrace(); } } return null; } public static void setPrincipal(HttpServletResponse response, Principal principal) { try { addCookie(response, COOKIE_USER_INFO, Base64.encodeBase64String(SerializeUtils.serialize(principal)), 0, DOMAIN); } catch (Exception e) { e.printStackTrace(); } } public static void removePrincipal(HttpServletResponse response) { try { addCookie(response, COOKIE_USER_INFO, null, 0, DOMAIN); } catch (Exception e) { e.printStackTrace(); } } }
Principal principal = new Principal(userId, login, userType, pharmacyId, saleManId, ydId, name); //假设正确,那么写cookie而且正确跳转 try { CookieUtils.setPrincipal(response, principal); redirect = StringUtils.isEmpty(request.getParameter("redirect"))?LOGIN_REDIRECT_URL:request.getParameter("redirect");// 须要处理首页 PrintUtils.printToMobile(response, new ResultObject<Object>(1, redirect), "json"); return; } catch (Exception e) { e.printStackTrace(); }
过滤器获取用户信息并放入ThreadLocal
/** * */ package com.xxx.commons.framework.filters; import java.io.IOException; import java.util.HashSet; import java.util.Set; 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 javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import com.xxx.commons.framework.utils.CookieUtils; import com.xxx.commons.framework.utils.StringUtils; import com.xxx.commons.framework.utils.UserUtil; /** * Servlet Filter implementation class AuthenticationFilter */ public class PrincipalFilter implements Filter { Logger logger = Logger.getLogger(PrincipalFilter.class); private static String notLoginUrl = null; // 被忽略的全部URL. private static Set<String> mobjIgnoredUrls = new HashSet<String>(); /** * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain) */ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { UserUtil.principal.set(CookieUtils.getPrincipal((HttpServletRequest)request)); if(notLoginUrl != null && UserUtil.principal.get() == null && !isIgnoreUrl((HttpServletRequest)request)){ ((HttpServletResponse)response).sendRedirect(notLoginUrl); return; } chain.doFilter(request, response); } /** * 加入描写叙述 * @author ElongDeo 2015年6月26日 * @param filterConfig * @throws ServletException */ @Override public void init(FilterConfig filterConfig) throws ServletException { notLoginUrl = filterConfig.getInitParameter("notLoginUrl"); // 包装要被忽略的URL String urlText = filterConfig.getInitParameter("ignoredUrls"); if(urlText != null){ urlText = urlText.replaceAll("\r\n", "").replaceAll("\t", "").trim(); String[] urls = urlText.split(","); for (int i = 0; i < urls.length; i++) { mobjIgnoredUrls.add(urls[i]); } } } /** * <pre> * 验证是否要被忽略的URL. * </pre> * * @param pobjRequest * the pobjRequest * @return true, if is ignore url * @author guotianchi 2011-4-20 */ private boolean isIgnoreUrl(HttpServletRequest pobjRequest) { String objRequestUri = pobjRequest.getRequestURI(); if (StringUtils.isNotEmpty(objRequestUri)) { int index = objRequestUri.lastIndexOf(‘/‘); if (index >= 0 && index < (objRequestUri.length() - 1) && mobjIgnoredUrls.contains(objRequestUri.substring( index + 1, objRequestUri.length()))) { return true; } } return false; } /** * 加入描写叙述 * @author ElongDeo 2015年6月26日 */ @Override public void destroy() { } }
应用serverweb.xml配置
<filter> <filter-name>PrincipalFilter</filter-name> <filter-class>com.xxx.commons.framework.filters.PrincipalFilter</filter-class> <init-param> <param-name>notLoginUrl</param-name> <param-value>/common/logout.htm</param-value> </init-param> <init-param> <param-name>ignoredUrls</param-name> <param-value>logout.htm</param-value> </init-param> </filter> <filter-mapping> <filter-name>PrincipalFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
以上是关于java无状态登录实现方式之ThreadLocal+Cookie的主要内容,如果未能解决你的问题,请参考以下文章