對這文章發表回應
發表限制: 非會員 可以發表
Apache shiro的簡單介紹與使用教程(與spring整合使用)
apache shiro框架簡介
Apache Shiro是一個強大而靈活的開源安全框架,它能夠乾淨利落地處理身份認證,授權,企業會話管理和加密。現在,使用Apache Shiro的人越來越多,因為它相當簡單,相比比Spring Security,Shiro可能沒有Spring Security那麼多強大的功能,但是在實際工作時可能並不需要那麼複雜的東西,所以使用簡單的Shiro就足夠了。
以下是你可以用 Apache Shiro所做的事情:
Shiro的4大核心部分——身份驗證,授權,會話管理和加密
Authentication:身份驗證,簡稱“登入”。
Authorization:授權,給使用者分配角色或者許可權資源
Session Management:使用者session管理器,可以讓CS程式也使用session來控制許可權
Cryptography:把JDK中複雜的密碼加密方式進行封裝。
除了以上功能,shiro還提供很多擴充套件
Web Support:主要針對web應用提供一些常用功能。
Caching:快取可以使應用程式執行更有效率。
Concurrency:多執行緒相關功能。
Testing:幫助我們進行測試相關功能
Run As:一個允許使用者假設為另一個使用者身份(如果允許)的功能,有時候在管理指令碼很有用。
Remember Me:記住使用者身份,提供類似購物車功能。
shiro框架認證流程
Application Code:應用程式程式碼,由開發人員負責開發的
Subject:框架提供的介面,是與程式進行互動的物件,可以是人也可以是服務或者其他,通常就理解為使用者。所有Subject 例項都必須繫結到一個SecurityManager上。我們與一個 Subject 互動,執行時shiro會自動轉化為與 SecurityManager互動的特定 subject的互動。
SecurityManager:框架提供的介面,是 Shiro的核心,代表安全管理器物件。初始化時協調各個模組執行。然而,一旦 SecurityManager協調完畢,SecurityManager 會被單獨留下,且我們只需要去操作Subject即可,無需操作SecurityManager 。 但是我們得知道,當我們正與一個 Subject 進行互動時,實質上是 SecurityManager在處理 Subject 安全操作。
Realm:可以開發人員編寫,框架也提供一些。Realms在 Shiro中作為應用程式和安全資料之間的“橋樑”或“聯結器”。他獲取安全資料來判斷subject是否能夠登入,subject擁有什麼許可權。他有點類似DAO。在配置realms時,需要至少一個realm。而且Shiro提供了一些常用的 Realms來連線資料來源,如LDAP資料來源的JndiLdapRealm,JDBC資料來源的JdbcRealm,ini檔案資料來源的IniRealm,properties檔案資料來源的PropertiesRealm,等等。我們也可以插入自己的 Realm實現來代表自定義的資料來源。 像其他元件一樣,Realms也是由SecurityManager控制。
更詳細的圖
下面就開始shiro與SSM工程的整合使用
下載地址: http://shiro.apache.org/download.html
下載下來這兩個個檔案,一個jar包,一個原始碼檔案
首先,第一步,將jar包匯入到工程中
然後,第二步,在web.xml中配置spring框架提供的用於整合shiro框架的過濾器(一定要放到springmvc或struts框架過濾器的前面,為了保險起見,放到最上面就好了)
<!--配置過濾器,用於整合Shiro-->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
第三步,在spring配置檔案中配置bean,id為shiroFilter
<!-- 配置shiro框架的過濾器工廠bean -->
<bean id="shiroFilter" >
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/index.jsp"/>
<property name="successUrl" value=""/>
<property name="unauthorizedUrl" value="/noPrivilegeUI.jsp"/>
<!-- 指定URL級別攔截策略 -->
<property name="filterChainDefinitions">
<value>
/script/** = anon
/style/** = anon
/index.jsp* = anon
/noPrivilegeUI.jsp* = anon
/user/login = anon
/role/findAllRoleList = perms["角色管理"]
/** = authc
</value>
</property>
</bean>
securityManager:這個屬性是必須的。
loginUrl :沒有登入的使用者請求需要登入的頁面時自動跳轉到登入頁面,不是必須的屬性,不輸入地址的話會自動尋找專案web專案的根目錄下的”/login.jsp”頁面。
successUrl :登入成功預設跳轉頁面,可以不配置,不配置則跳轉至”/”。如果登陸前點選的一個需要登入的頁面,則在登入自動跳轉到那個需要登入的頁面。不跳轉到此。
unauthorizedUrl :沒有許可權預設跳轉的頁面。
anon: 例子/admins/** = anon 沒有引數,表示可以匿名使用(需要認證(登入))。
authc : 例如/admins/user/** = authc 表示需要認證(登入)才能使用,沒有引數
roles:例子/admins/user/** = roles[admin], 引數可以寫多個,多個時必須加上引號,並且引數之間用逗號分割,當有多個引數時,例如admins/user/** = roles[“admin,guest”], 每個引數通過才算通過,相當於hasAllRoles()方法。
perms:例子/admins/user/** = perms[user:add:*], 引數可以寫多個,多個時必須加上引號,並且引數之間用逗號分割,例如/admins/user/** = perms[“user:add:*,user:modify:*”],當有多個引數時必須每個引數都通過才通過,想當於 isPermitedAll()方法。
Rest:例子/admins/user/** = rest[user];根據請求的方法,相當於/admins/user/** = perms[user:method] ;其中method為post,get,delete等。
port:例子/admins/user/** = port[8081]; 當請求的url的埠不是8081是跳轉到schemal://serverName:8081?queryString,其中schmal是協議http或https等,serverName是你訪問的host,8081是url配置裡port的埠,queryString
是你訪問的url裡的?後面的引數。
authcBasic:例如/admins/user/** = authcBasic; 沒有參數列示httpBasic認證
ssl:例子/admins/user/** = ssl;沒有引數,表示安全的url請求,協議為https
user:例如/admins/user/** = user; 沒有參數列示必須存在使用者,當登入操作時不做檢查
注:anon,authcBasic,auchc,user是認證過濾器,
perms,roles,ssl,rest,port是授權過濾器
第四步:配置安全管理器
<!-- 配置安全管理器 -->
<bean id="securityManager" />
第五步:寫一個login方法,使用shiro提供的方式進行認證操作
這是我之前的login方法,以這種方法,shiro是不知道登入驗證通過了的,一直不通過,所以我們要以shiro提供的認證操作方式進行登入操作
/**
* 登入
*/
@RequestMapping("/login")
public String login(User user, HttpServletRequest request, Model model){
HttpSession session = request.getSession();
User newUser = userService.login(user);
if(newUser != null){
session.setAttribute("loginUser",newUser);
return "home/home";
}
model.addAttribute("errorMessage","使用者名稱或者密碼不正確!");
return "forward:/index.jsp";
}
修改後的login方法
/**
* 使用Shiro框架提供的方式進行認證登入
*/
@RequestMapping("/login")
public String login(User user, HttpServletRequest request, Model model){
HttpSession session = request.getSession();
//使用Shiro框架提供的方式進行認證
Subject subject = SecurityUtils.getSubject(); //獲得當前登入使用者物件,現在狀態為 “未認證”
//使用者名稱密碼令牌
AuthenticationToken token = new UsernamePasswordToken(user.getLoginName(), MD5Utils.md5(user.getPassword()));
try{
subject.login(token); //執行你自定義的Realm
User user1 = (User) subject.getPrincipal();
session.setAttribute("loginUser",user1);
return "home/home";
}catch(UnknownAccountException e){
e.printStackTrace();
model.addAttribute("errorMessage","此使用者名稱不存在!");
}catch(IncorrectCredentialsException e){
e.printStackTrace();
model.addAttribute("errorMessage","密碼不正確!");
}catch(Exception e){
e.printStackTrace();
}
return "forward:/index.jsp";
}
第六步:自定義realm,並注入給安全管理器
建立一個UserRealm類,繼承AuthorizingRealm這個類
public class UserRealm extends AuthorizingRealm{
@Autowired
private UserDao userDao;
//認證方法
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("realm中的認證方法執行了。。。。");
UsernamePasswordToken myToken = (UsernamePasswordToken) token;
String loginName = myToken.getUsername();
//根據使用者名稱查詢資料庫中的使用者,這個方法是自己寫的
User user = userDao.findUserByLoginName(loginName);
if(user == null){
//使用者名稱不存在
return null;
}
//如果能查詢到,再由框架比對資料庫中查詢到的密碼和頁面提交的密碼是否一致
AuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());
return info;
}
//授權方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
}
將自定義realm注入給安全管理器
<!-- 配置安全管理器 -->
<bean id="securityManager" >
<!-- 注入realm -->
<property name="realm" ref="userRealm"/>
</bean>
<!-- 註冊自定義realm -->
<bean id="userRealm" />
到這裡程式就可以正常執行了,登入後進入首頁
但是點選角色管理,會進入沒有許可權的頁面
這是因為我在spring配置檔案中配置了 /role/findAllRoleList = perms[“角色管理”],而我還沒有給當前使用者授權,所以當前使用者沒有許可權訪問此路徑
所以要給該使用者授權,在UserRealm類中,編寫授權方法
//授權方法
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals){
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
User user = (User) principals.getPrimaryPrincipal();
for (Role role : user.getRoles()){
for (Privilege privilege : role.getPrivileges()){
info.addStringPermission(privilege.getName());
}
}
return info;
}
這樣,就可以正常訪問了,這個授權方法是在訪問/role/findAllRoleList這個路徑時,shiro框架自動呼叫的
我們之前進行許可權控制是在spring配置檔案中配置了 /role/findAllRoleList = perms[“角色管理”] ,現在介紹另一種方式,也是我比較喜歡的方式, 使用註解方式進行許可權控制
使用shiro的方法註解方式許可權控制
第一步:在springmvc配置檔案中開啟shiro註解支援(注意:springmvc框架,放到springmvc配置檔案中,struts放到spring配置檔案中)
<!-- 保證實現了Shiro內部lifecycle函式的bean執行 -->
<bean id="lifecycleBeanPostProcessor" />
<!-- 開啟shiro框架註解支援 -->
<!-- 自動代理 -->
<bean id="defaultAdvisorAutoProxyCreator" >
<!-- value必須設定為true使用cglib方式為物件建立代理物件,
預設為false,設為false,就是使用JDK方式為物件建立代理物件,程式會出錯 -->
<property name="proxyTargetClass" value="true"/>
</bean>
<!-- 配置shiro框架提供的切面類,用於建立代理物件 -->
<bean />
第二步:在Controller的方法上使用shiro註解—— @RequiresPermissions(“”) 執行這個方法必須有相應的許可權
/**
* 查詢崗位列表
*/
@RequiresPermissions("角色列表") //執行這個方法必須有角色列表這個許可權
@RequestMapping("/findAllRoleList")
public String findAllRoleList(Model model){
List<Role> roleList = roleService.findAllRoleList();
model.addAttribute("roleList",roleList);
return "role/list";
}
@RequiresAuthentication
驗證使用者是否登入,等同於方法subject.isAuthenticated() 結果為true時。
@ RequiresUser
驗證使用者是否被記憶,user有兩種含義:
一種是成功登入的(subject.isAuthenticated() 結果為true);
另外一種是被記憶的( subject.isRemembered()結果為true)。
@ RequiresGuest
驗證是否是一個guest的請求,與@ RequiresUser完全相反。
換言之,RequiresUser == ! RequiresGuest 。
此時subject.getPrincipal() 結果為null.
@ RequiresRoles
例如:
@RequiresRoles("aRoleName");
void someMethod();
如果subject中有aRoleName角色才可以訪問方法someMethod。如果沒有這個許可權則會丟擲異常AuthorizationException。
@RequiresPermissions
例如:
@RequiresPermissions( {"file:read", "write:aFile.txt"} )
void someMethod();
要求subject中必須同時含有file:read和write:aFile.txt的許可權才能執行方法someMethod()。否則丟擲異常AuthorizationException。
註解方式的許可權控制就完成了,但這種方式沒有許可權時不會自動跳轉到沒有許可權的頁面,而是直接把異常拋到頁面了,所以我們要配置一個全域性的異常處理
第三步:在springmvc配置檔案中,進行如下配置,配置全域性異常捕獲,當shiro框架丟擲許可權不足異常時,跳轉到許可權不足提示頁面
<!-- 全域性異常處理 -->
<bean >
<property name="exceptionMappings">
<props>
<prop key="org.apache.shiro.authz.UnauthorizedException">redirect:/noPrivilegeUI.jsp</prop>
</props>
</property>
</bean>
使用shiro提供的頁面標籤方式許可權控制
最後,說一說shiro提供的頁面標籤
第一步:在jsp頁面中引入shiro的標籤庫
<%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro"%>
第二步:使用shiro的標籤控制頁面元素展示
這樣,一個shiro入門程式就完成了。
總結
以上所述是小編給大家介紹的Apache shiro的簡單介紹與使用教程(與spring整合使用),希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回覆大家的。在此也非常感謝大家對指令碼之家網站的支援!
原文出處: Apache shiro的簡單介紹與使用教程