shiro使用流程及原理
1、核心介紹
1)Application Code使用者編寫程式碼
2)Subject就是shiro管理的使用者
3)SecurityManager安全管理器,就是shiro許可權控制核心物件,在程式設計時,只需要操作Subject方法,底層呼叫SecurityManager方法,無需直接程式設計操作SecurityManager
4)Realm應用程式和安全資料之間聯結器,應用程式進行許可權控制讀取安全資料(資料表、檔案、網路…)通過Realm物件完成
2、Shiro執行流程
應用程式—>Subject—>SecurityManager—>Realm—>安全資料
3、Shiro進行許可權控制的四種主要方式
1)在程式中通過Subject程式設計方式進行許可權控制
2)配置Filter實現URL級別粗粒度許可權控制
3)配置代理,基於註解實現細粒度許可權控制
4)在頁面中使用shiro自定義標籤實現,頁面顯示許可權控制
Subject:表示當前操作的主體使用者,是一個抽象的概念,Subject可以進行登入、退出、許可權判斷等動作,通常一個subject與一個執行緒進行關聯。
Realm:表示驗證的資料來源,儲存使用者的安全資料,可以進行使用者名稱和密碼的匹配,及使用者許可權查詢。
認證大致原理:
shiro的核心是java servlet規範中的filter,通過配置攔截器,使用攔截器鏈來攔截請求,如果允許訪問,則通過。通常情況下,系統的登入、退出會配置攔截器。
登入的時候,呼叫subject.login(token),token是使用者驗證資訊,這個時候會在Realm(繼承AuthorizingRealm類)中doGetAuthenticationInfo方法中進行認證。這個時候會把使用者提交的驗證資訊與資料庫中儲存的認證資訊進行比較(先判斷使用者名稱是否正確,自定義查詢資料庫,然後執行new SimpleAuthenticationInfo(user,
user.getPassword(), getName());),
引數: // 引數一:儲存在subject中的資訊
// 引數二:securityManager自動用查到的password和使用者輸入的密碼進行比較,密碼一致,登入成功,錯誤則丟擲異常
// 引數三:realm名稱一致則允許訪問,並在瀏覽器種下此次回話的cookie,在伺服器端儲存session資訊。退出的時候,呼叫subject.logout(),會清除回話資訊。
// 基於subject實現登入
Subject subject = SecurityUtils.getSubject();
AuthenticationToken token = new UsernamePasswordToken(model.getUsername(), model.getPassword());
try {
// 登入成功shiro安全框架就會將使用者的資訊存放在session中
subject.login(token);
授權:執行Realm中的doGetAuthorizationInfo方法通過查詢資料庫的到對應的角色(role)和許可權(Permission)將其放入SimpleAuthorizationInfo(類)中,然後配置檔案中的
攔截器鏈(/pages/base/courier.html* = perms[courier:list],/pages/base/area.html* = roles[base])進行攔截
授權程式碼:
// 授權
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection pc) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 得到當前使用者
Subject subject = SecurityUtils.getSubject();
User user = (User) subject.getPrincipal();
// 呼叫業務層,// 查詢使用者對應的角色
List<Role> roles = roleService.findByUser(user);
for (Role role : roles) {
authorizationInfo.addRole(role.getKeyword());
}
// 呼叫業務層,查詢使用者所對應的許可權
List<Permission> permissions = permissionService.findByUser(user);
for (Permission permission : permissions) {
authorizationInfo.addStringPermission(permission.getKeyword());
}
return authorizationInfo;
核心filter配置
<!-- 配置核心shiro的Filter -->
<!-- 該id和web.xml中的<filter-name>shiroFilter</filter-name>一致 -->
<!-- 攔截器鏈-->
<bean id="shiroFilter"
class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- shiro 的核心安全介面-->
<property name="securityManager" ref="securityManager" />
<!-- 要求登入時的連結-->
<property name="loginUrl" value="/login.html" />
<!-- 登陸成功後要跳轉的連線-->
<property name="successUrl" value="/index.html" />
<!-- 未授權時要跳轉的連線-->
<property name="unauthorizedUrl" value="/unauthorized.html" />
<!-- shiro 連線約束配置-->
<property name="filterChainDefinitions" >
<value>
<!-- anon無須授權 authc需要授權 -->
/login.html* = anon
/css/**=anon
/js/** = anon
/images/**=anon
/services/**=anon
/validatecode.jsp*=anon
/user_login.action*=anon
<!-- 表示使用者必需擁有courier:list許可權才可以正常發起’/courier.html’請求 -->
/pages/base/courier.html* = perms[courier:list]
<!-- 表示使用者擁有base角色才可以正常發起’/area.html’請求 -->
/pages/base/area.html* = roles[base]
/** = authc
</value>
</property>
</bean>
Filter:
1.AnonymousFilter:通過此filter修飾的url,任何人都可以進行訪問,即使沒有進行許可權認證
2.FormAuthenticationFilter:通過此filter修飾的url,會對請求的url進行驗證,如果沒有通過,則會重定向返回到loginurl
3.BasicHttpAuthenticationFilter:通過此filter修飾的url,要求使用者已經通過認證,如果沒有通過,則會要求通過Authorization 資訊進行認證
4.LogoutFilter:通過此filter修飾的url,一旦收到url請求,則會立即呼叫subject進行退出,並重定向到redirectUrl
5.NoSessionCreationFilter:通過此filter修飾的url,不會建立任何會話
6.PermissionAuthorizationFilter:許可權攔截器,驗證使用者是否具有相關許可權
7.PortFilter:埠攔截器,不是通過制定埠訪問url,將自動將埠重定向到指定埠
8.HttpMethodPermissionFilter:rest風格攔截器,配置rest的訪問方式
9.RolesAuthorizationFilter:角色攔截器,未登陸,將跳轉到loginurl,未授權,將跳轉到unauthorizedUrl
10.SslFilter:HTTPS攔截器,需要以HTTPS的方式進行訪問
11.UserFilter:使用者攔截器,需要使用者已經認證,或已經remember me
anon未認證可以訪問
authc認證後可以訪問
perms需要特定許可權才能訪問
roles需要特定角色才能訪問
user需要特定使用者才能訪問
port需要特定端口才能訪問(不常用)
rest根據指定HTTP請求才能訪問(不常用)