Shiro安全框架的使用
Shiro安全框架
1.介紹
Shiro有三個(gè)核心的概念:Subject、SecurityManager和Realms。
Subject(主體):?subject本質(zhì)上是當(dāng)前正在執(zhí)行的用戶的特定于安全的“view”。它也可以表示第三方服務(wù)、守護(hù)進(jìn)程帳戶、cron作業(yè)或任何類似的東西——基本上是當(dāng)前與軟件交互的任何東西。
SecurityManager(安全管理器): SecurityManager是Shiro架構(gòu)的核心,它充當(dāng)一種“傘形”對(duì)象,協(xié)調(diào)其內(nèi)部安全組件,這些組件一起構(gòu)成一個(gè)對(duì)象圖,一旦為應(yīng)用程序配置了SecurityManager及其內(nèi)部對(duì)象圖,通常就不需要再管它了,應(yīng)用程序開發(fā)人員幾乎將所有時(shí)間都花在Subject API上
Realms(領(lǐng)域): realm充當(dāng)Shiro和應(yīng)用程序的安全數(shù)據(jù)之間的“橋梁”或“連接器”。 當(dāng)需要與與安全相關(guān)的數(shù)據(jù)(如用戶帳戶)進(jìn)行實(shí)際交互以執(zhí)行身份驗(yàn)證(登錄)和授權(quán)(訪問控制)時(shí),Shiro會(huì)從一個(gè)或多個(gè)為應(yīng)用程序配置的Realms中查找這些內(nèi)容.類似于SpringMVC的DAO層
2.導(dǎo)入架包
在pom.xml中導(dǎo)入架包,使用SpringBoot來使用Shiro,采用的版本是<shiro.version>1.4.0</shiro.version>
<!--使用shiro安全框架--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-core</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version>${shiro.version}</version></dependency><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-ehcache</artifactId><version>${shiro.version}</version></dependency> </dependencies>?
3.編寫Shiro配置文件
package com.example.demo.config; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.spring.LifecycleBeanPostProcessor; import org.apache.shiro.spring.web.ShiroFilterFactoryBean; import org.apache.shiro.web.filter.authc.LogoutFilter; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.LinkedHashMap; import java.util.Map;@Configuration public class ShiroConfiguration {/**管理Shiro的生命周期*/ @Bean(name = "lifecycleBeanPostProcessor") public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor(){ return new LifecycleBeanPostProcessor();}/**處理攔截請(qǐng)求,需要注入securityManager*/ @Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){ System.out.println("處理攔截請(qǐng)求"); ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean(); /*用工廠*/ shiroFilterFactoryBean.setSecurityManager(securityManager); /*默認(rèn)跳轉(zhuǎn)界面*/ shiroFilterFactoryBean.setLoginUrl("/login.html"); /*登錄成功后跳轉(zhuǎn)界面*/ shiroFilterFactoryBean.setSuccessUrl("/index.html"); /*跳轉(zhuǎn)到未授權(quán)界面*/ shiroFilterFactoryBean.setUnauthorizedUrl("/test.html"); /*自定義攔截器,攔截動(dòng)作次序與編寫時(shí)順序有關(guān),確保最后進(jìn)行'/**'的驗(yàn)證操作,否則他之后的會(huì)攔截失效*/ Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); //設(shè)置不需要訪問權(quán)限的界面,Resource和Controller訪問目錄為'/' filterChainDefinitionMap.put("/login", "anon"); filterChainDefinitionMap.put("/demo/test", "anon"); filterChainDefinitionMap.put("/js/**", "anon"); filterChainDefinitionMap.put("/css/**", "anon"); //對(duì)所有的用戶進(jìn)行認(rèn)證,'authc'代表需要登錄,當(dāng)所有的認(rèn)證都通過的時(shí)候才可以訪問路徑, filterChainDefinitionMap.put("/**", "authc"); //退出攔截器,并對(duì)退出動(dòng)作進(jìn)行重定向 filterChainDefinitionMap.put("/logout", "logout"); LogoutFilter logoutFilter = new LogoutFilter(); logoutFilter.setRedirectUrl("/login.html"); //將自定義攔截器放入'shiroFilter'攔截器中 shiroFilterFactoryBean.getFilters().put("logout", logoutFilter); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; }@Bean(name = "securityManager") public SecurityManager securityManager(EhCacheManager cacheManager) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //設(shè)置自己編寫的Realm,進(jìn)行認(rèn)證和授權(quán)操作 securityManager.setRealm(myShiroRealm()); securityManager.setCacheManager(cacheManager); return securityManager; }/**設(shè)置自己編寫的Realm,進(jìn)行認(rèn)證和授權(quán)操作,'MyShiroRealm'要另外編寫,* 進(jìn)行認(rèn)證和授權(quán)時(shí)會(huì)自動(dòng)調(diào)用realm中的方法*/ @Bean public MyShiroRealm myShiroRealm() { MyShiroRealm myShiroRealm = new MyShiroRealm(); myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher()); return myShiroRealm; }/** * 憑證匹配器 (由于我們的密碼校驗(yàn)交給Shiro的SimpleAuthenticationInfo進(jìn)行處理了 * 進(jìn)行的加密操作 */ @Bean public HashedCredentialsMatcher hashedCredentialsMatcher() { HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); hashedCredentialsMatcher.setHashAlgorithmName("md5");// 散列算法:這里使用MD5算法; hashedCredentialsMatcher.setHashIterations(2);// 散列的次數(shù),比如散列兩次,相當(dāng)于 // md5(md5("")); return hashedCredentialsMatcher; }/**配置緩存*/ @Bean public EhCacheManager getCacheManager(){ EhCacheManager ehCacheManager = new EhCacheManager(); ehCacheManager.setCacheManagerConfigFile("classpath:ehcache.xml"); return ehCacheManager; } }?
4.緩存配置
<?xml version="1.0" encoding="UTF-8"?> <ehcache updateCheck="false" name="shiroCache"><defaultCachemaxElementsInMemory="10000"eternal="false"timeToIdleSeconds="120"timeToLiveSeconds="120"overflowToDisk="false"diskPersistent="false"diskExpiryThreadIntervalSeconds="120"/> </ehcache>5.自定義Realm
在Shiro中,進(jìn)行的授權(quán)和認(rèn)證就是由它來操作的,認(rèn)證操作時(shí)在登錄時(shí)通過Subject的login方法,將用戶名密碼傳入這里面,與數(shù)據(jù)里面進(jìn)行交互,判斷是否存在此用戶或者密碼是否正確,存在則認(rèn)證成功,主要有兩個(gè)方法
?
編寫一個(gè)工具類,來獲取當(dāng)前的user或者session
package com.example.demo.utils; import com.example.demo.pojo.User; import org.apache.shiro.SecurityUtils; import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; public class UserUtils {private static String login_user="login_user";public static void setUserSession(User user) {getSession().setAttribute(login_user, user);}public static Session getSession() {Subject currentUser = SecurityUtils.getSubject();Session session = currentUser.getSession();return session;}public static User getCurrentUser() {User user = (User) getSession().getAttribute(login_user);return user;} }
6.加密算法和獲取Session的方法
加密算法在Shiro配置文件中使用的是MD5,加密兩次,相應(yīng)的login認(rèn)證操作調(diào)用EncoderPassword()?方法時(shí),兩者也應(yīng)該一樣
在Service中編寫登錄認(rèn)證的加密算法,這樣登錄認(rèn)證時(shí)的加密后的密碼和數(shù)據(jù)庫(kù)中對(duì)應(yīng)的一致
@Override public String EncoderPassword(String password, String salt) {//采取MD5算法進(jìn)行加密,加密2次Object object = new SimpleHash("MD5", password, salt, 2);return object.toString(); }7.登錄操作
獲取到前端的用戶名和密碼,封裝在一個(gè)token里面,然后獲取當(dāng)前的subject,調(diào)用它的login方法,參數(shù)傳入,然后它會(huì)調(diào)用到自定義realm中的認(rèn)證操作,認(rèn)證成功后返回?cái)?shù)據(jù)
@RestController @RequestMapping(value = "/demo") public class DemoController {@RequestMapping("/test")public User index(User user) {//用于存取用戶名和密碼UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(user.getName(), user.getPassword());//設(shè)置一個(gè)subjectSubject subject =SecurityUtils.getSubject();/*對(duì)這個(gè)subject對(duì)應(yīng)的用戶名和密碼進(jìn)行認(rèn)證操作,若自己自定義了realm,會(huì)用自定義的realm記性*/subject.login(usernamePasswordToken);User user2=UserUtils.getCurrentUser();System.out.println(UserUtils.getCurrentUser().toString());return user2;} }?
8.授權(quán)操作
在realm中doGetAuthorizationInfo()中編寫,為認(rèn)證后的用戶添加角色控制,在controller中或其他地方設(shè)置訪問權(quán)限,只有擁有權(quán)限的用戶方可進(jìn)行相關(guān)操作,如下所示:
數(shù)據(jù)庫(kù)中角色定位2,那么只有
@RequestMapping("/role") //@RequiresAuthentication:只要授權(quán)就能就能進(jìn)行訪問 @RequiresRoles(value = {"2","user"},logical = Logical.OR) //只要其中一個(gè)角色進(jìn)行了進(jìn)行了認(rèn)證就行 public String Role(){Sysem.out.println("測(cè)試角色");return "regist.html"; }9.測(cè)試結(jié)果
登錄界面,默認(rèn)跳轉(zhuǎn)界面
?
?
認(rèn)證成功
?
點(diǎn)擊測(cè)試角色,動(dòng)作為"/role"
?
與50位技術(shù)專家面對(duì)面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的Shiro安全框架的使用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CAS乐观锁原理
- 下一篇: 求二叉树最长路径长度和