用shiro+springboot+mybatis實現禁止賬號重複登入
springboot和mybatis整合在這我就不說了有興趣的自己去找一下,網上有很多
下面介紹一下和shiro整合的一些配置以及怎麼防止使用者重複登入,什麼叫防止重複登入?
嗯........ 好吧,我解釋一下就是,一個賬號在同一時間只能在一處登入,比如張三在北京登入了,還沒有下線呢,李四也用同一賬號在上海登入了,那就會把北京的張三擠下來,張三如果不服,也可以把李四擠下來。就像qq在電腦端一樣,後面的會把前面的擠下線。
好,明白了。
下面進行技術講解,哈哈哈哈
stringboot提倡習慣大於約定,所以基本沒有xml檔案配置,那些通過xml配置產生的交給Spring管理的bean都變成了這樣
@Bean(name="sessionDAO") public MemorySessionDAO getMemorySessionDAO() { return new MemorySessionDAO(); }
@Bean註解寫在函式上面即表示該函式產生的bean交給了Spring管理,預設為函式的名字為bean的id
可以用@Qualifier("bean的id")來寫在引數前
或者用@Resource("")寫在變數上面
跑偏了,跑偏了
下面直接上shiro和Spring整合的配置檔案吧
import org.apache.shiro.cache.MemoryConstrainedCacheManager;import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.session.mgt.eis.MemorySessionDAO; 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.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; 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 java.util.LinkedHashMap; @Configuration public class ShiorConfig { @Bean(name="sessionDAO") public MemorySessionDAO getMemorySessionDAO() { return new MemorySessionDAO(); } @Bean(name = "sessionIdCookie") public SimpleCookie getSimpleCookie() { SimpleCookie simpleCookie = new SimpleCookie(); simpleCookie.setName("SHRIOSESSIONID"); return simpleCookie; } //配置shiro session 的一個管理器 @Bean(name = "sessionManager") public DefaultWebSessionManager getDefaultWebSessionManager(@Qualifier("sessionDAO") MemorySessionDAO sessionDAO, @Qualifier("sessionIdCookie") SimpleCookie simpleCookie) { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); sessionManager.setSessionDAO(sessionDAO); sessionManager.setSessionIdCookie(simpleCookie); return sessionManager; } //配置session的快取管理器 @Bean(name= "shiroCacheManager") public MemoryConstrainedCacheManager getMemoryConstrainedCacheManager() { return new MemoryConstrainedCacheManager(); } @Bean(name="shiroFilter") public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager manager) { //安全事務管理器工廠類 ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean(); bean.setSecurityManager(manager); //配置未登入時攔截到的路徑 bean.setLoginUrl("/user/notlogin"); //配置訪問許可權 LinkedHashMap<String, String> filterChainDefinitionMap=new LinkedHashMap<>(); filterChainDefinitionMap.put("/user/validateCode","anon");//匿名訪問驗證碼 filterChainDefinitionMap.put("/user/insert", "anon");//匿名註冊 filterChainDefinitionMap.put("/user/login", "anon"); //匿名登入 filterChainDefinitionMap.put("/AidocPlatform/index.html", "anon"); //匿名訪問 filterChainDefinitionMap.put("/u/**", "anon"); //匿名登入 filterChainDefinitionMap.put("/*", "authc");//表示需要認證才可以訪問 filterChainDefinitionMap.put("/**", "authc");//表示需要認證才可以訪問 filterChainDefinitionMap.put("/*.*", "authc"); bean.setFilterChainDefinitionMap(filterChainDefinitionMap); return bean; } //配置核心安全事務管理器 @Bean(name="securityManager") public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm, @Qualifier("shiroCacheManager") MemoryConstrainedCacheManager shiroCacheManager, @Qualifier("sessionManager") DefaultWebSessionManager sessionManager) { System.err.println("--------------shiro已經載入----------------"); DefaultWebSecurityManager manager=new DefaultWebSecurityManager(); manager.setRealm(authRealm); manager.setCacheManager(shiroCacheManager); manager.setSessionManager(sessionManager); return manager; } //配置自定義的許可權登入器 @Bean(name="authRealm") public AuthRealm authRealm(@Qualifier("credentialsMatcher") CredentialsMatcher matcher) { AuthRealm authRealm=new AuthRealm(); authRealm.setCredentialsMatcher(matcher); return authRealm; } //配置自定義的密碼比較器 @Bean(name="credentialsMatcher") public CredentialsMatcher credentialsMatcher() { return new CredentialsMatcher(); } @Bean public LifecycleBeanPostProcessor lifecycleBeanPostProcessor(){ return new LifecycleBeanPostProcessor(); } @Bean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){ DefaultAdvisorAutoProxyCreator creator=new DefaultAdvisorAutoProxyCreator(); creator.setProxyTargetClass(true); return creator; } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager manager) { AuthorizationAttributeSourceAdvisor advisor=new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(manager); return advisor; }
自定義密碼比較器
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) { UsernamePasswordToken utoken=(UsernamePasswordToken) token; //獲得使用者輸入的密碼:(可以採用加鹽(salt)的方式去檢驗) String inPassword = new String(utoken.getPassword()); //獲得資料庫中的密碼 String dbPassword=(String) info.getCredentials(); //進行密碼的比對 return this.equals(inPassword, dbPassword); } }
自定義Realm檔案
import ai.medp.aidoc.dto.user.RoleDto; import ai.medp.aidoc.dto.user.UserDto; import ai.medp.aidoc.service.UserService; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.authz.SimpleAuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.session.mgt.eis.SessionDAO; import org.apache.shiro.subject.PrincipalCollection; import org.springframework.beans.factory.annotation.Autowired; import java.util.ArrayList; import java.util.List; import java.util.Set; public class AuthRealm extends AuthorizingRealm { @Autowired private UserService userService; @Autowired private SessionDAO sessionDAO; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) { UserDto user = (UserDto) principal.fromRealm(this.getClass().getName()).iterator().next();//獲取session中的使用者 List<String> permissions = new ArrayList<>(); Set<RoleDto> roles = user.getRoleDtos(); if (roles.size() > 0) { for (RoleDto role : roles) { permissions.add(role.getRole()); } } SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.addRoles(permissions);//將許可權放入shiro中. return info; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //獲取使用者輸入的token UsernamePasswordToken utoken = (UsernamePasswordToken) token; String username = utoken.getUsername(); //以下為只允許同一賬戶單個登入 Collection<Session> sessions = sessionDAO.getActiveSessions(); if(sessions.size()>0) { for (Session session : sessions) { System.out.println("::::::::::::::::" + session); //獲得session中已經登入使用者的名字 if(null!=session.getAttribute("user")) { String loginUsername = ((UserDto)session.getAttribute("user")).getEmail(); System.out.println("::::::::::::::::" + loginUsername); if (username.equals(loginUsername)) { //這裡的username也就是當前登入的username session.setTimeout(0); //這裡就把session清除, System.out.println("清除了"); } } } } UserDto user = userService.findUserByUserName(username); Set<RoleDto> set = userService.getUserPermissionsName(user.getId()); user.setRoleDtos(set); //放入shiro.呼叫CredentialsMatcher檢驗密碼 return new SimpleAuthenticationInfo(user, user.getPassword(), this.getClass().getName()); } }
咳咳...... 敲黑板 關鍵程式碼在這,登陸成功時我將使用者儲存到了shiro提供的session的Attribute中key值時user,所以現在拿到了session之後先判斷能不能通過“user”取到值,如果取得到再進行匹配使用者的名字(每個使用者的名字必須不同)如果匹配上了,就將該session移除,系統會為新登入的使用者新建一個session,之前的session失效之後之前的賬戶就無法繼續操作就會被迫下線,當然,這是shiro中過濾器的功勞,大體上的邏輯就是這樣,但是這種方法有個效率問題,如果一千萬使用者線上,那就要遍歷一千萬次,太慢了,以後再想到有其他什麼方法再說吧
Collection<Session> sessions = sessionDAO.getActiveSessions(); if(sessions.size()>0) { for (Session session : sessions) { System.out.println("::::::::::::::::" + session); //獲得session中已經登入使用者的名字 if(null!=session.getAttribute("user")) { String loginUsername = ((UserDto)session.getAttribute("user")).getEmail(); System.out.println("::::::::::::::::" + loginUsername); if (username.equals(loginUsername)) { //這裡的username也就是當前登入的username session.setTimeout(0); //這裡就把session清除, System.out.println("清除了"); } } } }
相關推薦
用shiro+springboot+mybatis實現禁止賬號重複登入
springboot和mybatis整合在這我就不說了有興趣的自己去找一下,網上有很多下面介紹一下和shiro整合的一些配置以及怎麼防止使用者重複登入,什麼叫防止重複登入?嗯........ 好吧,我解釋一下就是,一個賬號在同一時間只能在一處登入,比如張三在北京登入了,還沒有
基於SpringBoot + Mybatis實現 MVC 項目
myba ces find json格式 see framework pro select .info 1.預覽: (1)完整項目結構 (2) 創建數據庫、數據表: 【user.sql】 SET FOREIGN_KEY_CHECKS=0;
SpringBoot + MyBatis 實現對員工的增刪改查
implement char beans 數據庫配置 time unicode sql pom.xml multi SpringBoot + MyBatis 實現對員工的增刪改查 一、使用idea新建SpringBoot項目 File——>New——>Proje
springboot+mybatis實現動態切換數據源
nbsp targe key component mybatis run 註解 config cte 前幾天有個需求,需要使用不同的數據源,例如某業務要用A數據源,另一個業務要用B數據源。我上網收集了一些資料整合了一下,雖然最後這個需求不了了之了,但是多數據源動態切換還是蠻
SpringBoot+mybatis實現增刪改查
SpringBoot+mybatis實現增刪改查 1.建立一個專案。 2.用mybatis逆向工程建立,還不會逆向工程的看我上一篇文章 Mybatis逆向工程建立方法 3.建立好會有如下圖的三個檔案 4.新建一個controller資料夾在裡面新建一個PersonController類
springboot + jpa(hiberbate)or springboot + mybatis實現主從分離
springboot+ jpa 以及spring+mybatis 都已經實現主從,這篇主要講解下springboot +jpa的實現,兩種方式的原始碼我都會貼上github地址。 github原始碼地址: springboot + jpa : https://github.com/
springboot+mybatis實現動態切換資料來源
前幾天有個需求,需要使用不同的資料來源,例如某業務要用A資料來源,另一個業務要用B資料來源。我上網收集了一些資料整合了一下,雖然最後這個需求不了了之了,但是多資料來源動態切換還是蠻好用的,所以記錄一下,或許以後有用呢?或者自己感興趣又想玩呢! 1.加個依賴 <dependency>
springboot+mybatis實現資料庫讀寫分離
本文不包含資料庫主從配置。 實現思路:在專案中配置多資料來源,通過程式碼控制訪問哪一個資料來源。 spring-jdbc為我們提供了AbstractRoutingDataSource,DataSource的抽象實現,基於查詢鍵,返回不通不同的資料來源。編寫我們自己的動態資料來源類DynamicDataSo
springboot+mybatis實現數據庫讀寫分離
aspect def con odin scanner config help getconf mine 本文不包含數據庫主從配置。 實現思路:在項目中配置多數據源,通過代碼控制訪問哪一個數據源。 spring-jdbc為我們提供了AbstractRoutingDataSo
巧用session機制實現使用者不重複登入、記錄使用者登入日誌、統計線上人數
HttpSessionBindingListener 這個具體的使用文件自查,本篇中是新建了一個類實現本介面 public class UsersOnlineCountListener implements HttpSessionBindingListe
springboot +mybatis 實現一對多,多對一,多對多 【註解版】
MyBatis中的一對多 ,多對一,多對多【註解】 以下的例子就是針對 前端框架中所實現的 省-市-區 選擇框的資料介面 前端需要的介面型別: 後臺程式碼: dao層: ProvinceDAO /** * * @author 鄔志斌
Springboot+Mybatis實現多資料來源配置
1、預設application.properties配置檔案增加多資料來源配置,也可另行自己增加新的配置檔案獨立維護 ## master資料來源[主端業務]:用於mybatis自動程式碼生成呼叫及spring對資料庫的系列操作 master.datasource.url=j
SpringBoot+Mybatis 實現動態資料來源切換方案
背景 最近讓我做一個大資料的系統,分析了一下,麻煩的地方就是多資料來源切換抽取資料。考慮到可以跨伺服器跨資料庫抽數,再整理資料,就配置了這個動態資料來源的解決方案。在此分享給大家。 實現方案 資料庫配置檔案 我們專案使用的是yml形式的配置檔案,採用的是hikari的資料庫連線池。第一步我們自然是配置多個數據
基於Redis無序集合實現禁止多端登入
基於Redis無序集合實現禁止多端登入 應用背景 多個應用端假設名稱叫做A和B,禁止使用者從A B同時登入,A登入踢B,B登入踢A 實現思路 設定兩個無序集合a_set, b_set a b 登入的時候執行 $redis->sAdd('a_set',$user_id);//A登入
Spring+SpringMVC+MyBatis實現資料庫連線的登入功能
在使用SSM框架實現連線資料的登入功能時, 第一步首先匯入相應的jar包,然後配置web.xml檔案 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/
springMVC整合shiro與cas實現SSO單點登入
一、前言 Apache Shiro與Spring Security一樣是Java的一個安全框架。那為什麼與Spring整合卻用Shiro?其實我個人是認為Spring Security太過於笨重,要寫太多的過濾器,Shiro的配置簡單這就是我選擇的理由,何況Spring官方
安卓Android本地Sqlite實現註冊賬號和登入功能
實現了註冊賬號時將資料寫入本地SQLite,登入賬號時從本地SQLite匹配資料,並有記住密碼功能,以及通過改密口令(類似於密保問題)修改密碼的功能 思路很簡單,登入賬號的時候,先去資料庫匹配賬號,如果匹配到了相同賬號,再去匹配同一行的密碼,匹配成功則登入成功,匹配不成功則
判斷賬號重複登入 網站
判斷一個網站使用者賬號是否重複登入,有兩種表現形式: 第一種:同一個賬號,甲先在自己電腦上登入,正在使用中。。。。,乙又用該賬號在另一個地方登入,此時乙能正常登入,甲會被迫下線。
使用session監聽禁止使用者重複登入
在web應用中,常常需要禁止使用者重複登入。這裡,介紹的方法是通過配置session監聽+shiro許可權控制框架實現。具體的方法是: 使用者登入成功後,將使用者資訊放入HashMap中,如果存在重複,強制登出之前的session,使之過期。
用MVC設計模式實現簡單的JavaWeb登入註冊功能
MVC 全稱Model(模型)-View(檢視)-Controller(控制器),這是一種開發模式,他的好處是可以將介面和業務邏輯分離。 Model(模型),是程式的主體部分,主要包含業務資料和業務邏輯。在模型層,還會涉及到使用者釋出的服務,在服務中會根據不