spring boot整合shiro
安全框架Shiro和Spring Security比較,本文主要圍繞Shiro進行學習
一 Shiro 是一個強大而靈活的開源安全框架,能夠清晰的處理認證 授權 管理會話以及,密碼加密
01 .認證與授權相關概念
安全實體: 系統需要保護的具體物件資料
許可權: 系統相關的功能操作,例如基本的CRUD
Authentication:身份認證授權/登入,驗證使用者是否擁有相應的身份
Authorization: 授權,即許可權的認證,認證某個已認證的使用者是否擁有某個許可權
Session Manager : 會話管理.即使用者登入後就是一次會話,在沒有退出之前,所有資訊都在會話中
Cryptography: 加密,保護資料的安全性
Web Support:web支援
Caching: 快取
Concurrency: shiro支援多執行緒併發驗證,一個執行緒中開啟另一個執行緒,能把許可權自動傳播過去:
Remember Me:記住我
02. shiro四大核心,.如下是shiro架構
03 Shiro三個核心元件:Subject .SecurityManager和Realms
Subject: 主體,代表當前"使用者",所有Subject都繫結到SecurityManager,是一個抽象的概念,與當前應用互動任何東西都是Subject,如網路爬蟲,機器人,與Subject的所有互動都會委託給SecurityManager;
SecurityManager:安全管理器: 即所有與安全有關的操作都會與SecuityManager互動,管理所有的Subject;是Shiro的核心,它負責與後邊介紹的其他元件進行互動
Realm: 域 , shiro從Realm獲取安全資料(如 使用者,角色,許可權)SecurityManager要驗證使用者身份,那麼他需要從Realm獲取相應的使用者,已確定使使用者身份是否合法,也需要從Realm得到使用者相應的角色/許可權進行驗證用於是否能進行操作,可以吧Realm看成DataSource.,即安全資料來源
04 以下已springboot的一個專案中shiro運用為例
下面是pom.xml中相關jar
<!--shiro -->org.apache.shiro shiro-core 1.3.2 <!-- shiro ehcache --> org.apache.shiro shiro-spring 1.3.2 org.apache.shiro shiro-ehcache 1.3.2 com.github.theborakompanioni thymeleaf-extras-shiro 1.2.1
ShiroConfig配置檔案
import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;import com.prostate.common.config.Constant;import com.prostate.common.redis.shiro.RedisCacheManager;import com.prostate.common.redis.shiro.RedisManager;import com.prostate.common.redis.shiro.RedisSessionDAO;import com.prostate.system.shiro.UserRealm;//import org.apache.shiro.cache.CacheManager;import net.sf.ehcache.CacheManager;import org.apache.shiro.cache.ehcache.EhCacheManager;import org.apache.shiro.mgt.SecurityManager;import org.apache.shiro.session.SessionListener;import org.apache.shiro.session.mgt.eis.MemorySessionDAO;import org.apache.shiro.session.mgt.eis.SessionDAO;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.session.mgt.DefaultWebSessionManager;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Value;import org.springframework.cache.ehcache.EhCacheCacheManager;import org.springframework.cache.ehcache.EhCacheManagerFactoryBean;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.io.ClassPathResource;import java.util.ArrayList;import java.util.Collection;import java.util.LinkedHashMap;/** * @author*/ @Configurationpublic class ShiroConfig { @Value("${spring.redis.host}") private String host; @Value("${spring.redis.password}") private String password; @Value("${spring.redis.port}") private int port; @Value("${spring.redis.timeout}") private int timeout; @Value("${spring.cache.type}") private String cacheType; @Value("${server.session-timeout}") private int tomcatTimeout;// @Autowired// CacheManager cacheManager; @Bean public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } /** * ShiroDialect,為了在thymeleaf裡使用shiro的標籤的bean * * @return */ @Bean public ShiroDialect shiroDialect() { return new ShiroDialect(); } // ShiroFilterFactoryBean 為了生成ShiroFilter,處理攔截資原始檔問題 //它主要保持三項資料,securityManager,filters,fiterChainDefinition // Shiro驗證URL時,匹配成功就不在匹配,自上而下 // @Bean ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/login"); shiroFilterFactoryBean.setSuccessUrl("/index"); shiroFilterFactoryBean.setUnauthorizedUrl("/403"); LinkedHashMapfilterChainDefinitionMap = new LinkedHashMap(); filterChainDefinitionMap.put("/css/**", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/fonts/**", "anon"); filterChainDefinitionMap.put("/img/**", "anon"); filterChainDefinitionMap.put("/docs/**", "anon"); filterChainDefinitionMap.put("/druid/**", "anon"); filterChainDefinitionMap.put("/upload/**", "anon"); filterChainDefinitionMap.put("/files/**", "anon"); filterChainDefinitionMap.put("/logout", "logout"); filterChainDefinitionMap.put("/", "anon"); filterChainDefinitionMap.put("/blog", "anon"); filterChainDefinitionMap.put("/blog/open/**", "anon"); filterChainDefinitionMap.put("/**", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public SecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //設定realm. securityManager.setRealm(userRealm()); // 自定義快取實現 使用redis if (Constant.CACHE_TYPE_REDIS.equals(cacheType)) { securityManager.setCacheManager(cacheManager()); } else { securityManager.setCacheManager(ehCacheManager()); } securityManager.setSessionManager(sessionManager()); return securityManager; } @Bean UserRealm userRealm() { UserRealm userRealm = new UserRealm(); return userRealm; } /** * 開啟shiro aop註解支援. * 使用代理方式;所以需要開啟程式碼支援; * * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } /** * 配置shiro redisManager * * @return */ @Bean public RedisManager redisManager() { RedisManager redisManager = new RedisManager(); redisManager.setHost(host); redisManager.setPort(port); redisManager.setExpire(1800);// 配置快取過期時間 //redisManager.setTimeout(1800); redisManager.setPassword(password); return redisManager; } /** * cacheManager 快取 redis實現 * 使用的是shiro-redis開源外掛 * * @return */ public RedisCacheManager cacheManager() { RedisCacheManager redisCacheManager = new RedisCacheManager(); redisCacheManager.setRedisManager(redisManager()); return redisCacheManager; } /** * RedisSessionDAO shiro sessionDao層的實現 透過redis * 使用的是shiro-redis開源外掛 */ @Bean public RedisSessionDAO redisSessionDAO() { RedisSessionDAO redisSessionDAO = new RedisSessionDAO(); redisSessionDAO.setRedisManager(redisManager()); return redisSessionDAO; } @Bean public SessionDAO sessionDAO() { if (Constant.CACHE_TYPE_REDIS.equals(cacheType)) { return redisSessionDAO(); } else { return new MemorySessionDAO(); } } /** * shiro session的管理 */ @Bean public DefaultWebSessionManager sessionManager() { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); sessionManager.setGlobalSessionTimeout(tomcatTimeout * 1000); sessionManager.setSessionDAO(sessionDAO()); Collection listeners = new ArrayList (); listeners.add(new BDSessionListener()); sessionManager.setSessionListeners(listeners); return sessionManager; } @Bean public EhCacheManager ehCacheManager() { EhCacheManager em = new EhCacheManager(); em.setCacheManager(CacheManager.create()); return em; } }
這裡補充一下ehcache和redis比較
ehcache直接在jvm虛擬機器中快取,速度快,效率高,但是快取共享麻煩,叢集分散式應用不方便
redis是透過socket訪問快取務,效率比ehcachedi,處理叢集和分散式快取方便,有成熟的方案
UserRealm
import java.util.HashMap;import java.util.Map;import java.util.Set;import com.prostate.common.config.ApplicationContextRegister;import com.prostate.system.domain.UserToken;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.IncorrectCredentialsException;import org.apache.shiro.authc.LockedAccountException;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authc.UnknownAccountException;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.springframework.beans.factory.annotation.Autowired;import com.prostate.common.utils.ShiroUtils;import com.prostate.system.dao.UserDao;import com.prostate.system.domain.UserDO;import com.prostate.system.service.MenuService;/** * 自定義realm 安全的資料庫 */public class UserRealm extends AuthorizingRealm {/* @Autowired UserDao userMapper; @Autowired MenuService menuService;*/ /** * * @param arg0 * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) { Long userId = ShiroUtils.getUserId(); MenuService menuService = ApplicationContextRegister.getBean(MenuService.class); Setperms = menuService.listPerms(userId); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); info.setStringPermissions(perms); return info; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String) token.getPrincipal(); Map map = new HashMap(16); map.put("username", username); String password = new String((char[]) token.getCredentials()); UserDao userMapper = ApplicationContextRegister.getBean(UserDao.class); // 查詢使用者資訊 UserDO user = userMapper.list(map).get(0); // 賬號不存在 if (user == null) { throw new UnknownAccountException("賬號或密碼不正確"); } // 密碼錯誤 if (!password.equals(user.getPassword())) { throw new IncorrectCredentialsException("賬號或密碼不正確"); } // 賬號鎖定 if (user.getStatus() == 0) { throw new LockedAccountException("賬號已被鎖定,請聯絡管理員"); } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password, getName()); return info; } }
ShiroUtils
package com.prostate.common.utils;import com.prostate.system.domain.UserToken;import org.apache.commons.beanutils.BeanUtils;import org.apache.shiro.SecurityUtils;import org.apache.shiro.session.Session;import org.apache.shiro.session.mgt.eis.SessionDAO;import org.apache.shiro.subject.Subject;import com.prostate.system.domain.UserDO;import org.springframework.beans.factory.annotation.Autowired;import java.lang.reflect.InvocationTargetException;import java.security.Principal;import java.util.Collection;import java.util.List;public class ShiroUtils { @Autowired private static SessionDAO sessionDAO; public static Subject getSubjct() { return SecurityUtils.getSubject(); } public static UserDO getUser() { Object object = getSubjct().getPrincipal(); return (UserDO)object; } public static Long getUserId() { return getUser().getUserId(); } public static void logout() { getSubjct().logout(); } public static ListgetPrinciples() { List principals = null; Collection sessions = sessionDAO.getActiveSessions(); return principals; } }
Shiro 分析
①: Shiro常見的丟擲異常
UnknownAccountException(賬號不存在) IncorrectCredentialsException(密碼不存在) DisabledAccountException(帳號被禁用) LockedAccountException(帳號被鎖定) ExcessiveAttemptsException(登入失敗次數過多) ExpiredCredentialsException(憑證過期)等
②:Shiro標籤
登入之後 不在登入狀態時 使用者在沒有RememberMe時 使用者在RememberMe時 在有abc或者123角色時 擁有角色abc 沒有角色abc 擁有許可權abc 沒有許可權abc 顯示使用者登入名
③ Shiro過濾器鏈中的幾種內建過濾器
--(1)認證過濾器 anon 匿名過濾器 authc 需要認證 authcBasic 表示httpBasic認證 user 表示必須存在使用者,當登入操作時不做檢查--(2)授權過濾器 roles /admins/user/**=authc,roles[admin] (必須認證過,並擁有admin 角色) perms port rest ssl --(3) shiro 登入退出 shiro 內建的logout 過濾器(先配置logout,再在過濾器鏈中配置)filterChainDefinitions 配置 /logout = logout --(4) 關於登入過濾器的配置 通常將登入請求和使用的資源(js.css等)放開設定為anon,將其他的所有資源/** 設定為authc --(5)關於Session 失效的問題 每次請求都會經過過濾器鏈的過濾,對於authc的資源,如果登入失效,自動返回到預設登入首頁 配置的loginUrl 中; 或者可以自定義個session 攔截的過濾器放入shiro 的過濾器鏈
二 Spring Security是一個能夠為Spring的企業應用系統提供宣告式安全訪問控制解決方案的安全框架.它提供一組Spring應用上下文中配置Bean,充分利用Spring Ioc,DI,AOP,減少了為企業系統安全控制編寫大量重複程式碼,它是一個輕量級的安全框架,他確保基於Spring的應用程式提供身份驗證和授權支援,並配備了流行的安全演算法實現捆綁在一起
後續詳解 Spring Security
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4369/viewspace-2802507/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- spring boot 整合shiroSpring Boot
- spring boot 框架spring date jpa整合shiroSpring Boot框架
- Spring Boot:整合Shiro許可權框架Spring Boot框架
- Spring Boot整合shiro出現UnavailableSecurityManagerExceptionSpring BootAIException
- Java後端避坑——Spring Boot整合ShiroJava後端Spring Boot
- Spring Boot 最簡單整合 Shiro+JWT 方式Spring BootJWT
- Spring Boot 整合 Shiro ,兩種方式全總結!Spring Boot
- Spring Boot (十四): Spring Boot 整合 Shiro-登入認證和許可權管理Spring Boot
- spring-boot-plus整合Shiro+JWT許可權管理SpringbootJWT
- Spring Boot 整合 Shiro實現認證及授權管理Spring Boot
- Spring Boot 2.0(八):Spring Boot 整合 MemcachedSpring Boot
- Spring Boot(十八):使用 Spring Boot 整合 FastDFSSpring BootAST
- Spring Boot整合rabbitmqSpring BootMQ
- Spring Boot 整合 rabbitmqSpring BootMQ
- Spring Boot 整合 elasticsearchSpring BootElasticsearch
- Spring Boot 整合 dockerSpring BootDocker
- Spring Boot 整合 elkSpring Boot
- Spring Boot 整合 ApolloSpring Boot
- Spring Boot整合RedisSpring BootRedis
- Spring Boot 整合redisSpring BootRedis
- Spring Boot 整合 MyBatisSpring BootMyBatis
- Spring Boot整合SocketSpring Boot
- spring boot整合jooqSpring Boot
- Spring Boot 整合 KafkaSpring BootKafka
- spring boot 整合mybatisSpring BootMyBatis
- Spring Boot整合Spring BatchSpring BootBAT
- Spring Boot整合Spring SecuritySpring Boot
- Spring Boot整合Spring AopSpring Boot
- Shiro和Spring MVC、Mybatis整合教程SpringMVCMyBatis
- Shiro(環境搭建與Spring整合)Spring
- Spring boot學習(三) Spring boot整合mybatisSpring BootMyBatis
- Spring Boot:整合Spring Data JPASpring Boot
- spring-boot+spring-session整合SpringbootSession
- Spring Boot 整合 Apache DubboSpring BootApache
- Spring Boot Actuator 整合 PrometheusSpring BootPrometheus
- spring boot整合HadoopSpring BootHadoop
- ElasticSearch與Spring Boot整合ElasticsearchSpring Boot
- spring boot(三)整合 redisSpring BootRedis