提交 72f718f7 编写于 作者: shuzheng5201314's avatar shuzheng5201314

重写基于redis的sessionDAO,持久化session

上级 62c03044
...@@ -3,12 +3,15 @@ package com.zheng.upms.server.controller; ...@@ -3,12 +3,15 @@ package com.zheng.upms.server.controller;
import com.zheng.common.base.BaseController; import com.zheng.common.base.BaseController;
import com.zheng.common.util.CookieUtil; import com.zheng.common.util.CookieUtil;
import com.zheng.common.util.RedisUtil; import com.zheng.common.util.RedisUtil;
import com.zheng.upms.server.util.SystemConstant; import com.zheng.upms.common.constant.UpmsResult;
import com.zheng.upms.common.constant.UpmsResultConstant;
import com.zheng.upms.dao.model.UpmsSystemExample; import com.zheng.upms.dao.model.UpmsSystemExample;
import com.zheng.upms.rpc.api.UpmsSystemService; import com.zheng.upms.rpc.api.UpmsSystemService;
import com.zheng.upms.rpc.api.UpmsUserService; import com.zheng.upms.rpc.api.UpmsUserService;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils; import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException; import org.apache.shiro.authc.IncorrectCredentialsException;
...@@ -16,6 +19,8 @@ import org.apache.shiro.authc.LockedAccountException; ...@@ -16,6 +19,8 @@ import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException; import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject; import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.util.SavedRequest;
import org.apache.shiro.web.util.WebUtils;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
...@@ -29,11 +34,11 @@ import redis.clients.jedis.Jedis; ...@@ -29,11 +34,11 @@ import redis.clients.jedis.Jedis;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import static org.apache.shiro.web.util.WebUtils.getSavedRequest;
/** /**
* 单点登录管理 * 单点登录管理
* Created by shuzheng on 2016/12/10. * Created by shuzheng on 2016/12/10.
...@@ -65,36 +70,38 @@ public class SSOController extends BaseController { ...@@ -65,36 +70,38 @@ public class SSOController extends BaseController {
public String index(HttpServletRequest request) throws Exception { public String index(HttpServletRequest request) throws Exception {
String system_name = request.getParameter("system_name"); String system_name = request.getParameter("system_name");
String backurl = request.getParameter("backurl"); String backurl = request.getParameter("backurl");
if (StringUtils.isBlank(system_name)) {
throw new RuntimeException("无效访问!");
}
// 判断请求认证系统是否注册 // 判断请求认证系统是否注册
UpmsSystemExample upmsSystemExample = new UpmsSystemExample(); UpmsSystemExample upmsSystemExample = new UpmsSystemExample();
upmsSystemExample.createCriteria() upmsSystemExample.createCriteria()
.andNameEqualTo(system_name); .andNameEqualTo(system_name);
int count = upmsSystemService.countByExample(upmsSystemExample); int count = upmsSystemService.countByExample(upmsSystemExample);
if (StringUtils.isEmpty(system_name) || 0 == count) { if (0 == count) {
_log.info("未注册的系统:{}", system_name); throw new RuntimeException(String.format("未注册的系统:%s", system_name));
return "/500";
} }
return "redirect:/sso/login?backurl=" + URLEncoder.encode(backurl, "utf-8"); return "redirect:/sso/login?backurl=" + URLEncoder.encode(backurl, "utf-8");
} }
@ApiOperation(value = "登录") @ApiOperation(value = "登录")
@RequestMapping(value = "/login", method = RequestMethod.GET) @RequestMapping(value = "/login", method = RequestMethod.GET)
public String login(HttpServletRequest request, HttpServletResponse response) { public String login(HttpServletRequest request) {
// 分配单点登录sessionId,首次获取后缓存到cookie,防止session丢失 // 分配单点登录sessionId,首次获取后缓存到cookie,防止session丢失
String serverSessionId = CookieUtil.getCookie(request, ZHENG_UPMS_SERVER_SESSION_ID); String serverSessionId = CookieUtil.getCookie(request, ZHENG_UPMS_SERVER_SESSION_ID);
if (StringUtils.isEmpty(serverSessionId)) { if (StringUtils.isBlank(serverSessionId)) {
serverSessionId = request.getSession().getId(); Subject subject = SecurityUtils.getSubject();
CookieUtil.setCookie(response, ZHENG_UPMS_SERVER_SESSION_ID, serverSessionId); serverSessionId = subject.getSession().getId().toString();
} }
// 有回跳路径的访问判断是否已登录,如果已登录,则回跳 // 有回跳路径的访问判断是否已登录,如果已登录,则回跳
String backurl = request.getParameter("backurl"); String backurl = request.getParameter("backurl");
String token = RedisUtil.get(ZHENG_UPMS_SERVER_SESSION_ID + "_" + serverSessionId); String token = RedisUtil.get(ZHENG_UPMS_SERVER_SESSION_ID + "_" + serverSessionId);
// token校验值 // token校验值
if (!StringUtils.isEmpty(token)) { if (!StringUtils.isBlank(token)) {
// 回跳 // 回跳
String redirectUrl = backurl; String redirectUrl = backurl;
if (StringUtils.isEmpty(backurl)) { if (StringUtils.isBlank(backurl)) {
redirectUrl = "/"; redirectUrl = "/";
} else { } else {
if (backurl.contains("?")) { if (backurl.contains("?")) {
...@@ -103,7 +110,7 @@ public class SSOController extends BaseController { ...@@ -103,7 +110,7 @@ public class SSOController extends BaseController {
redirectUrl += "?token=" + token; redirectUrl += "?token=" + token;
} }
} }
_log.info("认证中心帐号通过,带token回跳:{}", redirectUrl); _log.debug("认证中心帐号通过,带token回跳:{}", redirectUrl);
return "redirect:" + redirectUrl; return "redirect:" + redirectUrl;
} }
return "/sso/login"; return "/sso/login";
...@@ -116,54 +123,44 @@ public class SSOController extends BaseController { ...@@ -116,54 +123,44 @@ public class SSOController extends BaseController {
String backurl = request.getParameter("backurl"); String backurl = request.getParameter("backurl");
String username = request.getParameter("username"); String username = request.getParameter("username");
String password = request.getParameter("password"); String password = request.getParameter("password");
String rememberMe = request.getParameter("rememberMe");
Map result = new HashMap<>(); if (StringUtils.isBlank(username)) {
String data = ""; return new UpmsResult(UpmsResultConstant.EMPTY_USERNAME, "帐号不能为空!");
if (StringUtils.isEmpty(username)) {
result.put("result", false);
result.put("data", SystemConstant.NO_USERNAME);
return result;
} }
if (StringUtils.isEmpty(password)) { if (StringUtils.isBlank(password)) {
result.put("result", false); return new UpmsResult(UpmsResultConstant.EMPTY_PASSWORD, "密码不能为空!");
result.put("data", SystemConstant.NO_PASSWORD);
return result;
} }
// 使用shiro认证 // 使用shiro认证
Subject subject = SecurityUtils.getSubject(); Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password); UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(username, password);
try { try {
//usernamePasswordToken.setRememberMe(false); if (BooleanUtils.toBoolean(rememberMe)) {
usernamePasswordToken.setRememberMe(true);
} else {
usernamePasswordToken.setRememberMe(false);
}
subject.login(usernamePasswordToken); subject.login(usernamePasswordToken);
} catch (UnknownAccountException e) { } catch (UnknownAccountException e) {
result.put("result", false); return new UpmsResult(UpmsResultConstant.INVALID_USERNAME, "帐号不存在!");
result.put("data", SystemConstant.ERROR_USERNAME);
return result;
} catch (IncorrectCredentialsException e) { } catch (IncorrectCredentialsException e) {
result.put("result", false); return new UpmsResult(UpmsResultConstant.INVALID_PASSWORD, "密码错误!");
result.put("data", SystemConstant.ERROR_PASSWORD);
return result;
} catch (LockedAccountException e) { } catch (LockedAccountException e) {
result.put("result", false); return new UpmsResult(UpmsResultConstant.INVALID_ACCOUNT, "帐号已锁定!");
result.put("data", SystemConstant.INVALID_ACCOUNT);
return result;
}
// 分配单点登录sessionId,首次获取后缓存到cookie,防止session丢失
String serverSessionId = CookieUtil.getCookie(request, ZHENG_UPMS_SERVER_SESSION_ID);
if (StringUtils.isEmpty(serverSessionId)) {
serverSessionId = request.getSession().getId();
CookieUtil.setCookie(response, ZHENG_UPMS_SERVER_SESSION_ID, serverSessionId);
} }
// serverSessionId
String serverSessionId = subject.getSession().getId().toString();
// 默认验证帐号密码正确,创建token // 默认验证帐号密码正确,创建token
String token = UUID.randomUUID().toString(); String token = UUID.randomUUID().toString();
// 全局会话sessionId // 全局会话sessionId
RedisUtil.set(ZHENG_UPMS_SERVER_SESSION_ID + "_" + serverSessionId, token, TIMEOUT); RedisUtil.set(ZHENG_UPMS_SERVER_SESSION_ID + "_" + serverSessionId, token, TIMEOUT);
// token校验值 // token校验值
RedisUtil.set(ZHENG_UPMS_SERVER_TOKEN + "_" + token, token, TIMEOUT); RedisUtil.set(ZHENG_UPMS_SERVER_TOKEN + "_" + token, token, TIMEOUT);
// 回调子系统 // 回跳登录前地址
if (StringUtils.isEmpty(backurl)) { if (StringUtils.isBlank(backurl)) {
result.put("result", true); SavedRequest savedRequest = WebUtils.getSavedRequest(request);
result.put("data", "/"); backurl = null == savedRequest ? "/" : savedRequest.getRequestURI();
return new UpmsResult(UpmsResultConstant.SUCCESS, backurl);
} else { } else {
String redirectUrl = backurl; String redirectUrl = backurl;
if (backurl.contains("?")) { if (backurl.contains("?")) {
...@@ -171,11 +168,9 @@ public class SSOController extends BaseController { ...@@ -171,11 +168,9 @@ public class SSOController extends BaseController {
} else { } else {
redirectUrl += "?token=" + token; redirectUrl += "?token=" + token;
} }
_log.info("认证中心帐号通过,带token回跳:{}", redirectUrl); _log.debug("认证中心帐号通过,带token回跳:{}", redirectUrl);
result.put("result", true); return new UpmsResult(UpmsResultConstant.SUCCESS, redirectUrl);
result.put("data", redirectUrl);
} }
return result;
} }
@ApiOperation(value = "校验token") @ApiOperation(value = "校验token")
...@@ -184,7 +179,7 @@ public class SSOController extends BaseController { ...@@ -184,7 +179,7 @@ public class SSOController extends BaseController {
public String token(HttpServletRequest request) { public String token(HttpServletRequest request) {
String tokenParam = request.getParameter("token"); String tokenParam = request.getParameter("token");
String token = RedisUtil.get(ZHENG_UPMS_SERVER_TOKEN + "_" + tokenParam); String token = RedisUtil.get(ZHENG_UPMS_SERVER_TOKEN + "_" + tokenParam);
if (StringUtils.isEmpty(tokenParam) || !tokenParam.equals(token)) { if (StringUtils.isBlank(tokenParam) || !tokenParam.equals(token)) {
return "failed"; return "failed";
} }
return "success"; return "success";
...@@ -212,10 +207,14 @@ public class SSOController extends BaseController { ...@@ -212,10 +207,14 @@ public class SSOController extends BaseController {
} }
// 清除全局会话sessionId // 清除全局会话sessionId
CookieUtil.removeCookie(response, ZHENG_UPMS_SERVER_SESSION_ID); CookieUtil.removeCookie(response, ZHENG_UPMS_SERVER_SESSION_ID);
_log.info("当前token={},对应的注册系统个数:{}个", token, jedis.scard(ZHENG_UPMS_CLIENT_SESSION_IDS + "_" + token)); _log.debug("当前token={},对应的注册系统个数:{}个", token, jedis.scard(ZHENG_UPMS_CLIENT_SESSION_IDS + "_" + token));
jedis.close();
// 跳回原地址 // 跳回原地址
String redirectUrl = request.getHeader("Referer"); String redirectUrl = request.getHeader("Referer");
_log.info("跳回退出登录请求地址:{}", redirectUrl); if (null == redirectUrl) {
redirectUrl = "/";
}
_log.debug("跳回退出登录请求地址:{}", redirectUrl);
return "redirect:" + redirectUrl; return "redirect:" + redirectUrl;
} }
......
package com.zheng.upms.server.shiro;
import com.zheng.common.util.CookieUtil;
import com.zheng.common.util.RedisUtil;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.SimpleSession;
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import java.io.*;
import java.util.Set;
/**
* 基于redis的sessionDao,缓存共享session
* Created by shuzheng on 2017/2/23.
*/
public class SessionRedisDao extends EnterpriseCacheSessionDAO {
private static Logger _log = LoggerFactory.getLogger(SessionRedisDao.class);
// 全局会话key
private final static String ZHENG_UPMS_SERVER_SESSION_ID = "zheng-upms-server-session-id";
// token key
private final static String ZHENG_UPMS_SERVER_TOKEN = "zheng-upms-server-token";
// 局部会话key
private final static String ZHENG_UPMS_CLIENT_SESSION_ID = "zheng-upms-client-session-id";
// 单点同一个token所有局部会话key
private final static String ZHENG_UPMS_CLIENT_SESSION_IDS = "zheng-upms-client-session-ids";
@Override
protected Serializable doCreate(Session session) {
Serializable sessionId = super.doCreate(session);
RedisUtil.set(sessionToByte("shiro-sessionId-" + sessionId), sessionToByte(session));
_log.debug("[SessionRedisDao]创建session: sessionId={}", session.getId());
return sessionId;
}
@Override
protected Session doReadSession(Serializable sessionId) {
// 先从缓存中获取session,如果没有再去redis中获取
Session session = super.doReadSession(sessionId);
if(session == null){
byte[] bytes = RedisUtil.get(sessionId.toString().getBytes());
if(null != bytes && bytes.length > 0){
session = (Session) byteToSession(bytes);
_log.debug("[SessionRedisDao]redis中获取session: sessionId={}", session.getId());
}
}
return session;
}
@Override
protected void doUpdate(Session session) {
// 更新session的最后一次访问时间
super.doUpdate(session);
RedisUtil.set(session.getId().toString().getBytes(), sessionToByte(session));
_log.debug("[SessionRedisDao]redis中更新session: sessionId={}", session.getId());
}
@Override
protected void doDelete(Session session) {
// 删除session前,清空所有注册的局部会话
String serverSessionId = session.getId().toString();
// 当前全局会话token
String token = RedisUtil.get(ZHENG_UPMS_SERVER_SESSION_ID + "_" + serverSessionId);
// 清除全局会话
RedisUtil.remove(ZHENG_UPMS_SERVER_SESSION_ID + "_" + serverSessionId);
// 清除token校验值
RedisUtil.remove(ZHENG_UPMS_SERVER_TOKEN + "_" + token);
// 清除所有局部会话
Jedis jedis = RedisUtil.getJedis();
Set<String> clientSessionIds = jedis.smembers(ZHENG_UPMS_CLIENT_SESSION_IDS + "_" + token);
for (String clientSessionId : clientSessionIds) {
jedis.del(ZHENG_UPMS_CLIENT_SESSION_ID + "_" + clientSessionId);
jedis.srem(ZHENG_UPMS_CLIENT_SESSION_IDS + "_" + token, clientSessionId);
}
_log.debug("当前token={},对应的注册系统个数:{}个", token, jedis.scard(ZHENG_UPMS_CLIENT_SESSION_IDS + "_" + token));
jedis.close();
// 删除session
super.doDelete(session);
RedisUtil.remove(session.getId().toString().getBytes());
_log.debug("[SessionRedisDao]redis中删除session: sessionId={}", session.getId());
}
// 把Object对象转化为byte保存到redis中
public byte[] sessionToByte(Object session) {
ByteArrayOutputStream bo = new ByteArrayOutputStream();
byte[] bytes = null;
try {
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(session);
bytes = bo.toByteArray();
} catch (IOException e) {
e.printStackTrace();
}
return bytes;
}
// 把byte还原为Object
public Object byteToSession(byte[] bytes) {
ByteArrayInputStream bi = new ByteArrayInputStream(bytes);
ObjectInputStream in;
SimpleSession session = null;
try {
in = new ObjectInputStream(bi);
session = (SimpleSession) in.readObject();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return session;
}
}
...@@ -19,19 +19,11 @@ ...@@ -19,19 +19,11 @@
</property> </property>
<property name="filterChainDefinitions"> <property name="filterChainDefinitions">
<value> <value>
<!-- isAuthenticated --> /swagger-ui.html = user
/manage/**=authc /druid/** = user
<!-- isAuthenticated或RememberMe --> /manage/index = user
/druid/**=user /manage/** = authc
<!-- logout --> /** = anon
/sso/logout = logout
<!-- anon -->
/ = anon
/swagger-ui.html = anon
/webjars/** = anon
/resources/** = anon
/sso/** = anon
/403 = anon
</value> </value>
</property> </property>
</bean> </bean>
...@@ -47,7 +39,7 @@ ...@@ -47,7 +39,7 @@
</bean> </bean>
<!-- realm实现,继承自AuthorizingRealm --> <!-- realm实现,继承自AuthorizingRealm -->
<bean id="upmsRealm" class="com.zheng.upms.server.realm.UpmsRealm"></bean> <bean id="upmsRealm" class="com.zheng.upms.server.shiro.realm.UpmsRealm"></bean>
<!-- 会话管理器 --> <!-- 会话管理器 -->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
...@@ -76,13 +68,7 @@ ...@@ -76,13 +68,7 @@
</bean> </bean>
<!-- 会话DAO,可重写,持久化session --> <!-- 会话DAO,可重写,持久化session -->
<bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.MemorySessionDAO"> <bean id="sessionDAO" class="com.zheng.upms.server.shiro.SessionRedisDao"/>
<!--<property name="shiroSessionRepository" ref="jedisShiroSessionRepository"/>-->
<property name="sessionIdGenerator" ref="sessionIdGenerator"/>
</bean>
<!-- 会话ID生成器 -->
<bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/>
<!-- 会话Cookie模板 --> <!-- 会话Cookie模板 -->
<bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
...@@ -91,11 +77,11 @@ ...@@ -91,11 +77,11 @@
<!-- 设置Cookie的过期时间,秒为单位,默认-1表示关闭浏览器时过期Cookie --> <!-- 设置Cookie的过期时间,秒为单位,默认-1表示关闭浏览器时过期Cookie -->
<property name="maxAge" value="-1"/> <property name="maxAge" value="-1"/>
<!-- Cookie名称 --> <!-- Cookie名称 -->
<property name="name" value="zheng-upms-shiro-sessionId"/> <property name="name" value="zheng-upms-server-session-id"/>
</bean> </bean>
<!-- 会话监听器 --> <!-- 会话监听器 -->
<bean id="sessionListener" class="com.zheng.upms.server.listener.ShiroSessionListener"/> <bean id="sessionListener" class="com.zheng.upms.server.shiro.listener.ShiroSessionListener"/>
<!-- rememberMe管理器 --> <!-- rememberMe管理器 -->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager"> <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
...@@ -124,8 +110,6 @@ ...@@ -124,8 +110,6 @@
<property name="loginUrl" value="/sso/login"/> <property name="loginUrl" value="/sso/login"/>
</bean> </bean>
<!-- 设置SecurityUtils,相当于调用SecurityUtils.setSecurityManager(securityManager) --> <!-- 设置SecurityUtils,相当于调用SecurityUtils.setSecurityManager(securityManager) -->
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/> <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册