1. 程式人生 > >用shiro+springboot+mybatis實現禁止賬號重複登入

用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(模型),是程式的主體部分,主要包含業務資料和業務邏輯。在模型層,還會涉及到使用者釋出的服務,在服務中會根據不