前言
在之前 Shiro 集成 Spring 這一章中我們簡單使用了 shiroFilter
中的 filterChainDefinitions
來做 認證
和 授權
的攔截,其實還有許多過濾器,可以做各種各樣的攔截,並且 Shiro 還提供了接口來讓我們自定義過濾器。
身份認證相關
anon
例:/admins/**=anon
,沒有參數,表示可以匿名使用。
authc
例:/admins/user/**=authc
,沒有參數,表示需要認證(登錄)才能使用。
authcBasic
例:/admins/user/**=authcBasic
,沒有參數,表示 httpBasic 認證。
user
例:/admins/user/**=user
,沒有參數,表示必須存在用戶(不一定已通過認證),只要曾被 Shiro 記住過登錄狀態的用戶就可以正常發起請求,比如 rememberMe
)。
logout
例:/logout=logout
,沒有參數,註銷當前登陸用戶,成功後會重定向地址到 /
。
授權相關
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()
方法。
port
例: /admins/user/**=port[8081]
,單個參數,當請求的 url 的端口不是 8081
時重定向到 schemal://hostName:8081?queryString
, 也就是說,除了端口,其他東西都會保留。
rest
例:/admins/user/**=rest[user]
,根據請求的方法,相當於 /admins/user/**=perms[user:method]
,其中method爲post,get,delete等。
ssl
例:/admins/user/**=ssl
沒有參數,表示安全的 url 請求,協議爲 https
,其實也等同於 /admin/user/**=port[443]
,即重定向到 443 端口。
自定義過濾器
以 roles
過濾器爲例:/admin/page1= roles["admin, user"]
,表示 /admin/page1
這個頁面必須需要用戶同時具備 admin
與 user
角色纔可訪問。
我們開發一個自定義的過濾器,判定需要 admin
或 user
可訪問。
package im.zhaojun.filter; import org.apache.shiro.subject.Subject; import org.apache.shiro.web.filter.authz.AuthorizationFilter; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class AnyRolesFilter extends AuthorizationFilter { @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { Subject subject = this.getSubject(request, response); String[] rolesArray = (String[]) ((String[]) mappedValue); if (rolesArray != null && rolesArray.length != 0) { for (String role : rolesArray) { if (subject.hasRole(role)) { return true; } } } else { return true; } return false; } }
注:這裏用到了 ServletRequest
和 ServletResponse
類,所以還需要導入相應的庫:
<dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency>
然後將其配置到 IOC 容器中:
<bean id="anyRolesFilter" class="im.zhaojun.filter.AnyRolesFilter"/>
最後爲其分配別名,並添加到過濾器鏈中:
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- 略 --> <property name="filterChainDefinitions"> <value> /login.jsp = anon /login = anon /user.jsp = anyRoles[user, admin] /userList.jsp = perms[select:delete] /logout = logout /** = authc </value> </property> <property name="filters"> <map> <entry key="anyRoles" value-ref="anyRolesFilter"/> </map> </property> </bean>
我們分別將 /user.jsp
設爲 roles[user, admin]
和 anyRoles[user, admin]
。
目前 Relam 中的用戶 zhao
- 123456
僅具備 user
角色,所以可以分別測試出,anyRoles
過濾的頁面可以正常訪問,而 roles
過濾器的內容因未同時具備 user
與 admin
角色而被攔截,跳轉到未授權頁面。
通配符
上面的示例中,我們還用到了 **
做通配符,其實還有幾個通配符:
?
:匹配一個字符,如 /admin?
可以匹配 /admin1
、/admin2
,但不能匹配 /admin
。
*
:匹配零個或一個或多個字符,如 /admin*
可以匹配 /admin
、/admin1
、/admin123
,但不能匹配 /admin/123
。
**
:匹配零個或多個路徑,如 /admin/**
可以匹配 /admin
、/admin/a/b/c
。
本章代碼地址 : https://github.com/zhaojun1998/Premission-Study/tree/master/Permission-Shiro-07/