注:本文提到的无状态指的是无需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;
/**
* 加入类描写叙述
* @authorElongDeo
* @version1.0
* Created2014年12月18日 下午1:24:27
*/
public class UserUtil {
public static final ThreadLocal principal = new ThreadLocal();
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;
/**
*
*
Author : ElongDeo
*
Date : 2014-3-10
*
Cookie操作辅助类
*
*/
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 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 readCookieMap(HttpServletRequest request){
Map cookieMap = new HashMap();
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();
}
}
}
登录写入cookie代码片段
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(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 mobjIgnoredUrls = new HashSet();
/**
* @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]);
}
}
}
/**
*
* 验证是否要被忽略的URL.
*
*
* @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配置
PrincipalFilter
com.xxx.commons.framework.filters.PrincipalFilter
notLoginUrl
/common/logout.htm
ignoredUrls
logout.htm
PrincipalFilter
/*