分享一個視屏教程集合 http://www.tudou.com/home/konghao/item
1.Shiro
Apache Shiro是一個強大且易用的Java安全框架,執行身份驗證、授權、密碼學和會話管理。使用Shiro的易於理解的API,您可以快速、輕松地獲得任何應用程序,從最小的移動應用程序到最大的網絡和企業應用程序,可以和Spring無縫結合.關鍵步驟需要開發實現.
2.主要功能
Authentication 認證
Authorization 授權
Cryptography 加密
Session Management Session 管理
Web Integration Web集成
Integrations 和其他集成
Subject:代表了當前用戶的安全操作,SecurityManager則管理所有用戶的安全操作,Current User。
SecurityManager:它是Shiro框架的核心,管理所有的Subject
Realm:Access your security data, Realm充當了Shiro與應用安全數據間的“橋梁”或者“連接器”。也就是說,當對用戶執行認證(登錄)和授權(訪問控制)驗證時,Shiro會從應用配置的Realm中查找用戶及其權限信息。
從這個意義上講,Realm實質上是一個安全相關的DAO:它封裝了數據源的連接細節,並在需要時將相關數據提供給Shiro。當配置Shiro時,你必須至少指定一個Realm,用於認證和(或)授權。
Shiro內置了可以連接大量安全數據源(又名目錄)的Realm,如LDAP、關系數據庫(JDBC)、類似ini的文本配置資源以及屬性文件等。如果缺省的Realm不能滿足需求,你還可以插入代表自定義數據源的自己的Realm。【百度百科】
<!-- 添加Apache Shiro 依賴關系 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.2</version> </dependency>
4.授權
也叫訪問控制,在應用中控制誰能訪問哪些資源(如訪問頁面/編輯數據/頁面操作等)。在授權中需了解的幾個關鍵對象:主體(Subject)、資源(Resource)、權限(Permission)、角色(Role)。
5.主體【Subject】
主體,即訪問應用的用戶,在Shiro中使用Subject代表該用戶。用戶只有授權后才允許訪問相應的資源。
6.資源【Resource】
在應用中用戶可以訪問的任何東西,比如訪問JSP頁面、查看/編輯某些數據、訪問某個業務方法、打印文本等等都是資源。用戶只要授權后才能訪問。
7.權限
安全策略中的原子授權單位,通過權限我們可以表示在應用中用戶有沒有操作某個資源的權力。即權限表示在應用中用戶能不能訪問某個資源,如:
訪問用戶列表頁面
查看/新增/修改/刪除用戶數據(即很多時候都是CRUD(增查改刪)式權限控制)
打印文檔等等。。。
如上可以看出,權限代表了用戶有沒有操作某個資源的權利,即反映在某個資源上的操作允不允許,不反映誰去執行這個操作。所以后續還需要把權限賦予給用戶,即定義哪個用戶允許在某個資源上做什么操作(權限),Shiro不會去做這件事情,而是由實現人員提供。
8.角色【Role】
角色代表了操作集合,可以理解為權限的集合,一般情況下我們會賦予用戶角色而不是權限,即這樣用戶可以擁有一組權限,賦予權限時比較方便。典型的如:項目經理、技術總監、CTO、開發工程師等都是角色,不同的角色擁有一組不同的權限。
隱式角色:
顯式角色:
請baidu搜索“RBAC”和“RBAC新解”分別了解“基於角色的訪問控制”“基於資源的訪問控制(Resource-Based Access Control)”。
9.Shiro 授權方式
Shiro支持三種方式授權
(1)編程式
Subject subject = SecurityUtils.getSubject(); if(subject.hasRole(“admin”)) { //有權限 } else { //無權限 }
(2)注解式:通過在執行的Java方法上放置相應的注解完成,沒有權限將拋出相應的異常;
@RequiresRoles("admin") public void hello() { //有權限 }
(3)JSP/GSP標簽:在JSP/GSP頁面通過相應的標簽完成
<shiro:hasRole name="admin"> <!— 有權限 —> </shiro:hasRole>
授權
(1)基於角色的訪問控制(隱式角色)
在ini配置文件配置用戶擁有的角色(shiro-role.ini)
[users] zhang=123,role1,role2 wang=123,role1
規則即:“用戶名=密碼,角色1,角色2”,如果需要在應用中判斷用戶是否有相應角色,就需要在相應的Realm中返回角色信息,也就是說Shiro不負責維護用戶-角色信息,需要應用提供,Shiro只是提供相應的接口方便驗證
測試用例
@Test public void testHasRole() { login("classpath:shiro-role.ini", "zhang", "123"); //判斷擁有角色:role1 Assert.assertTrue(subject().hasRole("role1")); //判斷擁有角色:role1 and role2 Assert.assertTrue(subject().hasAllRoles(Arrays.asList("role1", "role2"))); //判斷擁有角色:role1 and role2 and !role3 boolean[] result = subject().hasRoles(Arrays.asList("role1", "role2", "role3")); Assert.assertEquals(true, result[0]); Assert.assertEquals(true, result[1]); Assert.assertEquals(false, result[2]); }
Shiro提供了hasRole/hasRole用於判斷用戶是否擁有某個角色/某些權限;但是沒有提供如hashAnyRole用於判斷是否有某些權限中的某一個。
@Test(expected = UnauthorizedException.class) public void testCheckRole() { login("classpath:shiro-role.ini", "zhang", "123"); //斷言擁有角色:role1 subject().checkRole("role1"); //斷言擁有角色:role1 and role3 失敗拋出異常 subject().checkRoles("role1", "role3"); }
(2)基於資源的訪問控制(顯式角色)
在ini配置文件配置用戶擁有的角色及角色-權限關系(shiro-permission.ini)
[users] zhang=123,role1,role2 wang=123,role1 [roles] role1=user:create,user:update role2=user:create,user:delete
規則:“用戶名=密碼,角色1,角色2”“角色=權限1,權限2”,即首先根據用戶名找到角色,然后根據角色再找到權限;即角色是權限集合;Shiro同樣不進行權限的維護,需要我們通過Realm返回相應的權限信息。只需要維護“用戶——角色”之間的關系即可。
測試用例
@Test public void testIsPermitted() { login("classpath:shiro-permission.ini", "zhang", "123"); //判斷擁有權限:user:create Assert.assertTrue(subject().isPermitted("user:create")); //判斷擁有權限:user:update and user:delete Assert.assertTrue(subject().isPermittedAll("user:update", "user:delete")); //判斷沒有權限:user:view Assert.assertFalse(subject().isPermitted("user:view")); }
@Test(expected = UnauthorizedException.class) public void testCheckPermission () { login("classpath:shiro-permission.ini", "zhang", "123"); //斷言擁有權限:user:create subject().checkPermission("user:create"); //斷言擁有權限:user:delete and user:update subject().checkPermissions("user:delete", "user:update"); //斷言擁有權限:user:view 失敗拋出異常 subject().checkPermissions("user:view"); }
失敗的情況下會拋出 UnauthorizedException 異常.
Subject subject = SecurityUtils.getSubject();
案例筆記:
權限數據庫設計(PS:盡量不要涉及外鍵,管理起來有時候會比較麻煩):
表:User(用戶) Role(角色) UserRole(用戶角色對應關系) Resource(資源) RoleResource(角色資源)
User(id username userpwd nickname status) //status標注用戶賬號是否停用或者被鎖定; Role(id name) Resource(id name permission url) RoleResource(id roleId resId) UserRole(id userId roleId)
Dao設計:繼承IBaseDao
IuserDao: 用戶接口
public list<User> listAllUsers();//查詢所有用戶 public list<User> listUsersByRole(int roleId);//根據角色取出所有用戶 public User loadByUserName(string username);//根據用戶得到用戶
IRoleDao: 角色接口
public list<Role> listRoles();//查詢所有的角色 public list<Role> listUserRole();//查詢某個用戶所有的角色 pubic UserRole loadUserRole(int userId,int RoleId); public void addUserRole(int userId,int RoleId); public void deleteUserRole(int UserId,int RoleId); public void deleteUserRole(int UserId);//刪除某個用戶的所有角色 public List<Resource> listRoleResources(int roleId);//根據角色Id添加角色可以訪問的資源 public void addRoleResource(int RoleId,int resId); public void deleteRoleResource(int roleId,int resId); public RoleResource loadRoleResource(int roleId,int resId); //獲取角色資源對象
IResourceDao: 資源接口
public List<Resource> listResource();
02 實現Service層:
IUserService IRoleService IRoleResource
shiro.Kit包下面添加密碼加密函數
static String md5(String password,String salt) { String p = null; p = new Md5Hash(password,salt).toHex(); return P; }
03 Junit 實現對Service層測試;