shiro框架---shiro配置介紹(二)
關於shiro在springboot的配置,共有四個基本配置檔案主要的檔案有四個ShiroConfig
、RetryLimitHashedCredentialsMatcher
、UserRealm
、MShiroFilterFactoryBean
。
因為上一篇僅僅寫完了shiroconfig
類的配置,雖然在上一篇最下邊,我已經附上了所有檔案的下載連結,但是我覺得還是要寫一下剩下的三個配置檔案,寫一下我對shiro配置的理解。下邊是剩餘三個配置檔案,即RetryLimitHashedCredentialsMatcher
、UserRealm
、MShiroFilterFactoryBean
的配置詳情。
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 隨機變