merge
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
package com.xwbing.shiro;
|
||||
|
||||
import com.xwbing.domain.entity.sys.SysUser;
|
||||
import org.apache.shiro.cache.Cache;
|
||||
import org.apache.shiro.cache.CacheManager;
|
||||
import org.apache.shiro.session.Session;
|
||||
import org.apache.shiro.session.mgt.DefaultSessionKey;
|
||||
import org.apache.shiro.session.mgt.SessionManager;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.apache.shiro.web.filter.AccessControlFilter;
|
||||
import org.apache.shiro.web.util.WebUtils;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import java.io.Serializable;
|
||||
import java.util.Deque;
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* 项目名称: boot-module-demo
|
||||
* 创建时间: 2018/4/3 18:02
|
||||
* 作者: xiangwb
|
||||
* 说明: 防止二次登陆的功能
|
||||
*/
|
||||
public class KickoutSessionControlFilter extends AccessControlFilter {
|
||||
private String kickoutUrl; // 踢出后到的地址
|
||||
private boolean kickoutAfter; // 踢出之前登录的/之后登录的用户 默认踢出之前登录的用户
|
||||
private int maxSession = 1; // 同一个帐号最大会话数 默认1
|
||||
private SessionManager sessionManager;
|
||||
private Cache<String, Deque<Serializable>> cache;
|
||||
|
||||
public void setKickoutUrl(String kickoutUrl) {
|
||||
this.kickoutUrl = kickoutUrl;
|
||||
}
|
||||
|
||||
public void setKickoutAfter(boolean kickoutAfter) {
|
||||
this.kickoutAfter = kickoutAfter;
|
||||
}
|
||||
|
||||
public void setMaxSession(int maxSession) {
|
||||
this.maxSession = maxSession;
|
||||
}
|
||||
|
||||
public void setSessionManager(SessionManager sessionManager) {
|
||||
this.sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
public void setCacheManager(CacheManager cacheManager) {
|
||||
this.cache = cacheManager.getCache("shiro-kickout-session");
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否允许访问,返回true表示允许
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @param mappedValue
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 表示访问拒绝时是否自己处理,如果返回true表示自己不处理且继续拦截器链执行,返回false表示自己已经处理了(比如重定向到另一个页面)。
|
||||
*
|
||||
* @param request
|
||||
* @param response
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
|
||||
Subject subject = getSubject(request, response);
|
||||
if (!subject.isAuthenticated() && !subject.isRemembered()) {
|
||||
// 如果没有登录,直接进行之后的流程
|
||||
return true;
|
||||
}
|
||||
Session session = subject.getSession();
|
||||
Object object = subject.getPrincipal();
|
||||
SysUser sysUser = (SysUser) object;
|
||||
Serializable sessionId = session.getId();
|
||||
// 初始化用户的队列放到缓存里
|
||||
Deque<Serializable> deque = cache.get(sysUser.getUserName());
|
||||
if (deque == null || deque.size() == 0) {
|
||||
deque = new LinkedList<>();
|
||||
cache.put(sysUser.getUserName(), deque);
|
||||
}
|
||||
// 如果队列里没有此sessionId,且用户没有被踢出;放入队列
|
||||
if (!deque.contains(sessionId) && session.getAttribute("kickout") == null) {
|
||||
deque.push(sessionId);
|
||||
}
|
||||
// 如果队列里的sessionId数超出最大会话数,开始踢人
|
||||
while (deque.size() > maxSession) {
|
||||
Serializable kickoutSessionId;
|
||||
if (kickoutAfter) { // 如果踢出后者
|
||||
kickoutSessionId = deque.removeFirst();
|
||||
} else { // 否则踢出前者
|
||||
kickoutSessionId = deque.removeLast();
|
||||
}
|
||||
try {
|
||||
Session kickoutSession = sessionManager.getSession(new DefaultSessionKey(kickoutSessionId));
|
||||
if (kickoutSession != null) {
|
||||
// 设置会话的kickout属性表示踢出了
|
||||
kickoutSession.setAttribute("kickout", true);
|
||||
}
|
||||
} catch (Exception e) {// ignore exception
|
||||
}
|
||||
}
|
||||
// 如果被踢出了,直接退出,重定向到踢出后的地址
|
||||
if (session.getAttribute("kickout") != null) {
|
||||
// 会话被踢出了
|
||||
try {
|
||||
subject.logout();
|
||||
} catch (Exception e) { // ignore
|
||||
}
|
||||
saveRequest(request);
|
||||
WebUtils.issueRedirect(request, response, kickoutUrl);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -8,8 +8,6 @@ import com.xwbing.service.sys.SysAuthorityService;
|
||||
import com.xwbing.service.sys.SysRoleService;
|
||||
import com.xwbing.service.sys.SysUserService;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.authc.AuthenticationException;
|
||||
import org.apache.shiro.authc.AuthenticationInfo;
|
||||
import org.apache.shiro.authc.AuthenticationToken;
|
||||
@@ -92,11 +90,11 @@ public class MyShiroRealm extends AuthorizingRealm {
|
||||
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
|
||||
UsernamePasswordCaptchaToken captchaToken = (UsernamePasswordCaptchaToken) authenticationToken;
|
||||
//1.校验验证码
|
||||
String captcha = captchaToken.getCaptcha();
|
||||
String imgCode = (String) SecurityUtils.getSubject().getSession().getAttribute(CommonConstant.KEY_CAPTCHA);
|
||||
if (StringUtils.isEmpty(captcha) || !captcha.equalsIgnoreCase(imgCode)) {
|
||||
throw new AuthenticationException("验证码错误");
|
||||
}
|
||||
// String captcha = captchaToken.getCaptcha();
|
||||
// String imgCode = (String) SecurityUtils.getSubject().getSession().getAttribute(CommonConstant.KEY_CAPTCHA);
|
||||
// if (StringUtils.isEmpty(captcha) || !captcha.equalsIgnoreCase(imgCode)) {
|
||||
// throw new AuthenticationException("验证码错误");
|
||||
// }
|
||||
//2.查是否有此用户
|
||||
SysUser user = sysUserService.getByUserName(captchaToken.getUsername());
|
||||
if (user == null) {
|
||||
|
||||
@@ -67,6 +67,7 @@ public class ShiroConfig {
|
||||
|
||||
Map<String, Filter> filters = new HashMap<>();
|
||||
filters.put("sessionFilter", sessionFilter());
|
||||
filters.put("kickout", kickoutSessionControlFilter());
|
||||
filters.put("authc", urlPermissionsFilter());
|
||||
filters.put("anon", new AnonymousFilter());
|
||||
shiroFilterFactoryBean.setFilters(filters);
|
||||
@@ -95,7 +96,7 @@ public class ShiroConfig {
|
||||
//登出
|
||||
chains.put("/user/logout", "anon");
|
||||
//必须通过验证或者rememberMe
|
||||
chains.put("/**", "user,authc,sessionFilter");
|
||||
chains.put("/**", "user,authc,sessionFilter,kickout");
|
||||
shiroFilterFactoryBean.setFilterChainDefinitionMap(chains);
|
||||
return shiroFilterFactoryBean;
|
||||
}
|
||||
@@ -203,6 +204,26 @@ public class ShiroConfig {
|
||||
return new SessionFilter();
|
||||
}
|
||||
|
||||
///////////////////////kickoutSessionControlFilter///////////////////
|
||||
@Bean
|
||||
public FilterRegistrationBean kickoutSessionControlFilterRegistrationBean(KickoutSessionControlFilter kickoutSessionControlFilter) {
|
||||
FilterRegistrationBean registration = new FilterRegistrationBean(kickoutSessionControlFilter);
|
||||
//设置不自动在在配置时执行,默认是true
|
||||
registration.setEnabled(false);
|
||||
return registration;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KickoutSessionControlFilter kickoutSessionControlFilter() {
|
||||
KickoutSessionControlFilter kickoutSessionControlFilter = new KickoutSessionControlFilter();
|
||||
kickoutSessionControlFilter.setCacheManager(cacheManager());
|
||||
kickoutSessionControlFilter.setSessionManager(sessionManager());
|
||||
kickoutSessionControlFilter.setKickoutAfter(false);
|
||||
kickoutSessionControlFilter.setMaxSession(1);
|
||||
kickoutSessionControlFilter.setKickoutUrl("/kickout.html");
|
||||
return kickoutSessionControlFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shiro生命周期处理器
|
||||
*
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>kickout</title>
|
||||
</head>
|
||||
<body>
|
||||
<h2>你的账号在另一个地方登录,请确认是否本人登录!</h2>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user