1. 程式人生 > >shiro框架---shiro配置介紹(二)

shiro框架---shiro配置介紹(二)

  關於shiro在springboot的配置,共有四個基本配置檔案主要的檔案有四個ShiroConfigRetryLimitHashedCredentialsMatcherUserRealmMShiroFilterFactoryBean
  因為上一篇僅僅寫完了shiroconfig 類的配置,雖然在上一篇最下邊,我已經附上了所有檔案的下載連結,但是我覺得還是要寫一下剩下的三個配置檔案,寫一下我對shiro配置的理解。下邊是剩餘三個配置檔案,即RetryLimitHashedCredentialsMatcherUserRealmMShiroFilterFactoryBean
的配置詳情。
1.UserRealm 類的配置內容

具體程式碼如下:

package microservice.fpzj.shiro;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import
org.apache.shiro.authc.SimpleAuthenticationInfo; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; 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.apache.shiro.util.ByteSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import microservice.fpzj.core.models.Permission; import microservice.fpzj.core.models.Role; import microservice.fpzj.core.models.User; import microservice.fpzj.service.jwt.UserService; /** * 驗證使用者登入 * * @author Administrator */ @Component("userRealm") public class UserRealm extends AuthorizingRealm { @Autowired private UserService userService; public UserRealm() { setName("UserRealm"); // 採用MD5加密 setCredentialsMatcher(new HashedCredentialsMatcher("md5")); } /** *許可權資源角色配置,如果在jsp里加入了shiro的標籤配置,將會在訪問那個jsp頁 * 面的時候觸發這個方法,這裡先不考慮這個方法的邏輯。 **/ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { User user = (User)principals.getPrimaryPrincipal(); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); return info; } //登入驗證 @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken upt = (UsernamePasswordToken) token; char[] passwords = upt.getPassword(); String pwd = new String(passwords); if(!StringUtils.isEmpty(pwd)){ //如果密碼不是空,表示是本地登入 User user = this.userService.findUserByUserName(upt.getUsername()); if(user == null){ throw new AuthenticationException("no_user"); } boolean res =true; for(Role r:user.getRoles()){ if(r.getSiteid()==2){ res = false; break; } } if(res){ throw new AuthenticationException("no_permission"); } if(user!=null && !user.isDeleted()){ SimpleAuthenticationInfo info = new SimpleAuthenticationInfo( user, //使用者物件 user.getPasswd(), //密碼 ByteSource.Util.bytes(user.getUserid()+user.getUsername()),//salt=username+salt getName()); //realm name return info; } return null;//getAuthenticationInfoMethod(upt.getUsername()); }else{ /** *如果密碼是空,表示是遠端登入,從username位置獲得token, *暫時不考慮這種情況,這裡只走上邊if裡邊 **/ String username = userService.getUsernameFromToken(upt.getUsername()); return getAuthenticationInfoMethod(username); } } public AuthenticationInfo getAuthenticationInfoMethod(String username){ User user = userService.findUserByUserName(username); if(user == null){ throw new AuthenticationException("no_user"); } if(user != null){ boolean res =true; for(Role r:user.getRoles()){ if(r.getSiteid()==2){ res = false; break; } } if(res){ throw new AuthenticationException("no_permission"); } SimpleAuthenticationInfo info = new SimpleAuthenticationInfo( user, //使用者物件 user.getPasswd(), //密碼 ByteSource.Util.bytes(user.getUserid()+user.getUsername()),//salt=username+salt getName()); //realm name return info; } return null; } }

  以上主要看登入驗證方法doGetAuthenticationInfo 在該方法裡,通過從自己寫的userService 介面,先根據使用者名稱查詢出使用者物件,即呼叫findUserByUserName 方法,獲取使用者物件下的角色roles,通過判斷使用者下的角色集合中,是否含有siteId 為2的,如果含有siteId 為2的,則讓通過登入,如果沒有當前siteId 的角色,則登入失敗,站點siteId 表示系統類別,2在我們多系統裡為業務系統,還有門戶系統、後臺系統等。
  siteId我在第一篇裡已經寫了,shiro框架—關於shiro框架的簡單介紹及使用者表的建立維護

2.RetryLimitHashedCredentialsMatcher 類的配置內容

  具體程式碼如下:

package microservice.fpzj.shiro;


import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import microservice.fpzj.core.models.User;
import microservice.fpzj.service.jwt.UserService;

/**
 * 
 * @author ZML
 *
 */
public class RetryLimitHashedCredentialsMatcher extends HashedCredentialsMatcher {
    @Autowired
    private UserService userService;

    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        if(token instanceof UsernamePasswordToken){
            UsernamePasswordToken userToken = (UsernamePasswordToken) token;
            User user = userService.findUserByUserName(userToken.getUsername());
            char[] passwordchars =userToken.getPassword();
            String password = new String(passwordchars);
            if("".equals(password)){ //token字串登入
                boolean flg = userService.verifyToken(userToken.getUsername());
                return flg;
            }else{ //賬號密碼登入
                boolean res = userService.passwordVerify(password,user.getPasswd(),user.getUserid()+user.getUsername());
                return res;
            }
        }
        return false;
    }
}

  上一篇已經說過,RetryLimitHashedCredentialsMatcher類,繼承於HashedCredentialsMatcher 類,對於HashedCredentialsMatcher 類,你如果往上找,就會發現,其實就是實現了CredentialsMatcher 介面,最後又在shiroConfig 配置檔案中,將該類注入到我們的spring容器中供UserRealm 呼叫,加入到shiro 框架裡,這樣就可以擴充套件我們自定義的這個RetryLimitHashedCredentialsMatcher 類,該類的功能主要是將使用者輸入的密碼與查詢到的密碼進行比較,也就是密碼比較器。
  上邊方法doCredentialsMatch 的邏輯裡,有verifyToken 這樣的方法,其實這個是針對於那種沒有賬號密碼,只有token 字串的金鑰登入的方式。這裡先不說這一種。
  userService 裡是我們自己提前寫好的一系列針對於使用者驗證的介面,因為shiro 不會去維護使用者、許可權、角色這些東西,需要我們自己維護,關於建表的那些步驟,我在第一篇裡已經寫了,shiro框架—關於shiro框架的簡單介紹及使用者表的建立維護,比如這裡的passwordVerify 方法 ,通過名字可以理解,是驗證密碼的介面,這些會在下一篇寫出來。

3.MShiroFilterFactoryBean 類的配置內容

  還記得在上一篇文章shiro框架—shiro配置介紹(一) 裡,提到過 MShiroFilterFactoryBean 繼承於 ShiroFilterFactoryBean 類,是我們自己自定義的shiroFilter ,該類在shiroConfig 裡注入到spring 容器中,另外,因為shiro 的攔截是對所有請求進行攔截,關於.js.css.html.png靜態資源的請求,應該是不要攔截的,所以我們需要在自定義shiroFilter 裡對這些靜態資源進行過濾,對我們專案來說,這就是這個MShiroFilterFactoryBean 的存在的意義。
  具體配置如下:

package microservice.fpzj.shiro;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.filter.mgt.FilterChainManager;
import org.apache.shiro.web.filter.mgt.FilterChainResolver;
import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver;
import org.apache.shiro.web.mgt.WebSecurityManager;
import org.apache.shiro.web.servlet.AbstractShiroFilter;
import org.springframework.beans.factory.BeanInitializationException;
/**
 * 自定義shiro過濾規則
 * @author Administrator
 *
 */
public class MShiroFilterFactoryBean extends ShiroFilterFactoryBean{
//   對ShiroFilter來說,需要直接忽略的請求
    private Set<String> ignoreExt;
    public MShiroFilterFactoryBean() {
        super();
        ignoreExt = new HashSet<>();
        ignoreExt.add(".jsp");
//        ignoreExt.add(".png");
    }

    @Override
    protected AbstractShiroFilter createInstance() throws Exception {
        org.apache.shiro.mgt.SecurityManager securityManager = getSecurityManager();
        if (securityManager == null) {
            String msg = "SecurityManager property must be set.";
            throw new BeanInitializationException(msg);
        }

        if (!(securityManager instanceof WebSecurityManager)) {
            String msg = "The security manager does not implement the WebSecurityManager interface.";
            throw new BeanInitializationException(msg);
        }
        FilterChainManager manager = createFilterChainManager();
        PathMatchingFilterChainResolver chainResolver = new PathMatchingFilterChainResolver();
        chainResolver.setFilterChainManager(manager);
        return new MSpringShiroFilter((WebSecurityManager) securityManager, chainResolver);
    }

    private final class MSpringShiroFilter extends AbstractShiroFilter {
        protected MSpringShiroFilter(WebSecurityManager webSecurityManager, FilterChainResolver resolver) {
            super();
            if (webSecurityManager == null) {
                throw new IllegalArgumentException("WebSecurityManager property cannot be null.");
            }
            setSecurityManager(webSecurityManager);
            if (resolver != null) {
                setFilterChainResolver(resolver);
            }
        }

        @Override
        protected void doFilterInternal(ServletRequest servletRequest, ServletResponse servletResponse,
                FilterChain chain) throws ServletException, IOException {
            HttpServletRequest request = (HttpServletRequest)servletRequest;
            String str = request.getRequestURI().toLowerCase();
            // 因為ShiroFilter 攔截所有請求(在上面我們配置了urlPattern 為 * ,當然你也可以在那裡精確的新增要處理的路徑,這樣就不需要這個類了),而在每次請求裡面都做了session的讀取和更新訪問時間等操作,這樣在叢集部署session共享的情況下,數量級的加大了處理量負載。
            // 所以我們這裡將一些能忽略的請求忽略掉。
            // 當然如果你的集群系統使用了動靜分離處理,靜態資料的請求不會到Filter這個層面,便可以忽略。
            boolean flag = true;
            int idx = 0;
            if(( idx = str.indexOf(".")) > 0 ){
                str = str.substring(idx);
                /**
                *如果不是jsp則為false,即除了.jsp,其他的都不需要攔截
                **/
                if(!ignoreExt.contains(str.toLowerCase())){ 
                    flag = false;
                }
            }
            if(flag){
                super.doFilterInternal(servletRequest, servletResponse, chain);
            }else{
                chain.doFilter(servletRequest, servletResponse);
            }
        }

    }
}

  通過以上的配置,就會將所有不是.jsp 的又帶有.資源全部放開,即,沒有登入的情況下,可以訪問到,其他帶有. 的資源則全部被shiro攔截。

4.注意點

  以上的配置檔案中,你會看到有很多的userService 中的方法,我沒有貼出來,後邊我也都會貼出來,但是,其實這樣的邏輯基本都是資料庫查詢的邏輯。

比如:

  下面的這個是根據使用者名稱獲取使用者物件的方法,因為使用者名稱是唯一的,這個應該很容易寫出來,就是根據使用者名稱欄位去匹配使用者表的一條物件記錄。

User user = userService.findUserByUserName(upt.getUsername())

  下面的這個是驗證賬號密碼的方法。

boolean flag = userService.passwordVerify(password,user.getPasswd(),user.getUserid()+user.getUsername())

  下面的這個是根據token字串獲取使用者名稱,token是一種jwt字串,是一種很長的字串,這裡主要用於那種沒有使用者名稱,只有一個令牌token字串,通過這個token字串,來到後臺驗證的時候,需要通過這個字串轉換成使用者名稱,然後再根據使用者名稱,呼叫上邊的方法獲取使用者物件。這裡先不考慮這種的登入,只考慮正常的那種賬號密碼的登入方式。

String username = userService.getUsernameFromToken(upt.getUsername())

  下面的這個是驗證客戶端傳入的token字串是否有效的介面。同樣這裡不考慮這種的登入方式。

boolean flag = userService.verifyToken(userToken.getUsername())

相關推薦

shiro框架---shiro配置介紹

  關於shiro在springboot的配置,共有四個基本配置檔案主要的檔案有四個ShiroConfig 、RetryLimitHashedCredentialsMatcher 、UserRealm 、MShiroFilterFactoryBean

AndroidStudio工具使用、build.gradle配置介紹

1:Project Structure 專案配置介紹 上面的配置都會在專案的build.gradle檔案中顯示出來 Sdk Location中可以配置AS的SDK,NDK,JDK 2:build.gradle構建檔案介紹 構建檔

上門洗車APP --- Androidclient開發 之 網絡框架封裝介紹

glob imp success rgb sed error margin p s 再次 上門洗車APP --- Androidclient開發 之 網絡框架封裝介紹(二)前幾篇博文中給大家介紹了一下APP中的基本業務及開發本項目使用的網絡架構:上門洗車APP ---

Spring MVC 框架結構介紹

指定 let url 16px () isp -s 一個 ping Spring MVC框架結構    Spring MVC是圍繞DispatcherServlet設計的,DispatcherServlet向處理程序分發各種請求。處理程序[email prot

unity遊戲開發之ULua框架介紹

1.SimpleFramework框架配置檔案 (1)AppConst 檔案    在AppConst.cs檔案中配置了很多專案開發過程中,需要使用到的“公共常量資訊”。指令碼內的常量都有中文備註。所在位置是:Scripts/ConstDefine/AppConst.cs

SSM整合系列之 基於Shiro框架實現自動登入RememberMe

一、前言:Shiro框架提供了記住我(RememerMe)的功能,比如我們訪問一些網站,關閉了瀏覽器,下次再開啟還是能記住你是誰,下次訪問的時候無需登入即可訪問,本文將實現記住我的功能。 專案git地址:https://github.com/gitcaiqing/SSM_DEMO.git

Java集合框架詳解--Collection介面簡單介紹

一、Collection介面簡單介紹        Collection介面是處理物件集合的根介面,其中定義了很多對元素進行操作的方法。Collection介面有兩個主要的子介面List和Set,注意Map不是Collection的子介面。 Collection介面中的方

開源框架.netCore DncZeus學習配置連線

配置連線字串,update-database,初始資料後,訪問報錯,提示offset錯誤。 .net Core中的EF訪問sqlserver2008預設使用的是offset分頁,這在sql2008上不支援。 .SetCompatibilityVersion(CompatibilityVersion.Ve

Weblogic基本配置-目錄介紹

weblogic目錄詳解 1. 目錄結構 user_projects:存放域的資料夾(必須要建立域後才可以產生) logs :存放日誌資訊 wlserver_10.3:weblogic目錄 預設域的目錄:Middleware\use_pro

應用程式框架實戰三十三:表現層及ASP.NET MVC介紹

  最近的更新速度越來越慢,主要是專案上比較忙,封裝EasyUi也要花很多時間。不過大家請放心,本系列不會半途夭折,並且程式碼乾貨也會持續更新。本文繼續介紹表現層和Asp.net Mvc,我將在本篇討論一些重要的設計問題和封裝技巧。 是否需要將控制器分離為獨立專案   經常有人問我,是否有必要將控制器從W

優秀框架介紹

前言 這一篇接著把一些很棒的框架介紹給大家,在官網上已經有很詳細的使用說明,所以我就不廢話了。 正文 RecyclerViewPager 一款基於RecyclerView的ViewPager,可以設定滑動速度,滑動的方向(橫向或豎直),是否

shiro+mybatis+springmvc例項記錄——shiro支援ajax請求

接上文,頁面跳轉顯然不適合動靜分離ajax互動的架構模式,因此就需要對框架進行改造優化,使得後臺能夠返回json資料給前端請求。 自定義攔截器 shiro對許可權、使用者資訊的校驗實在預設的攔截器中進行的,要改寫資料返回方式,則需要重寫攔截器。這裡我們分

.Net Core應用框架Util介紹

預覽版 相同 多多支持 framework 默認安裝 server 必須 自己 自動 Util的開源地址 https://github.com/dotnetcore/util Util的開源協議   Util以MIT協議開源,這是目前最寬松的開源協議,你不僅可以

.NET Core應用框架AA介紹

AA的開源地址 https://github.com/ChengLab/AAFrameWork  AA框架是一個基礎應用框架,是建立在眾多大家熟知的流行工具之上並與之整合。比如:ASP.NET Core、Automapper、Dapper、Dapper-FluentMap、RabbitMQ、Re

DNS服務器介紹——主從復制和區域轉發

dns;區域轉發;主從復值背景介紹實際環境中為了避免單點故障,DNS服務器是由一組服務器組成每一個服務器上都有若幹個區域,不同服務器上的相同區域分為主和從兩種角色。由於正向和反向是不同的區域,所以多臺服務器間的相同區域可以互為主從或者一主多從,本處以右圖為例進行演示。DNS服務器的主從復制1.之前已經在172

mongodb3.4.4安裝副本集,wt引擎配置優化

記錄 空間 今天大概研究下wiredtiger引擎,mongo從3.0開始引入,主要為了解決吃內存多,占用大量磁盤空間的問題,其實即使用了wt引擎,在性能上還是比tokuft要差,但是tokuft 在功能上代碼叠代的太慢,退而求其次大家還是用了mongo,首先3.0的時候默認還是mmapv1 引擎,所

集成CCFlow工作流與GPM的辦公系統馳騁CCOA介紹

崗位 mes 顯示 ccf 辦公 人員 文件 ron min GPM怎樣控制菜單權限以及菜單的增刪顯示 因為CCOA中僅僅有屬於admin才幹夠進行權限管理與流程設計。password為pub。 1.加入CCOA功能菜單 進入GPM後,找到編號為CCOA的信

Struts2入門介紹

輸入 clu ons dom 訪問路徑 訪問 filter pri locale 一、Struts執行過程的分析。   當我們在瀏覽器中輸入了網址http://127.0.0.1:8080/Struts2_01/hello.action的時候,Struts2做了如下過程:

linux設備驅動之misc驅動框架源碼分析

linux驅動開發misc設備驅動1、misc_open函數分析 該函數在driver/char/misc.c中,misc.c是驅動框架實現的,這裏面的misc_Open函數是misc驅動框架為應用層提供的一個打開misc設備的一個接口。 1、首先我們要知道在misc.c中的misc_init函數

深度學習數學基礎介紹概率與數理統計

特征 數字特征 抽樣分布 第5章 最大 中心 3.4 獨立 知識 第1章 隨機事件與概率§1.1 隨機事件§1.2 隨機事件的概率§1.3 古典概型與幾何概型§1.4 條件概率§1.5 事件的獨立性 第2章 隨機變量的分布與數字特征§2.1 隨機變量及其分布§2.2 隨機變