springboot shiro 重复登录 剔除

springboot整合shiro后。

当同一个用户重复登录时,默认会两个都登录成功,两个session。

目标是:当第二次登录时,把第一个session剔除。不允许重复登录

小知识:同一个浏览器,用两个标签页分别登录,是同一个session。

两个浏览器登录,是两个session。

ShiroConfiguration.java

package com.zfzn.hospital_backend.application;


import com.zfzn.hospital_backend.shiro.AuthRealm;
import com.zfzn.hospital_backend.shiro.CredentialsMatcher;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import java.util.LinkedHashMap;

/**
* shiro的配置类
* @author Administrator
*
*/
@Configuration
public class ShiroConfiguration {
private static final Logger logger = LoggerFactory.getLogger(ShiroConfiguration.class);
/**
* ShiroFilterFactoryBean,是个factorybean,为了生成ShiroFilter。
* 它主要保持了三项数据,securityManager,filters,filterChainDefinitionManager。
*
* @return
*/
@Bean(name="shiroFilter")
public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") org.apache.shiro.mgt.SecurityManager manager) {
logger.info("ShiroConfiguration.shiroFilter()");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 必须设置SecuritManager
shiroFilterFactoryBean.setSecurityManager(manager);

// Map<String, Filter> filtersMap = shiroFilterFactoryBean.getFilters();
// filtersMap.put("authc", myFormAuthenticationFilter(manager));// 自定义拦截器
// shiroFilterFactoryBean.setFilters(filtersMap);

// 拦截器
//配置登录的url和登录成功的url
shiroFilterFactoryBean.setLoginUrl("/user/login");
// bean.setSuccessUrl("/home");
//配置访问权限
LinkedHashMap<String, String> filterChainDefinitionMap=new LinkedHashMap<>();
// filterChainDefinitionMap.put("/jsp/login.jsp*", "anon"); //表示可以匿名访问
// filterChainDefinitionMap.put("/loginUser", "anon");
// filterChainDefinitionMap.put("/logout*","anon");
// filterChainDefinitionMap.put("/jsp/error.jsp*","anon");
// filterChainDefinitionMap.put("/jsp/index.jsp*","authc");
// filterChainDefinitionMap.put("/*", "authc");//表示需要认证才可以访问
// filterChainDefinitionMap.put("/**", "authc");//表示需要认证才可以访问
// filterChainDefinitionMap.put("/*.*", "authc");

filterChainDefinitionMap.put("/upload/**","authc");
filterChainDefinitionMap.put("/KeyDevice/**", "authc");//表示需要认证才可以访问
filterChainDefinitionMap.put("/CoolingTower/**", "authc");
filterChainDefinitionMap.put("/CoolingTowerDetail/**", "authc");
filterChainDefinitionMap.put("/Refrigerating/**", "authc");
filterChainDefinitionMap.put("/RefrigeratingDetail/**", "authc");
filterChainDefinitionMap.put("/LKInterface/**", "authc");
filterChainDefinitionMap.put("/hospitalService/**", "authc");
filterChainDefinitionMap.put("/historyData/**", "authc");
filterChainDefinitionMap.put("/deviceManage/**", "authc");
filterChainDefinitionMap.put("/dictionary/**", "authc");
filterChainDefinitionMap.put("/WebSocketService/**", "authc");
filterChainDefinitionMap.put("/AccidentRecord/**", "authc");
filterChainDefinitionMap.put("/DataUpload/**", "authc");
filterChainDefinitionMap.put("/DataUploadLog/**", "authc");
filterChainDefinitionMap.put("/NewTrendDetail/getNewTrendDetail/**", "authc");
filterChainDefinitionMap.put("/NewTrend/**", "authc");
filterChainDefinitionMap.put("/ServiceProvider/**", "authc");
filterChainDefinitionMap.put("/buildService/**", "authc");
filterChainDefinitionMap.put("/Sewage/**", "authc");
filterChainDefinitionMap.put("/SewageDetail/**", "authc");
filterChainDefinitionMap.put("/AirCondtion/**", "authc");
filterChainDefinitionMap.put("/AirCondtionDetail/**", "authc");
filterChainDefinitionMap.put("/AccidentRecord/**", "authc");
filterChainDefinitionMap.put("/system/**", "authc");
filterChainDefinitionMap.put("/Repairman/**", "authc");
filterChainDefinitionMap.put("/maintainInspection/**", "authc");
filterChainDefinitionMap.put("/RepairmanTeam/**", "authc");
filterChainDefinitionMap.put("/EnergyConsumption/**", "authc");
filterChainDefinitionMap.put("/DeviceGroup/**", "authc");
filterChainDefinitionMap.put("/device/**", "authc");
filterChainDefinitionMap.put("/AnlysisRepair/**", "authc");
filterChainDefinitionMap.put("/AnlysisMaintain/**", "authc");
filterChainDefinitionMap.put("/propertyManage/**", "authc");
filterChainDefinitionMap.put("/Boiler/**", "authc");
filterChainDefinitionMap.put("/BoilerDetail/**", "authc");
filterChainDefinitionMap.put("/QueryConfigure/**", "authc");
filterChainDefinitionMap.put("/elevator/**", "authc");


// // 如果不设置默认会自动寻找工程根目录下的"/login"页面
// shiroFilterFactoryBean.setLoginUrl("/login");
// // 登录成功后要跳转的链接
// shiroFilterFactoryBean.setSuccessUrl("/index");
// // 未授权界面;
// shiroFilterFactoryBean.setUnauthorizedUrl("/403");
// 加载shiroFilter权限控制规则
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;

}

//配置核心安全事务管理器
@Bean(name="securityManager")
public org.apache.shiro.mgt.SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm) {
System.err.println("--------------shiro已经加载----------------");
DefaultWebSecurityManager manager=new DefaultWebSecurityManager();
manager.setRealm(authRealm);
manager.setSessionManager(sessionManager());
// <!-- 用户授权/认证信息Cache, 采用EhCache 缓存 -->
manager.setCacheManager(ehCacheManager());
//注入记住我管理器;
manager.setRememberMeManager(rememberMeManager());
return manager;
}

@Bean(name = "sessionManager")
public DefaultWebSessionManager sessionManager() {
DefaultWebSessionManager sessionManager=new DefaultWebSessionManager();
return sessionManager;
}
//配置自定义的权限登录器
@Bean(name="authRealm")
public AuthRealm authRealm(@Qualifier("credentialsMatcher") CredentialsMatcher matcher) {
System.out.println("authRealm");
AuthRealm authRealm=new AuthRealm();
authRealm.setCredentialsMatcher(matcher);
return authRealm;
}
//配置自定义的密码比较器
@Bean(name="credentialsMatcher")
public CredentialsMatcher credentialsMatcher() {
System.out.println("credentialsMatcher");
return new CredentialsMatcher();
}
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") org.apache.shiro.mgt.SecurityManager manager) {
System.out.println("authorizationAttributeSourceAdvisor");
AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(manager);
return advisor;
}

//-----------------------------------------------
/**
* LifecycleBeanPostProcessor,这是个DestructionAwareBeanPostProcessor的子类,
* 负责org.apache.shiro.util.Initializable类型bean的生命周期的,初始化和销毁。
* 主要是AuthorizingRealm类的子类,以及EhCacheManager类。
*
* @return
*/
@Bean(name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
logger.info("ShiroConfiguration.getLifecycleBeanPostProcessor()");
return new LifecycleBeanPostProcessor();
}

/**
* HashedCredentialsMatcher,这个类是为了对密码进行编码的,防止密码在数据库里明码保存,
* 当然在登陆认证的生活,这个类也负责对form里输入的密码进行编码。
*
* @return
*/
// @Bean(name = "hashedCredentialsMatcher")
// public HashedCredentialsMatcher hashedCredentialsMatcher() {
// HashedCredentialsMatcher credentialsMatcher = new
// HashedCredentialsMatcher();
// credentialsMatcher.setHashAlgorithmName("MD5");
// credentialsMatcher.setHashIterations(2);
// credentialsMatcher.setStoredCredentialsHexEncoded(true);
// return credentialsMatcher;
// }
/**
* ShiroRealm,这是个自定义的认证类,继承自AuthorizingRealm, 负责用户的认证和权限的处理
*
* @return
*/
@Bean(name = "myShiroRealm")
@DependsOn("lifecycleBeanPostProcessor")
public AuthRealm myShiroRealm() {
logger.info("ShiroConfiguration.myShiroRealm()");
AuthRealm myShiroRealm = new AuthRealm();
return myShiroRealm;
}

/**
* EhCacheManager,缓存管理,用户登陆成功后,把用户信息和权限信息缓存起来,
* 然后每次用户请求时,放入用户的session中,如果不设置这个bean,每个请求都会查询一次数据库。
*
* @return
*/
@Bean(name = "ehCacheManager")
@DependsOn("lifecycleBeanPostProcessor")
public EhCacheManager ehCacheManager() {
logger.info("ShiroConfiguration.ehCacheManager()");
EhCacheManager cacheManager = new EhCacheManager();
cacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
return cacheManager;
}

@Bean(name = "rememberMeCookie")
public SimpleCookie rememberMeCookie() {
logger.info("ShiroConfiguration.rememberMeCookie()");
// 这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
// <!-- 记住我cookie生效时间30天 ,单位秒;-->
simpleCookie.setMaxAge(259200);
return simpleCookie;
}
/**
* cookie管理对象;
*
* @return
*/
@Bean(name = "rememberMeManager")
public CookieRememberMeManager rememberMeManager() {
logger.info("ShiroConfiguration.rememberMeManager()");
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
return cookieRememberMeManager;
}




// @Bean
// public MyFormAuthenticationFilter myFormAuthenticationFilter(@Qualifier("securityManager") org.apache.shiro.mgt.SecurityManager manager) {
// MyFormAuthenticationFilter myFormAuthenticationFilter = new MyFormAuthenticationFilter();
// myFormAuthenticationFilter.setSecurityManager(manager);
// return myFormAuthenticationFilter;
// }

/**
* DefaultAdvisorAutoProxyCreator,Spring的一个bean,由Advisor决定对哪些类的方法进行AOP代理。
*
* @return
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
logger.info("ShiroConfiguration.defaultAdvisorAutoProxyCreator()");
DefaultAdvisorAutoProxyCreator daap = new DefaultAdvisorAutoProxyCreator();
daap.setProxyTargetClass(true);
return daap;
}


}

_____________________________________________________________
AuthRealm.java

package com.zfzn.hospital_backend.shiro;

import com.zfzn.hospital_backend.dao.IotdModuleDao;
import com.zfzn.hospital_backend.dao.IotdModuleRoleDao;
import com.zfzn.hospital_backend.dao.IotdRoleDao;
import com.zfzn.hospital_backend.dao.IotdUserDao;
import com.zfzn.hospital_backend.entity.IotdModuleEntity;
import com.zfzn.hospital_backend.entity.IotdModuleRoleEntity;
import com.zfzn.hospital_backend.entity.IotdRoleEntity;
import com.zfzn.hospital_backend.entity.IotdUserEntity;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.mgt.SessionsSecurityManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;

public class AuthRealm extends AuthorizingRealm {
@Autowired
private IotdUserDao iotdUserDao;
@Autowired
IotdRoleDao iotdRoleDao;

@Autowired
IotdModuleRoleDao iotdModuleRoleDao;

@Autowired
IotdModuleDao iotdModuleDao;

//认证.登录
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("------------------------------------doGetAuthenticationInfo(AuthenticationToken token)");
UsernamePasswordToken utoken = (UsernamePasswordToken) token;//获取用户输入的token
String username = utoken.getUsername();
System.out.println("username=" + username);
System.out.println("password=" + utoken.getPassword());

//处理session
SessionsSecurityManager securityManager = (SessionsSecurityManager) SecurityUtils.getSecurityManager();
DefaultSessionManager sessionManager = (DefaultSessionManager) securityManager.getSessionManager();
Collection<Session> sessions = sessionManager.getSessionDAO().getActiveSessions();//获取当前已登录的用户session列表
for (Session session : sessions) {
//清除该用户以前登录时保存的session
// IotdUserEntity en=(IotdUserEntity)(session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY));
// String phone=en.getPhone();
//如果和当前session是同一个session,则不剔除
if (SecurityUtils.getSubject().getSession().getId().equals(session.getId()))
break;
IotdUserEntity user = (IotdUserEntity) (session.getAttribute("user"));
if (user != null) {
String phone = user.getPhone();
if (username.equals(phone)) {
System.out.println(username + "已登录,剔除中...");
sessionManager.getSessionDAO().delete(session);
}
}
}


// User user = userService.findUserByUserName(username);
IotdUserEntity user = iotdUserDao.findDistinctByPhone(username);
SimpleAuthenticationInfo rst = new SimpleAuthenticationInfo(user, user.getPwd(), this.getClass().getName());//放入shiro.调用CredentialsMatcher检验密码
return rst;
}

//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
System.out.println("----------------------doGetAuthorizationInfo(PrincipalCollection principal)");
IotdUserEntity user = (IotdUserEntity) principal.fromRealm(this.getClass().getName()).iterator().next();//获取session中的用户
List<String> permissions = new ArrayList<>();
// Set<Role> roles = user.getRoleid();
Integer roleid = user.getRoleid();
System.out.println("roleid=" + roleid);

String roleName = "";
if (roleid > 0) {
IotdRoleEntity role = iotdRoleDao.findDistinctById(roleid);
roleName = role.getRole();
List<IotdModuleRoleEntity> moduleRoleList = iotdModuleRoleDao.findByRoleid(roleid);
for (IotdModuleRoleEntity moduleRole : moduleRoleList) {
Integer module_id = moduleRole.getModuleId();
IotdModuleEntity module = iotdModuleDao.findById(module_id);
permissions.add(module.getMname());
}
}
System.out.println("permissions=" + permissions);
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

Set<String> roles = new HashSet<>();
roles.add(roleName);
info.setRoles(roles);

info.addStringPermissions(permissions);//将权限放入shiro中.
return info;
}

}

______________________________________________________________________________
CredentialsMatcher.java

package com.zfzn.hospital_backend.shiro;


import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.SimpleCredentialsMatcher;

public class CredentialsMatcher extends SimpleCredentialsMatcher {

@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
System.out.println("doCredentialsMatch");
UsernamePasswordToken utoken=(UsernamePasswordToken) token;
//获得用户输入的密码:(可以采用加盐(salt)的方式去检验)
String inPassword = new String(utoken.getPassword());
System.out.println("获得用户输入的密码:"+inPassword);
//获得数据库中的密码
String dbPassword=(String) info.getCredentials();
System.out.println("获得数据库中的密码:"+dbPassword);
//进行密码的比对
return this.equals(inPassword, dbPassword);
}
}



原文地址:https://www.cnblogs.com/zhanying999666/p/8392592.html