shiro最詳細的解讀


shiro可以做什么:

認證、授權、會話管理、加密、緩存、與web集成

shiro認證流程:

創建SecurityManager安全管理器 > 主體Subject提交認證信息 > SecurityManager安全管理器認證 > SecurityManager調用Authenticator認證器認證 >Realm驗證

1.Subject(把操作交給SecurityManager)

Subject即主體,外部應用與subject進行交互,subject記錄了當前操作用戶,將用戶的概念理解為當前操作的主體,可能是一個通過瀏覽器請求的用戶,也可能是一個運行的程序。 Subject在shiro中是一個接口,接口中定義了很多認證授相關的方法,外部程序通過subject進行認證授,而subject是通過SecurityManager安全管理器進行認證授權

2.SecurityManager(關聯Realm)

SecurityManager即安全管理器,對全部的subject進行安全管理,它是shiro的核心,負責對所有的subject進行安全管理。通過SecurityManager可以完成subject的認證、授權等,實質上SecurityManager是通過Authenticator進行認證,通過Authorizer進行授權,通過SessionManager進行會話管理等。

SecurityManager是一個接口,繼承了Authenticator, Authorizer, SessionManager這三個接口。

3.Authenticator

Authenticator即認證器,對用戶身份進行認證,Authenticator是一個接口,shiro提供ModularRealmAuthenticator實現類,通過ModularRealmAuthenticator基本上可以滿足大多數需求,也可以自定義認證器。

4.Authorizer

Authorizer即授權器,用戶通過認證器認證通過,在訪問功能時需要通過授權器判斷用戶是否有此功能的操作權限。

5.realm

Realm即領域,相當於datasource數據源,securityManager進行安全認證需要通過Realm獲取用戶權限數據,比如:如果用戶身份數據在數據庫那么realm就需要從數據庫獲取用戶身份信息。

注意:不要把realm理解成只是從數據源取數據,在realm中還有認證授權校驗的相關的代碼。

6.sessionManager

sessionManager即會話管理,shiro框架定義了一套會話管理,它不依賴web容器的session,所以shiro可以使用在非web應用上,也可以將分布式應用的會話集中在一點管理,此特性可使它實現單點登錄。

7.SessionDAO

SessionDAO即會話dao,是對session會話操作的一套接口,比如要將session存儲到數據庫,可以通過jdbc將會話存儲到數據庫。

8.CacheManager

CacheManager即緩存管理,將用戶權限數據存儲在緩存,這樣可以提高性能。

9.Cryptography

Cryptography即密碼管理,shiro提供了一套加密/解密的組件,方便開發。比如提供常用的散列、加/解密等功能。

————————————————————————————————————————————————————————————————————————

1.引入maven依賴

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.4.0</version>
        </dependency>

 2.首先在ShiroConfig配置類中創建SecurityManager安全管理器

(最基本的ShiroConfig 可直接復制)

package com.yuyang.demo.shiro;

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

/**
* @program: spring-boot-demo
* @description: shiro配置類
* @author: 於洋
* @create: 2019-09-18 14:30
**/
@Configuration
public class ShiroConfig {
/**
* 創建shiroFilterFactoryBean
*/
@Bean(name = "ShiroFilterFactoryBean")
public ShiroFilterFactoryBean getshiroFilterFactoryBean(@Qualifier("DefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//設置安全管理器
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
/**
* shiro內置過濾器,可以實現權限相關攔截
* 常用過濾器:
* anon:無需認證(登陸)可以訪問
* authc:必須認證才可以訪問
* user:如果使用rememberMe的功能才可以直接訪問
* perms:該資源必須得到資源權限才可以訪問
* role:該資源必須得到角色權限才可以訪問
*/
Map<String,String> map=new LinkedHashMap<>();
map.put("/excel/add","authc");
map.put("/excel/update","authc");
shiroFilterFactoryBean.setLoginUrl("/excel/login");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}

/**
* 創建DefaultWebSecurityManager
*/
@Bean(name = "DefaultWebSecurityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("MyRealm") MyRealm realm) {
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
/**
* 關聯Realm
*/
defaultWebSecurityManager.setRealm(realm);
return defaultWebSecurityManager;
}

/**
* 創建Realm
*/
@Bean(name = "MyRealm")
public MyRealm getRealm() {
return new MyRealm();
}
}

 

我的ShiroConfig類

@Configuration
public class ShiroConfig {
    /**
     * Filter Chain定義說明 
    * 1、一個URL可以配置多個Filter,使用逗號分隔
     * 2、當設置多個過濾器時,全部驗證通過,才視為通過
     * 3、部分過濾器可指定參數,如perms,roles
     */
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
       ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager);
      // 攔截器 Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); // 配置不會被攔截的鏈接 順序判斷 controllerMapping路徑 filterChainDefinitionMap.put("/sys/login", "anon"); //登錄接口排除 filterChainDefinitionMap.put("/auth/2step-code", "anon");//登錄驗證碼 filterChainDefinitionMap.put("/sys/common/view/**", "anon");//圖片預覽不限制token filterChainDefinitionMap.put("/sys/common/download/**", "anon");//文件下載不限制token filterChainDefinitionMap.put("/sys/common/pdf/**", "anon");//pdf預覽 filterChainDefinitionMap.put("/generic/**", "anon");//pdf預覽需要文件 filterChainDefinitionMap.put("/", "anon"); filterChainDefinitionMap.put("/doc.html", "anon"); filterChainDefinitionMap.put("/**/*.js", "anon"); filterChainDefinitionMap.put("/**/*.css", "anon"); filterChainDefinitionMap.put("/**/*.html", "anon"); filterChainDefinitionMap.put("/**/*.svg", "anon"); filterChainDefinitionMap.put("/**/*.jpg", "anon"); filterChainDefinitionMap.put("/**/*.png", "anon"); filterChainDefinitionMap.put("/**/*.ico", "anon"); filterChainDefinitionMap.put("/druid/**", "anon"); filterChainDefinitionMap.put("/swagger-ui.html", "anon"); filterChainDefinitionMap.put("/swagger**/**", "anon"); filterChainDefinitionMap.put("/webjars/**", "anon"); filterChainDefinitionMap.put("/v2/**", "anon");// 添加自己的過濾器並且取名為jwt Map<String, Filter> filterMap = new HashMap<String, Filter>(1); filterMap.put("jwt", new JwtFilter()); shiroFilterFactoryBean.setFilters(filterMap); // <!-- 過濾鏈定義,從上向下順序執行,一般將/**放在最為下邊 filterChainDefinitionMap.put("/**", "jwt"); // 未授權界面返回JSON shiroFilterFactoryBean.setUnauthorizedUrl("/sys/common/403"); shiroFilterFactoryBean.setLoginUrl("/sys/common/403"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean("securityManager") public DefaultWebSecurityManager securityManager(ShiroRealm myRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myRealm); /* *SecurityManager安全管理器需要到realm中去驗證認證信息,所以給SecurityManager設置Realm*/ DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO(); DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator(); defaultSessionStorageEvaluator.setSessionStorageEnabled(false); subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator); securityManager.setSubjectDAO(subjectDAO); return securityManager; } /** * 下面的代碼是添加注解支持 * @return */ @Bean @DependsOn("lifecycleBeanPostProcessor") public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); return defaultAdvisorAutoProxyCreator; } @Bean public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } }

3.SecurityManager安全管理器需要到realm中去驗證認證信息,所以給SecurityManager設置Realm。自定義Realm 

ShiroRealm類 繼承 AuthorizingRealm  重寫 doGetAuthenticationInfo  doGetAuthorizationInfo方法

@Component
@Slf4j
public class ShiroRealm extends AuthorizingRealm {

    @Autowired
    @Lazy
    private ISysUserService sysUserService;
    @Autowired
    @Lazy
    private RedisUtil redisUtil;/**
     * 功能: 獲取用戶權限信息,包括角色以及權限。只有當觸發檢測用戶權限時才會調用此方法,例如checkRole,checkPermission
     * 
     * @param token token
     * @return AuthorizationInfo 權限信息
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
          //根據自己的需求去寫 log.info(
"————權限認證 [ roles、permissions]————"); LoginUser sysUser = null; String username = null; if (principals != null) { sysUser = (LoginUser) principals.getPrimaryPrincipal(); username = sysUser.getUsername(); } SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); // 設置用戶擁有的角色集合,比如“admin,test” Set<String> roleSet = sysUserService.getUserRolesSet(username); info.setRoles(roleSet); // 設置用戶擁有的權限集合,比如“sys:role:add,sys:user:add” Set<String> permissionSet = sysUserService.getUserPermissionsSet(username); info.addStringPermissions(permissionSet); return info; } /** * 功能: 用來進行身份認證,也就是說驗證用戶輸入的賬號和密碼是否正確,獲取身份驗證信息,錯誤拋出異常 * * @param authenticationToken 用戶身份信息 token * @return 返回封裝了用戶信息的 AuthenticationInfo 實例 */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth) throws AuthenticationException { log.debug("————身份認證————"); String token = (String) auth.getCredentials(); if (token == null) { throw new AuthenticationException("token為空!"); } // 校驗token有效性 LoginUser loginUser = this.checkUserTokenIsEffect(token); return new SimpleAuthenticationInfo(loginUser, token, getName()); } }

 3.SecurityManager安全管理器需要到realm中去驗證認證信息,所以給SecurityManager設置Realm

   代碼寫在ShiroConfig 類里標     色地方

4.Shiro配置類的過濾器中啟用安全管理器,即shiroFilterFactoryBean中配置SecurityManager

  代碼寫在ShiroConfig 類里標      色地方

5.主體提交認證信息,即登錄請求

@PostMapping("/login")
    public String login(String username, String password, Model model){
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
 Subject currentUser = SecurityUtils.getSubject(); //重點
    try { //主體提交登錄請求到SecurityManager currentUser.login(token); }catch (IncorrectCredentialsException ice){ model.addAttribute("msg","密碼不正確"); }catch(UnknownAccountException uae){ model.addAttribute("msg","賬號不存在"); }catch(AuthenticationException ae){ model.addAttribute("msg","狀態不正常"); } if(currentUser.isAuthenticated()){ System.out.println("認證成功"); model.addAttribute("currentUser",currentUser()); return "success"; }else{ token.clear(); return "login"; } }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM