後臺管理系統-Shiro權限控制

Shiro安全框架簡介

Shiro概述

Shiro是apache旗下一個開源安全框架(http://shiro.apache.org/),它將軟件系統的安全認證相關的功能抽取出來,實現用戶身份認證,權限受權、加密、會話管理等功能,組成了一個通用的安全認證框架。使用shiro就能夠很是快速的完成認證、受權等功能的開發,下降系統成本。html

用戶在進行資源訪問時,要求系統要對用戶進行權限控制,其具體流程如圖所示:web

Shiro概要架構

在概念層面,Shiro 架構包含三個主要的理念,如圖所示:redis

其中:算法

  1. Subject :主體對象,負責提交用戶認證和受權信息。
  2. SecurityManager:安全管理器,負責認證,受權等業務實現。
  3. Realm:領域對象,負責從數據層獲取業務數據。

Shiro詳細架構

Shiro框架進行權限管理時,要涉及到的一些核心對象,主要包括:認證管理對象,受權管理對象,會話管理對象,緩存管理對象,加密管理對象以及Realm管理對象(領域對象:負責處理認證和受權領域的數據訪問題)等,其具體架構如圖-3所示:spring

其中:chrome

  1. Subject(主體):與軟件交互的一個特定的實體(用戶、第三方服務等)。
  2. SecurityManager(安全管理器) :Shiro 的核心,用來協調管理組件工做。
  3. Authenticator(認證管理器):負責執行認證操做。
  4. Authorizer(受權管理器):負責受權檢測。
  5. SessionManager(會話管理):負責建立並管理用戶 Session 生命週期,提供一個強有力的 Session 體驗。
  6. SessionDAO:表明 SessionManager 執行 Session 持久(CRUD)動做,它容許任何存儲的數據掛接到 session 管理基礎上。
  7. CacheManager(緩存管理器):提供建立緩存實例和管理緩存生命週期的功能。
  8. Cryptography(加密管理器):提供了加密方式的設計及管理。
  9. Realms(領域對象):是shiro和你的應用程序安全數據之間的橋樑。

Shiro框架認證攔截實現(filter)

Shiro基本環境配置

添加shiro依賴

使用spring整合shiro時,須要在pom.xml中添加以下依賴:數據庫

<dependency>
     <groupId>org.apache.shiro</groupId>
     <artifactId>shiro-spring</artifactId>
     <version>1.5.3</version>
</dependency>

Shiro核心對象配置

基於SpringBoot 實現的項目中,咱們的shiro應用基本配置以下:。apache

第一步:建立SpringShiroConfig類。關鍵代碼以下:segmentfault

package com.cy.pj.common.config;
    /**@Configuration 註解描述的類爲一個配置對象,
     * 此對象也會交給spring管理
     */
    @Configuration
    public class SpringShiroConfig {
}

第二步:在Shiro配置類中添加SecurityManager配置(這裏必定要使用org.apache.shiro.mgt.SecurityManager這個接口對象),關鍵代碼以下:瀏覽器

@Bean
public SecurityManager securityManager() {
    DefaultWebSecurityManager sManager=
    new DefaultWebSecurityManager();
    return sManager;

}

第三步: 在Shiro配置類中添加ShiroFilterFactoryBean對象的配置。經過此對象設置資源匿名訪問、認證訪問。關鍵代碼以下:

其配置過程當中,對象關係以下圖所示:

Shiro登錄頁面呈現

服務端Controller實現

  • 業務描述及設計實現

當服務端攔截到用戶請求之後,斷定此請求是否已經被認證,假如沒有認證應該先跳轉到登陸頁面。

  • 關鍵代碼分析及實現.

第一步:在PageController中添加一個呈現登陸頁面的方法,關鍵代碼以下:

@RequestMapping("doLoginUI")
public String doLoginUI(){
        return "login";
}

第二步:修改SpringShiroConfig類中shiroFilterFactorybean的配置,添加登錄url的設置。關鍵代碼見sfBean.setLoginUrl("/doLoginUI")部分。

@Bean
public ShiroFilterFactoryBean shiroFilterFactory (
             SecurityManager securityManager) {
         ShiroFilterFactoryBean sfBean=
         new ShiroFilterFactoryBean();
         sfBean.setSecurityManager(securityManager);
        sfBean.setLoginUrl("/doLoginUI");
        //定義map指定請求過濾規則(哪些資源容許匿名訪問,哪些必須認證訪問)
         LinkedHashMap<String,String> map=
                 new LinkedHashMap<>();
         //靜態資源容許匿名訪問:"anon"
         map.put("/bower_components/**","anon");
         map.put("/modules/**","anon");
         map.put("/dist/**","anon");
         map.put("/plugins/**","anon");
         //除了匿名訪問的資源,其它都要認證("authc")後訪問
         map.put("/**","authc");
         sfBean.setFilterChainDefinitionMap(map);
         return sfBean;
}

客戶端頁面實現

  • 業務描述及設計實現。

在/templates/pages/添加一個login.html頁面,而後將項目部署到web服務器,並啓動測試運行.

  • 關鍵代碼分析及實現。

具體代碼見項目中login.html。

Shiro框架認證業務實現

認證流程分析

身份認證即斷定用戶是不是系統的合法用戶,用戶訪問系統資源時的認證(對用戶身份信息的認證)流程圖所示:

其中認證流程分析以下:

  1. 系統調用subject的login方法將用戶信息提交給SecurityManager
  2. SecurityManager將認證操做委託給認證器對象Authenticator
  3. Authenticator將用戶輸入的身份信息傳遞給Realm。
  4. Realm訪問數據庫獲取用戶信息而後對信息進行封裝並返回。
  5. Authenticator 對realm返回的信息進行身份認證。

思考:不使用shiro框架如何完成認證操做?filter,intercetor。

認證服務端實現

核心業務分析

認證業務API處理流程分析,如圖所示:

DAO接口定義

  • 業務描述及設計實現。

在用戶數據層對象SysUserDao中,按特定條件查詢用戶信息,並對其進行封裝。

  • 關鍵代碼分析及實現。

在SysUserDao接口中,添加根據用戶名獲取用戶對象的方法,關鍵代碼以下:

SysUser findUserByUserName(String username)。

Mapper元素定義

  • 業務描述及設計實現。

根據SysUserDao中定義的方法,在SysUserMapper文件中添加元素定義。

  • 關鍵代碼分析及實現。

基於用戶名獲取用戶對象的方法,關鍵代碼以下:

<select id="findUserByUserName"
           resultType="com.cy.pj.sys.entity.SysUser">
      select *
      from sys_users  
      where username=#{username}
   </select>

Service接口及實現

  • 業務描述及設計實現。

本模塊的業務在Realm類型的對象中進行實現,咱們編寫realm時,要繼承

AuthorizingRealm並重寫相關方法,完成認證及受權業務數據的獲取及封裝。

  • 關鍵代碼分析及實現。

第一步:定義ShiroUserRealm類,關鍵代碼以下:

package com.cy.pj.sys.service.realm;
@Service
public class ShiroUserRealm extends AuthorizingRealm {

    @Autowired
    private SysUserDao sysUserDao;
        
    /**
     * 設置憑證匹配器(與用戶添加操做使用相同的加密算法)
     */
    @Override
    public void setCredentialsMatcher(
          CredentialsMatcher credentialsMatcher) {
        //構建憑證匹配對象 
        HashedCredentialsMatcher cMatcher=
        new HashedCredentialsMatcher();
        //設置加密算法
        cMatcher.setHashAlgorithmName("MD5");
        //設置加密次數
        cMatcher.setHashIterations(1);
        super.setCredentialsMatcher(cMatcher);
    }
    /**
     * 經過此方法完成認證數據的獲取及封裝,系統
     * 底層會將認證數據傳遞認證管理器,由認證
     * 管理器完成認證操做。
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) 
            throws AuthenticationException {
        //1.獲取用戶名(用戶頁面輸入)
        UsernamePasswordToken upToken=
        (UsernamePasswordToken)token;
        String username=upToken.getUsername();
        //2.基於用戶名查詢用戶信息
        SysUser user=
        sysUserDao.findUserByUserName(username);
        //3.斷定用戶是否存在
        if(user==null)
        throw new UnknownAccountException();
        //4.斷定用戶是否已被禁用。
        if(user.getValid()==0)
        throw new LockedAccountException();
        
        //5.封裝用戶信息
        ByteSource credentialsSalt=
        ByteSource.Util.bytes(user.getSalt());
        //記住:構建什麼對象要看方法的返回值
        SimpleAuthenticationInfo info=
        new SimpleAuthenticationInfo(
                user,//principal (身份)
                user.getPassword(),//hashedCredentials
                credentialsSalt, //credentialsSalt
                getName());//realName
        //6.返回封裝結果
        return info;//返回值會傳遞給認證管理器(後續
        //認證管理器會經過此信息完成認證操做)
    }
    ....
}

第二步:對此realm,須要在SpringShiroConfig配置類中,注入給SecurityManager對象,修改securityManager方法,見黃色背景部分,例如:

@Bean
public SecurityManager securityManager(Realm realm) {
         DefaultWebSecurityManager sManager=
         new DefaultWebSecurityManager();
         sManager.setRealm(realm);
         return sManager;
}

Controller 類實現

  • 業務描述及設計實現。

在此對象中定義相關方法,處理客戶端的登錄請求,例如獲取用戶名,密碼等而後提交該shiro框架進行認證。

  • 關鍵代碼分析及實現。

第一步:在SysUserController中添加處理登錄的方法。關鍵代碼以下:

@RequestMapping("doLogin")
       public JsonResult doLogin(String username,String password){
           //1.獲取Subject對象
           Subject subject=SecurityUtils.getSubject();
           //2.經過Subject提交用戶信息,交給shiro框架進行認證操做
           //2.1對用戶進行封裝
           UsernamePasswordToken token=
           new UsernamePasswordToken(
                   username,//身份信息
                   password);//憑證信息
           //2.2對用戶信息進行身份認證
           subject.login(token);
           //分析:
           //1)token會傳給shiro的SecurityManager
           //2)SecurityManager將token傳遞給認證管理器
           //3)認證管理器會將token傳遞給realm
           return new JsonResult("login ok");
       }

第二步:修改shiroFilterFactory的配置,對/user/doLogin這個路徑進行匿名訪問的配置,查看以下黃色標記部分的代碼:

@Bean
public ShiroFilterFactoryBean shiroFilterFactory (
             SecurityManager securityManager) {
         ShiroFilterFactoryBean sfBean=
         new ShiroFilterFactoryBean();
         sfBean.setSecurityManager(securityManager);
         //假如沒有認證請求先訪問此認證的url
         sfBean.setLoginUrl("/doLoginUI");
         //定義map指定請求過濾規則(哪些資源容許匿名訪問,哪些必須認證訪問)
         LinkedHashMap<String,String> map=
                 new LinkedHashMap<>();
         //靜態資源容許匿名訪問:"anon"
         map.put("/bower_components/**","anon");
         map.put("/build/**","anon");
         map.put("/dist/**","anon");
         map.put("/plugins/**","anon");

         map.put("/user/doLogin","anon");                       //authc表示,除了匿名訪問的資源,其它都要認證("authc")後才能訪問訪問
         map.put("/**","authc");
         sfBean.setFilterChainDefinitionMap(map);
         return sfBean;
     }

第三步:當咱們在執行登陸操做時,爲了提升用戶體驗,可對系統中的異常信息進行處理,例如,在統一異常處理類中添加以下方法:

@ExceptionHandler(ShiroException.class) 
   @ResponseBody
    public JsonResult doHandleShiroException(
            ShiroException e) {
        JsonResult r=new JsonResult();
        r.setState(0);
        if(e instanceof UnknownAccountException) {
            r.setMessage("帳戶不存在");
        }else if(e instanceof LockedAccountException) {
            r.setMessage("帳戶已被禁用");
        }else if(e instanceof IncorrectCredentialsException) {
            r.setMessage("密碼不正確");
        }else if(e instanceof AuthorizationException) {
            r.setMessage("沒有此操做權限");
        }else {
            r.setMessage("系統維護中");
        }
        e.printStackTrace();
        return r;
    }

認證客戶端實現

編寫用戶登錄頁面

在/templates/pages/目錄下添加登錄頁面(login.html)。

異步登錄操做實現

點擊登陸操做時,將輸入的用戶名,密碼異步提交到服務端。

$(function () {
    $(".login-box-body").on("click",".btn",doLogin);
  });
  function doLogin(){
      var params={
         username:$("#usernameId").val(),
         password:$("#passwordId").val()
      }
      var url="user/doLogin";
      $.post(url,params,function(result){
          if(result.state==1){
            //跳轉到indexUI對應的頁面
            location.href="doIndexUI?t="+Math.random();
          }else{
            $(".login-box-msg").html(result.message); 
          }
      });
  }

退出操做配置實現

在SpringShiroConfig配置類中,修改過濾規則,添加黃色標記部分代碼的配置,請看以下代碼:

@Bean
public ShiroFilterFactoryBean shiroFilterFactory(
            SecurityManager securityManager) {
         ShiroFilterFactoryBean sfBean=
         new ShiroFilterFactoryBean();
         sfBean.setSecurityManager(securityManager);
         //假如沒有認證請求先訪問此認證的url
         sfBean.setLoginUrl("/doLoginUI");
         //定義map指定請求過濾規則(哪些資源容許匿名訪問,哪些必須認證訪問)
         LinkedHashMap<String,String> map=new LinkedHashMap<>();
         //靜態資源容許匿名訪問:"anon"
         map.put("/bower_components/**","anon");
         map.put("/build/**","anon");
         map.put("/dist/**","anon");
         map.put("/plugins/**","anon");
  map.put("/user/doLogin","anon");
  map.put("/doLogout","logout"); 
                                                              //除了匿名訪問的資源,其它都要認證("authc")後訪問
         map.put("/**","authc");
         sfBean.setFilterChainDefinitionMap(map);
         return sfBean;
     }

Shiro框架受權過程實現

受權流程分析

受權即對用戶資源訪問的受權(是否容許用戶訪問此資源),用戶訪問系統資源時的受權流程如圖所示:

其中受權流程分析以下:

  1. 系統調用subject相關方法將用戶信息(例如isPermitted)遞交給SecurityManager。
  2. SecurityManager將權限檢測操做委託給Authorizer對象。
  3. Authorizer將用戶信息委託給realm。
  4. Realm訪問數據庫獲取用戶權限信息並封裝。
  5. Authorizer對用戶受權信息進行斷定。

    思考:思考不使用shiro如何完成受權操做?intercetor,aop。

添加受權配置

在SpringShiroConfig配置類中,添加受權時的相關配置:

第一步:配置bean對象的生命週期管理(SpringBoot能夠不配置)。

@Bean
public LifecycleBeanPostProcessor   lifecycleBeanPostProcessor() {
         return new LifecycleBeanPostProcessor();
}

第二步: 經過以下配置要爲目標業務對象建立代理對象(SpringBoot中可省略)。

@DependsOn("lifecycleBeanPostProcessor")
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
         return new DefaultAdvisorAutoProxyCreator();
}

第三步:配置advisor對象,shiro框架底層會經過此對象的matchs方法返回值(相似切入點)決定是否建立代理對象,進行權限控制。

@Bean
public AuthorizationAttributeSourceAdvisor 
authorizationAttributeSourceAdvisor (
                    SecurityManager securityManager) {
                AuthorizationAttributeSourceAdvisor advisor=
                new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
    return advisor;
}
說明:使用框架最重要的尊重規則,框架規則指定了什麼方式就使用什麼方式。

說明:使用框架最重要的尊重規則,框架規則指定了什麼方式就使用什麼方式。

受權服務端實現

核心業務分析

受權時,服務端核心業務以及API分析,如圖所示:

Dao實現

  • 業務描述及設計實現。

基於登錄用戶ID,認證信息獲取登錄用戶的權限信息,並進行封裝。

  • 關鍵代碼分析及實現。

第一步:在SysUserRoleDao中定義基於用戶id查找角色id的方法(假如方法已經存在則無需再寫),關鍵代碼以下:

List<Integer> findRoleIdsByUserId(Integer id);

第二步:在SysRoleMenuDao中定義基於角色id查找菜單id的方法,關鍵代碼以下:

List<Integer> findMenuIdsByRoleIds(
            @Param("roleIds")List<Integer> roleIds);

第三步:在SysMenuDao中基於菜單id查找權限標識的方法,關鍵代碼以下:

List<String> findPermissions(
            @Param("menuIds")
            List<Integer> menuIds);

Mapper實現

  • 業務描述及設計實現。

基於Dao中方法,定義映射元素。

  • 關鍵代碼分析及實現。

第一步:在SysUserRoleMapper中定義findRoleIdsByUserId元素。關鍵代碼以下:

<select id="findRoleIdsByUserId"
            resultType="int">
           select role_id
           from sys_user_roles
           where user_id=#{userId}        
</select>

第二步:在SysRoleMenuMapper中定義findMenuIdsByRoleIds元素。關鍵代碼以下:

<select id="findMenuIdsByRoleIds"
         resultType="int">
         select menu_id
         from sys_role_menus
         where role_id in 
         <foreach collection="roleIds"
                  open="("
                  close=")"
                  separator=","
                  item="item">
               #{item}
         </foreach>
</select>

第三步:在SysMenuMapper中定義findPermissions元素,關鍵代碼以下:

<select id="findPermissions"
           resultType="string">
       select permission <!-- sys:user:update -->
       from sys_menus
       where id in 
       <foreach collection="menuIds"
                open="("
                close=")"
                separator=","
                item="item">
            #{item}
       </foreach>
   </select>

Service實現

  • 業務描述及設計實現。

在ShiroUserReam類中,重寫對象realm的doGetAuthorizationInfo方法,並完成用戶權限信息的獲取以及封裝,最後將信息傳遞給受權管理器完成受權操做。

  • 關鍵代碼分析及實現。

修改ShiroUserRealm類中的doGetAuthorizationInfo方法,關鍵代碼以下:

@Service
public class ShiroUserRealm extends AuthorizingRealm {
    @Autowired
    private SysUserDao sysUserDao;
    @Autowired
    private SysUserRoleDao sysUserRoleDao;
    @Autowired
    private SysRoleMenuDao sysRoleMenuDao;
    @Autowired
    private SysMenuDao sysMenuDao;
    /**經過此方法完成受權信息的獲取及封裝*/
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(
        PrincipalCollection principals) {
        //1.獲取登陸用戶信息,例如用戶id
        SysUser user=(SysUser)principals.getPrimaryPrincipal();
        Integer userId=user.getId();
        //2.基於用戶id獲取用戶擁有的角色(sys_user_roles)
        List<Integer> roleIds=
        sysUserRoleDao.findRoleIdsByUserId(userId);
        if(roleIds==null||roleIds.size()==0)
        throw new AuthorizationException();
        //3.基於角色id獲取菜單id(sys_role_menus)
        List<Integer> menuIds=
        sysRoleMenuDao.findMenuIdsByRoleIds(roleIds);
        if(menuIds==null||menuIds.size()==0)
        throw new AuthorizationException();
        //4.基於菜單id獲取權限標識(sys_menus)
        List<String> permissions=
        sysMenuDao.findPermissions(menuIds);
        //5.對權限標識信息進行封裝並返回
        Set<String> set=new HashSet<>();
        for(String per:permissions){
            if(!StringUtils.isEmpty(per)){
                set.add(per);
            }
        }
        SimpleAuthorizationInfo info=
        new SimpleAuthorizationInfo();
        info.setStringPermissions(set);
        return info;//返回給受權管理器
    }
   。。。。

}

受權訪問實描述現

在須要進行受權訪問的業務層(Service)方法上,添加執行此方法須要的權限標識,參考代碼

@RequiresPermissions(「sys:user:update」)

說明:此要註解必定要添加到業務層方法上。

Shiro擴展功能應用

Shiro緩存配置

當咱們進行受權操做時,每次都會從數據庫查詢用戶權限信息,爲了提升受權性能,能夠將用戶權限信息查詢出來之後進行緩存,下次受權時從緩存取數據便可。

Shiro中內置緩存應用實現,其步驟以下:

第一步:在SpringShiroConfig中配置緩存Bean對象(Shiro框架提供)。

@Bean
public CacheManager shiroCacheManager(){
     return new MemoryConstrainedCacheManager();
}

說明:這個CacheManager對象的名字不能寫cacheManager,由於spring容器中已經存在一個名字爲cacheManager的對象了.

第二步:修改securityManager的配置,將緩存對象注入給SecurityManager對象。

@Bean
public SecurityManager securityManager(
            Realm realm,
            CacheManager cacheManager) {
         DefaultWebSecurityManager sManager=
         new DefaultWebSecurityManager();
         sManager.setRealm(realm);
         sManager.setCacheManager(cacheManager);
         return sManager;
}

說明:對於shiro框架而言,還能夠藉助第三方的緩存產品(例如redis)對用戶的權限信息進行cache操做.

Shiro記住我

記住我功能是要在用戶登陸成功之後,假如關閉瀏覽器,下次再訪問系統資源(例如首頁doIndexUI)時,無需再執行登陸操做。

客戶端業務實現

在頁面上選中記住我,而後執行提交操做,將用戶名,密碼,記住我對應的值提交到控制層,如圖所示:

其客戶端login.html中關鍵JS實現:

function doLogin(){
      var params={
         username:$("#usernameId").val(),
         password:$("#passwordId").val(),
         isRememberMe:$("#rememberId").prop("checked"),
      }
      var url="user/doLogin";
      console.log("params",params);
      $.post(url,params,function(result){
          if(result.state==1){
            //跳轉到indexUI對應的頁面
            location.href="doIndexUI?t="+Math.random();
          }else{
            $(".login-box-msg").html(result.message); 
          }
          return false;//防止刷新時重複提交
      });
  }

服務端業務實現

服務端業務實現的具體步驟以下:

第一步:在SysUserController中的doLogin方法中基因而否選中記住我,設置token的setRememberMe方法。

@RequestMapping("doLogin")
     @ResponseBody
     public JsonResult doLogin(
             boolean isRememberMe,
             String username,
             String password) {
         //1.封裝用戶信息
         UsernamePasswordToken token=
         new UsernamePasswordToken(username, password);
         if(isRememberMe) {
            token.setRememberMe(true); 
         }
         //2.提交用戶信息
         Subject subject=SecurityUtils.getSubject();
         subject.login(token);//token會提交給securityManager
         return new JsonResult("login ok");
     }

第二步:在SpringShiroConfig配置類中添加記住我配置,關鍵代碼以下:

@Bean
     public RememberMeManager rememberMeManager() {
         CookieRememberMeManager cManager=
         new CookieRememberMeManager();
         SimpleCookie cookie=new SimpleCookie("rememberMe");
         cookie.setMaxAge(7*24*60*60);
         cManager.setCookie(cookie);
         return cManager;
     }

第三步:在SpringShiroConfig中修改securityManager的配置,爲securityManager注入rememberManager對象。參考黃色部分代碼。

@Bean
     public SecurityManager securityManager(
            Realm realm,CacheManager cacheManager
            RememberMeManager rememberManager) {
         DefaultWebSecurityManager sManager=
         new DefaultWebSecurityManager();
         sManager.setRealm(realm);
         sManager.setCacheManager(cacheManager);
         sManager.setRememberMeManager(rememberManager);
         return sManager;
     }

第四步:修改shiro的過濾認證級別,將/=author修改成/=user,查看黃色背景部分。

@Bean
     public ShiroFilterFactoryBean shiroFilterFactory(
             SecurityManager securityManager) {
         ShiroFilterFactoryBean sfBean=
         new ShiroFilterFactoryBean();
         sfBean.setSecurityManager(securityManager);
         //假如沒有認證請求先訪問此認證的url
         sfBean.setLoginUrl("/doLoginUI");
         //定義map指定請求過濾規則(哪些資源容許匿名訪問,哪些必須認證訪問)
         LinkedHashMap<String,String> map=
                 new LinkedHashMap<>();
         //靜態資源容許匿名訪問:"anon"
         map.put("/bower_components/**","anon");
         map.put("/build/**","anon");
         map.put("/dist/**","anon");
         map.put("/plugins/**","anon");
         map.put("/user/doLogin","anon");
         map.put("/doLogout", "logout");//自動查LoginUrl
         //除了匿名訪問的資源,其它都要認證("authc")後訪問
         map.put("/**","user");//authc
         sfBean.setFilterChainDefinitionMap(map);
         return sfBean;
     }

說明:查看瀏覽器cookie設置,可在瀏覽器中輸入以下語句。

chrome://settings/content/cookies

Shiro會話管理配置

使用shiro框架實現認證操做,用戶登陸成功會將用戶信息寫入到會話對象中,其默認時長爲30分鐘,假如須要對此進行配置,可參考以下配置:

第一步:在SpringShiroConfig類中,添加會話管理器配置。關鍵代碼以下:

@Bean   
public SessionManager sessionManager() {
         DefaultWebSessionManager sManager=
                 new DefaultWebSessionManager();
         sManager.setGlobalSessionTimeout(60*60*1000);
         return sManager;
}

第二步:在SpringShiroConfig配置類中,對安全管理器  securityManager 增長 sessionManager值的注入,關鍵代碼以下:

@Bean
public SecurityManager securityManager(
            Realm realm,CacheManager cacheManager,
RememberMeManager rememberManager,
SessionManager sessionManager) {
         DefaultWebSecurityManager sManager=
         new DefaultWebSecurityManager();
         sManager.setRealm(realm);
         sManager.setCacheManager(cacheManager);
         sManager.setRememberMeManager(rememberMeManager);
         sManager.setSessionManager(sessionManager);
         return sManager;
}

課堂練習:

1.獲取用戶登錄信息,並將登錄用戶名呈如今系統主頁(starter.html)上.

第一步:定義一個工具類(ShiroUtils),獲取用戶登錄信息.

package com.cy.pj.common.util;
import org.apache.shiro.SecurityUtils;
import com.cy.pj.sys.entity.SysUser;
public class ShiroUtils {
      public static String getUsername() {
          return getUser().getUsername();
      }
      public static SysUser getUser() {
          return  (SysUser)
           SecurityUtils.getSubject().getPrincipal();
      }
}

第二步:修改PageController中的doIndexUI方法,代碼以下:

@RequestMapping("doIndexUI")
    public String doIndexUI(Model model) {
        SysUser user=ShiroUtils.getUser();
        model.addAttribute("user",user);
        return "starter";
    }

第三步:藉助thymeleaf中的表達式直接在頁面上(starter.html)獲取登錄用戶信息

<span class="hidden-xs" id="loginUserId">[[${user.username}]]</span>

2.修改登錄用戶的密碼?(參考用戶模塊文檔)

分析:

1)肯定都要修改誰?(密碼,鹽值,修改時間)

2)服務端的設計實現?(dao,service,controller)

3)客戶端的設計實現?(異步提交用戶密碼信息)

Shiro總結

重點和難點分析

  1. shiro 認證過程分析及實現(斷定用戶身份的合法性)。
  2. Shiro 受權過程分析及實現(對資源訪問進行權限檢測和受權)。
  3. Shiro 緩存,會話時長,記住我等功能實現。

常見FAQ

  1. 說說shiro的核心組件?
  2. 說說shiro的認證流程,你如何知道的,爲何要認證?
  3. 說說shiro的受權流程,你如何知道流程是這樣的,爲何要進行受權?
  4. Shiro中內置緩存應用實現?爲何使用此緩存?是否可使用第三方緩存?
  5. Shiro中的記住我功能如何實現?爲何要使用這個功能?
  6. Shiro中會話session的默認時長是多少,你怎麼知道的?

Bug分析

  1. SecurityManager包名錯誤。
  2. MD5加密算法設置錯誤。
  3. Realm對象沒有交給spring管理
  4. 用戶名和密碼接收錯誤
  5. CacheManager名字與Spring中內置的CacheManager名字衝突。
  6. 過濾規則配置錯誤?
  7. ...
相關文章
相關標籤/搜索