麻豆小视频在线观看_中文黄色一级片_久久久成人精品_成片免费观看视频大全_午夜精品久久久久久久99热浪潮_成人一区二区三区四区

首頁 > 編程 > Java > 正文

Java 安全框架 - Shiro

2019-11-06 06:09:56
字體:
來源:轉載
供稿:網友

簡介

Apache Shiro 官網

Apache Shiro是一個強大且易用的java安全框架,執行身份驗證、授權、密碼學和會話管理。使用Shiro的易于理解的API,您可以快速、輕松地獲得任何應用程序,從最小的移動應用程序到最大的網絡和企業應用程序。

主要特性

主要特性

Authentication(驗證)Authorization(授權)session Management(會話管理)Cryptography(加密)

身份認證(驗證)

ShiroAuthenticationSequence

從配置文件獲取用戶密碼

依賴<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.3.2</version> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </exclusion> </exclusions></dependency><dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.23</version></dependency>配置文件

shiro.ini

# 此處只是演示,實際項目中用戶/密碼會在數據庫取得[users]lee=123456

log4j.PRoperties

## Licensed to the Apache Software Foundation (ASF) under one# or more contributor license agreements. See the NOTICE file# distributed with this work for additional information# regarding copyright ownership. The ASF licenses this file# to you under the Apache License, Version 2.0 (the# "License"); you may not use this file except in compliance# with the License. You may obtain a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing,# software distributed under the License is distributed on an# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY# KIND, either express or implied. See the License for the# specific language governing permissions and limitations# under the License.#log4j.rootLogger=INFO, stdoutlog4j.appender.stdout=org.apache.log4j.ConsoleAppenderlog4j.appender.stdout.layout=org.apache.log4j.PatternLayoutlog4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n# General Apache librarieslog4j.logger.org.apache=WARN# Springlog4j.logger.org.springframework=WARN# Default Shiro logginglog4j.logger.org.apache.shiro=TRACE# Disable verbose logginglog4j.logger.org.apache.shiro.util.ThreadContext=WARNlog4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARNHelloShiro.javaimport org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.UsernamePassWordToken;import org.apache.shiro.config.IniSecurityManagerFactory;import org.apache.shiro.mgt.SecurityManager;import org.apache.shiro.subject.Subject;import org.apache.shiro.util.Factory;public class HelloShiro { public static void main(String[] args) { // 讀取配置文件,初始化 SecurityManager 工廠 Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); // 獲取 SecurityManager 實例 SecurityManager securityManager = factory.getInstance(); // 把 SecurityManager 實例綁定到 SecurityUtils SecurityUtils.setSecurityManager(securityManager); // 得到當前執行的用戶 Subject currentUser = SecurityUtils.getSubject(); // 創建 token 令牌,用戶名/密碼 UsernamePasswordToken token = new UsernamePasswordToken("lee", "123456"); try { // 登錄 currentUser.login(token); System.out.println("身份認證成功"); } catch (AuthenticationException e) { e.printStackTrace(); System.out.println("身份認證失敗"); } // 退出 currentUser.logout(); }}執行成功

成功

執行失敗,即用戶名或密碼錯誤

失敗

以上就是一簡單的 Shiro 實例。

從數據庫獲取用戶密碼

此過程根據上述代碼修改

依賴<dependency> <groupId>com.mchange</groupId> <artifactId>c3p0</artifactId> <version>0.9.5.2</version></dependency><dependency> <groupId>MySQL</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.39</version></dependency><!-- org.apache.shiro.util.AbstractFactory.getInstance需要 --><dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version></dependency>配置文件

jdbcRealm.ini

[main]# 使用數據庫保存的用戶密碼jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm# 數據源dataSource=com.mchange.v2.c3p0.ComboPooledDataSourcedataSource.driverClass=com.mysql.jdbc.DriverdataSource.jdbcUrl=jdbc:mysql://localhost:3306/javadataSource.user=rootdataSource.password=root# 設置 jdbcRealm 數據源jdbcRealm.dataSource=$dataSource# 設置 securityManager 的 realm,多個逗號隔開securityManager.realms=$jdbcRealmSQL 文件

在編寫 SQL 時先說明下,Shiro 默認是根據提供的數據庫,去尋找users,用戶名和密碼字段為usernamepassword。格式如下:

jdbcRealm

JdbcShiro.java// 此處只需改變配置文件即可,其它代碼與上述 HelloShrio 代碼一致Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:jdbcRealm.ini");

權限認證(授權)

最核心的三個要素:權限,角色和用戶。

ShiroUtils.javaimport org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.config.IniSecurityManagerFactory;import org.apache.shiro.mgt.SecurityManager;import org.apache.shiro.subject.Subject;import org.apache.shiro.util.Factory;public class ShiroUtils { public static Subject login(String iniResourcePath, String username, String password) { // 讀取配置文件,初始化 SecurityManager 工廠 Factory<SecurityManager> factory = new IniSecurityManagerFactory(iniResourcePath); // 獲取 SecurityManager 實例 SecurityManager securityManager = factory.getInstance(); // 把 SecurityManager 實例綁定到 SecurityUtils SecurityUtils.setSecurityManager(securityManager); // 得到當前執行的用戶 Subject currentUser = SecurityUtils.getSubject(); // 創建 token 令牌,用戶名/密碼 UsernamePasswordToken token = new UsernamePasswordToken(username, password); try { // 登錄 currentUser.login(token); System.out.println("身份認證成功"); } catch (AuthenticationException e) { e.printStackTrace(); System.out.println("身份認證失敗"); } return currentUser; }}

編程式授權

基于角色的訪問控制(RBAC)

baseRole.ini[users]# 等號右邊第一個為密碼,后面為角色lee1=123, role1lee2=456, role1, role2

角色控制

RoleTest.javaimport com.lee.shiro.util.ShiroUtils;import org.apache.shiro.subject.Subject;import org.junit.Test;public class RoleTest { @Test public void HasRoleTest() { Subject currentUser = ShiroUtils.login("classpath:shiroRole.ini", "lee1", "123"); System.out.println(currentUser.hasRole("role1")); }}

Subject 判斷當前用戶是否具有某角色的方法

返回值為布爾類型的

boolean hasRole(String roleIdentifier)boolean[] hasRoles(List<String> roleIdentifiers)boolean hasAllRoles(Collection<String> roleIdentifiers)

沒有返回值但拋異常的

void checkRole(String roleIdentifier) throws AuthorizationExceptionvoid checkRoles(Collection<String> roleIdentifiers) throws AuthorizationExceptionvoid checkRoles(String... roleIdentifiers) throws AuthorizationException

基于權限的訪問控制

basePermisssion.ini[users]# 等號右邊第一個為密碼,后面為角色lee1=123, role1lee2=456, role1, role2[roles]role1=user:selectrole2=user:add, user:update, user:delete

權限控制

PermissionTest.javaimport com.lee.shiro.util.ShiroUtils;import org.apache.shiro.subject.Subject;import org.junit.Test;public class PermissionTest { @Test public void isPermitted() { Subject currentUser = ShiroUtils.login("classpath:basePermission.ini", "lee1", "123"); System.out.println(currentUser.isPermitted("user:select")); }}

Subject 判斷當前用戶是否具有某權限的方法

返回值為布爾類型的

boolean isPermitted(Permission permission)boolean[] isPermitted(String... permissions)boolean[] isPermitted(List<Permission> permissions)boolean isPermittedAll(String... permissions)boolean isPermittedAll(Collection<Permission> permissions)

沒有返回值但拋異常的

void checkPermission(String permission) throws AuthorizationExceptionvoid checkPermission(Permission permission) throws AuthorizationExceptionvoid checkPermissions(String... permissions) throws AuthorizationExceptionvoid checkPermissions(Collection<Permission> permissions) throws AuthorizationException

注解式授權

基于注解授權

@RequiresAuthentication

要求當前 Subject 已經在當前的 session 中被驗證通過才能被訪問或調用。

@RequiresAuthenticationpublic void updateAccount(Account userAccount) { //this method will only be invoked by a //Subject that is guaranteed authenticated ...}

等同于

public void updateAccount(Account userAccount) { if (!SecurityUtils.getSubject().isAuthenticated()) { throw new AuthorizationException(...); } //Subject is guaranteed authenticated here ...}

@RequiresGuest

要求當前的 Subject 是一個“guest”,也就是說,他們必須是在之前的 session 中沒有被驗證或被記住才能被訪問或調用。

@RequiresGuestpublic void signUp(User newUser) { //this method will only be invoked by a //Subject that is unknown/anonymous ...}

等同于

public void signUp(User newUser) { Subject currentUser = SecurityUtils.getSubject(); PrincipalCollection principals = currentUser.getPrincipals(); if (principals != null && !principals.isEmpty()) { //known identity - not a guest: throw new AuthorizationException(...); } //Subject is guaranteed to be a 'guest' here ...}

@RequiresPermissions(“account:create”)

要求當前的 Subject 被允許一個或多個權限,以便執行注解方法。

@RequiresPermissions("account:create")public void createAccount(Account account) { //this method will only be invoked by a Subject //that is permitted to create an account ...}

等同于

public void createAccount(Account account) { Subject currentUser = SecurityUtils.getSubject(); if (!subject.isPermitted("account:create")) { throw new AuthorizationException(...); } //Subject is guaranteed to be permitted here ...}

@RequiresRoles(“administrator”)

要求當前的 Subject 擁有所有指定的角色,如果他們沒有,則該方法將不會被執行,而且AuthorizationException異常將會被拋出。

@RequiresRoles("administrator")public void deleteUser(User user) { //this method will only be invoked by an administrator ...}

等同于

public void deleteUser(User user) { Subject currentUser = SecurityUtils.getSubject(); if (!subject.hasRole("administrator")) { throw new AuthorizationException(...); } //Subject is guaranteed to be an 'administrator' here ...}

@RequiresUser

注解需要當前的 Subject 是一個應用程序用戶才能被注解的類/實例方法訪問或調用。一個“應用程序用戶”被定義為一個擁有已知身份,或在當前 session 中通過驗證確認,或者在之前 session 中的“RememberMe”服務被記住。

@RequiresUserpublic void updateAccount(Account account) { //this method will only be invoked by a 'user' //i.e. a Subject with a known identity ...}

等同于

public void updateAccount(Account account) { Subject currentUser = SecurityUtils.getSubject(); PrincipalCollection principals = currentUser.getPrincipals(); if (principals == null || principals.isEmpty()) { //no identity - they're anonymous, not allowed: throw new AuthorizationException(...); } //Subject is guaranteed to have a known identity here ...}

jsp 標簽授權

JSP 標簽授權需要導入shiro-web.jar,并添加標簽:

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

The guest tag

用戶沒有身份驗證時顯示相應信息,即游客訪問信息。

<shiro:guest> Hi there! Please <a href="login.jsp">Login</a> or <a href="signup.jsp">Signup</a> today!</shiro:guest>

The user tag

用戶已經身份驗證/記住我登錄后顯示相應的信息。

<shiro:user> Welcome back John! Not John? Click <a href="login.jsp">here<a> to login.</shiro:user>

The authenticated tag

用戶已經身份驗證通過,即 Subject.login 登錄成功,不是記住我登錄的。

<shiro:authenticated> <a href="updateAccount.jsp">Update your contact information</a>.</shiro:authenticated>

The notAuthenticated tag

用戶沒有身份驗證通過,即沒有調用 Subject.login 進行登錄,包括記住我自動登錄的也屬于未進行身份驗證。

<shiro:notAuthenticated> Please <a href="login.jsp">login</a> in order to update your credit card information.</shiro:notAuthenticated>

The principal tag

顯示用戶身份信息,默認調用 Subject.getPrincipal() 獲取,即 Primary Principal。

Hello, <shiro:principal/>, how are you today?

等同于

Hello, <%= SecurityUtils.getSubject().getPrincipal().toString() %>, how are you today?Principal propertyHello, <shiro:principal property="firstName"/>, how are you today?Hello, <%= SecurityUtils.getSubject().getPrincipal().getFirstName().toString() %>, how are you today?Hello, <shiro:principal type="com.foo.User" property="firstName"/>, how are you today?Hello, <%= SecurityUtils.getSubject().getPrincipals().oneByType(com.foo.User.class).getFirstName().toString() %>, how are you today?

The hasRole tag

如果當前 Subject 有此角色將顯示 body 內容。

<shiro:hasRole name="administrator"> <a href="admin.jsp">Administer the system</a></shiro:hasRole>

The lacksRole tag

如果當前 Subject 沒有角色將顯示 body 內容。

<shiro:lacksRole name="administrator"> Sorry, you are not allowed to administer the system.</shiro:lacksRole>

The hasAnyRole tag

如果當前 Subject 有任意一個角色(或關系),將顯示 body 內容。

<shiro:hasAnyRoles name="developer, project manager, administrator"> You are either a developer, project manager, or administrator.</shiro:lacksRole>

The haspermission tag

如果當前 Subject 有權限將顯示 body 內容。

<shiro:hasPermission name="user:create"> <a href="createUser.jsp">Create a new User</a></shiro:hasPermission>

The lacksPermission tag

如果當前 Subject 沒有權限將顯示 body 內容。

<shiro:lacksPermission name="user:delete"> Sorry, you are not allowed to delete user accounts.</shiro:hasPermission>

集成 Web

此處只列舉關鍵代碼,若要查看詳細代碼移步到GitHub

依賴<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.3.2</version></dependency><dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version></dependency>web.xml<!-- 若使用 classpath 則需在此定義,否則將此去掉 --><context-param> <param-name>shiroConfigLocations</param-name> <param-value>classpath:shiroWeb.ini</param-value></context-param><listener> <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class></listener><filter> <filter-name>ShiroFilter</filter-name> <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class> <!-- 若配置文件在 /WEB-INF/ 下則在此配置 <init-param> <param-name>configPath</param-name> <param-value>/WEB-INF/shiroWeb.ini</param-value> </init-param> --></filter><filter-mapping> <filter-name>ShiroFilter</filter-name> <url-pattern>/*</url-pattern></filter-mapping>shiroWeb.ini# authc、roles 等都代表著一個 Filter,具體意義看 Default Filters[main]# 身份認證,若沒有登錄則跳轉到 /loginauthc.loginUrl=/login# 角色認證,若無此角色的用戶將跳轉到 /unauthorized.jsproles.unauthorizedUrl=/unauthorized.jsp# 權限認證,若無權限則跳轉到 /unauthorized.jspperms.unauthorizedUrl=/unauthorized.jsp[users]lee1=123, adminlee2=456, teacherlee3=789[roles]admin=user:*, student:*teacher=student:*# 該 urls 里的所有 url 都將被右邊的過濾器攔截# ? 匹配單個字符,如:/admin? -> /admin1、/admin2# * 匹配零個或多個字符,如:/admin* -> /admin、/admin1、/admin123# ** 匹配多個路徑,如:/admin/** -> /admin/、/admin/1、/admin/1/2[urls]# 需要 anon 權限才能訪問,anon 表示不需要權限,游客/login=anon# 首先需要登錄,判斷有 admin 權限的用戶才能訪問/admin=roles[admin]# 訪問 /student 需要角色需要有 teacher/student=roles[teacher]# 訪問 /teacher 需要有 user:create/teacher=perms[user:create]LoginServlet.javaimport org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.subject.Subject;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@WebServlet(urlPatterns = "/login") // 需 web 3.0public class LoginServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("login doGet"); req.getRequestDispatcher("login.jsp").forward(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("login doPost"); String username = req.getParameter("username"); String password = req.getParameter("password"); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, password); try { subject.login(token); resp.sendRedirect("success.jsp"); } catch (AuthenticationException e) { e.printStackTrace(); req.setAttribute("errorInfo", "用戶名或密碼錯誤"); req.getRequestDispatcher("login.jsp").forward(req, resp); } }}

Default Filters

Default Filters 是 Shiro 提供給我們的 Web 過濾器,他們將攔截各種請求,并判斷是否有權限訪問。

身份驗證

authcorg.apache.shiro.web.filter.authc.FormAuthenticationFilter

基于表單的攔截器; 如“/**=authc”,如果沒有登錄會跳到相應的登錄頁面登錄; 主要屬性:usernameParam:表單提交的用戶名參數名( username); passwordParam:表單提交的密碼參數名(password); rememberMeParam:表單提交的密碼參數名(rememberMe); loginUrl:登錄頁面地址(/login.jsp); successUrl:登錄成功后的默認重定向地址; failureKeyAttribute:登錄失敗后錯誤信息存儲key(shiroLoginFailure);

authcBasicorg.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter

Basic HTTP身份驗證攔截器,主要屬性: applicationName:彈出登錄框顯示的信息(application);

logoutorg.apache.shiro.web.filter.authc.LogoutFilter

退出攔截器,主要屬性: redirectUrl:退出成功后重定向的地址(/); 示例“/logout=logout”

userorg.apache.shiro.web.filter.authc.UserFilter

用戶攔截器,用戶已經身份驗證/記住我登錄的都可; 示例“/**=user”

anonorg.apache.shiro.web.filter.authc.AnonymousFilter

匿名攔截器,即不需要登錄即可訪問; 一般用于靜態資源過濾; 示例“/static/**=anon”

授權相關

rolesorg.apache.shiro.web.filter.authz.RolesAuthorizationFilter

角色授權攔截器,驗證用戶是否擁有所有角色; 主要屬性: loginUrl:登錄頁面地址(/login.jsp); unauthorizedUrl:未授權后重定向的地址; 示例“/admin/**=roles[admin]”

permsorg.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter

權限授權攔截器,驗證用戶是否擁有所有權限; 屬性和roles一樣; 示例“/user/**=perms[“user:create”]”

portorg.apache.shiro.web.filter.authz.PortFilter

端口攔截器,主要屬性:port(80):可以通過的端口; 示例“/test= port[80]”,如果用戶訪問該頁面是非80,將自動將請求端口改為80并重定向到該80端口,其他路徑/參數等都一樣

restorg.apache.shiro.web.filter.authz.HttpMethodPermissionFilter

rest風格攔截器,自動根據請求方法構建權限字符串 (GET=read, POST=create,PUT=update,DELETE=delete, HEAD=read,TRACE=read,OPTIONS=read, MKCOL=create) 構建權限字符串; 示例“/users=rest[user]”,會自動拼出“user:read,user:create,user:update,user:delete”權限字符串進行權限匹配(所有都得匹配,isPermittedAll);

sslorg.apache.shiro.web.filter.authz.SslFilter

SSL攔截器,只有請求協議是https才能通過; 否則自動跳轉會https端口(443); 其他和port攔截器一樣;

其他

noSessionCreationorg.apache.shiro.web.filter.session.NoSessionCreationFilter

不創建會話攔截器,調用 subject.getSession(false)不會有什么問題, 但是如果 subject.getSession(true)將拋出 DisabledSessionException異常;

自定義 Realm

在認證、授權內部實現機制中都有提到,最終處理都將交給Real進行處理。因為在Shiro中,最終是通過Realm來獲取應用程序中的用戶、角色及權限信息的。通常情況下,在Realm中會直接從我們的數據源中獲取Shiro需要的驗證信息。可以說,Realm是專用于安全框架的DAO。

如何編寫自定義 Realm

CustomizeRealm.javaimport com.lee.shiro.dao.UserDao;import com.lee.shiro.dao.impl.UserDaoImpl;import com.lee.shiro.entity.User;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.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import java.util.Set;public class CustomizeRealm extends AuthorizingRealm { private UserDao userDao = new UserDaoImpl(); /** * 為當前用戶授權 * 先執行 doGetAuthenticationInfo(token) * 然后執行此方法 * * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { String username = (String) principalCollection.getPrimaryPrincipal(); SimpleAuthorizationInfo authInfo = new SimpleAuthorizationInfo(); Set<String> rolesSet = userDao.getRolesByUsername(username); Set<String> permissionSet = userDao.getPermissionsByUsername(username); authInfo.setRoles(rolesSet); authInfo.setStringPermissions(permissionSet); return authInfo; } /** * 驗證當前登錄的用戶 * * @param token * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String) token.getPrincipal(); User user = userDao.getByUsername(username); AuthenticationInfo authInfo = null; if (user != null) { authInfo = new SimpleAuthenticationInfo( user.getUsername(), user.getPassword(), "userRealm"); } return authInfo; }}

就像我們之前使用 Shiro 自帶的 org.apache.shiro.realm.jdbc.JdbcRealm,只不過我們需要按照 Shiro 規定的數據庫表和字段,自定義則可以自己編寫 SQL,接上面 Web 繼續編寫:

customizeRealm.ini# 有順序的,依次向下[main]# 身份認證,若沒有登錄則跳轉到 /loginauthc.loginUrl=/login# 角色認證,若無此角色的用戶將跳轉到 /unauthorized.jsproles.unauthorizedUrl=/unauthorized.jsp# 權限認證,若無權限則跳轉到 /unauthorized.jspperms.unauthorizedUrl=/unauthorized.jsp# 設置 Shiro 使用自定義 RealmcustomizeRealm=com.lee.shiro.realm.CustomizeRealmsecurityManager.realms=$customizeRealm########## 分割線 ########### 該 urls 里的所有 url 都將被右邊的過濾器攔截# ? 匹配單個字符,如:/admin? -> /admin1、/admin2# * 匹配零個或多個字符,如:/admin* -> /admin、/admin1、/admin123# ** 匹配多個路徑,如:/admin/** -> /admin/、/admin/1、/admin/1/2[urls]# 需要 anon 權限才能訪問,anon 表示不需要權限,游客/login=anon# 首先需要登錄,判斷有 admin 權限的用戶才能訪問/admin=roles[admin]# 訪問 /student 需要角色需要有 teacher/student=roles[teacher]# 訪問 /teacher 需要有 user:create/teacher=perms[user:create]

具體實現看GitHub

整合 Spring

整合 Spring

JavaSE應用

spring-shiro.xml提供了普通JavaSE獨立應用的Spring配置:

spring-shiro.xml<!-- 緩存管理器 使用Ehcache實現 --> <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/> </bean> <!-- 憑證匹配器 --> <bean id="credentialsMatcher" class=" com.github.zhangkaitao.shiro.chapter12.credentials.RetryLimitHashedCredentialsMatcher"> <constructor-arg ref="cacheManager"/> <property name="hashAlgorithmName" value="md5"/> <property name="hashIterations" value="2"/> <property name="storedCredentialsHexEncoded" value="true"/> </bean> <!-- Realm實現 --> <bean id="userRealm" class="com.github.zhangkaitao.shiro.chapter12.realm.UserRealm"> <property name="userService" ref="userService"/> <property name="credentialsMatcher" ref="credentialsMatcher"/> <property name="cachingEnabled" value="true"/> <property name="authenticationCachingEnabled" value="true"/> <property name="authenticationCacheName" value="authenticationCache"/> <property name="authorizationCachingEnabled" value="true"/> <property name="authorizationCacheName" value="authorizationCache"/> </bean> <!-- 會話ID生成器 --> <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/> <!-- 會話DAO --> <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"> <property name="activeSessionsCacheName" value="shiro-activeSessionCache"/> <property name="sessionIdGenerator" ref="sessionIdGenerator"/> </bean> <!-- 會話驗證調度器 --> <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler"> <property name="sessionValidationInterval" value="1800000"/> <property name="sessionManager" ref="sessionManager"/> </bean> <!-- 會話管理器 --> <bean id="sessionManager" class="org.apache.shiro.session.mgt.DefaultSessionManager"> <property name="globalSessionTimeout" value="1800000"/> <property name="deleteInvalidSessions" value="true"/> <property name="sessionValidationSchedulerEnabled" value="true"/> <property name="sessionValidationScheduler" ref="sessionValidationScheduler"/> <property name="sessionDAO" ref="sessionDAO"/> </bean> <!-- 安全管理器 --> <bean id="securityManager" class="org.apache.shiro.mgt.DefaultSecurityManager"> <property name="realms"> <list><ref bean="userRealm"/></list> </property> <property name="sessionManager" ref="sessionManager"/> <property name="cacheManager" ref="cacheManager"/> </bean> <!-- 相當于調用SecurityUtils.setSecurityManager(securityManager) --> <bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"> <property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/> <property name="arguments" ref="securityManager"/> </bean> <!-- Shiro生命周期處理器--> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

可以看出,只要把之前的ini配置翻譯為此處的spring xml配置方式即可。

LifecycleBeanPostProcessor用于在實現了Initializable接口的Shiro bean初始化時調用Initializable接口回調,在實現了Destroyable接口的Shiro bean銷毀時調用 Destroyable接口回調。如UserRealm就實現了Initializable,而DefaultSecurityManager實現了Destroyable。具體可以查看它們的繼承關系。

Web應用

Web應用和普通JavaSE應用的某些配置是類似的,此處只提供一些不一樣的配置,詳細配置可以參考spring-shiro-web.xml。

spring-shiro-web.xml<!-- 會話Cookie模板 --> <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="sid"/> <property name="httpOnly" value="true"/> <property name="maxAge" value="180000"/> </bean> <!-- 會話管理器 --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <property name="globalSessionTimeout" value="1800000"/> <property name="deleteInvalidSessions" value="true"/> <property name="sessionValidationSchedulerEnabled" value="true"/> <property name="sessionValidationScheduler" ref="sessionValidationScheduler"/> <property name="sessionDAO" ref="sessionDAO"/> <property name="sessionIdCookieEnabled" value="true"/> <property name="sessionIdCookie" ref="sessionIdCookie"/> </bean> <!-- 安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="userRealm"/> <property name="sessionManager" ref="sessionManager"/> <property name="cacheManager" ref="cacheManager"/> </bean>

1、sessionIdCookie是用于生產Session ID Cookie的模板; 2、會話管理器使用用于web環境的DefaultWebSessionManager; 3、安全管理器使用用于web環境的DefaultWebSecurityManager。

spring-shiro-web.xml<!-- 基于Form表單的身份驗證過濾器 --> <bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter"> <property name="usernameParam" value="username"/> <property name="passwordParam" value="password"/> <property name="loginUrl" value="/login.jsp"/> </bean> <!-- Shiro的Web過濾器 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="loginUrl" value="/login.jsp"/> <property name="unauthorizedUrl" value="/unauthorized.jsp"/> <property name="filters"> <util:map> <entry key="authc" value-ref="formAuthenticationFilter"/> </util:map> </property> <property name="filterChainDefinitions"> <value> /index.jsp = anon /unauthorized.jsp = anon /login.jsp = authc /logout = logout /** = user </value> </property> </bean>

1、formAuthenticationFilter為基于Form表單的身份驗證過濾器;此處可以再添加自己的Filter bean定義; 2、shiroFilter:此處使用ShiroFilterFactoryBean來創建ShiroFilter過濾器;filters屬性用于定義自己的過濾器,即ini配置中的[filters]部分;filterChainDefinitions用于聲明url和filter的關系,即ini配置中的[urls]部分。

web.xml<context-param> <param-name>contextConfigLocation</param-name> <param-value> classpath:spring-beans.xml, classpath:spring-shiro-web.xml </param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <filter> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> <init-param> <param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

Shiro權限注解

<aop:config proxy-target-class="true"></aop:config> <bean class=" org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean>

如上配置用于開啟Shiro Spring AOP權限注解的支持;<aop:config proxy-target-class="true">表示代理類。

接著就可以在相應的控制器(AnnotationController)中使用如下方式進行注解:

@RequiresRoles("admin") @RequestMapping("/hello2") public String hello2() { return "success"; }

訪問hello2方法的前提是當前用戶有admin角色。

當驗證失敗,其會拋出UnauthorizedException異常,此時可以使用Spring的ExceptionHandler(DefaultExceptionHandler)來進行攔截處理:

@ExceptionHandler({UnauthorizedException.class}) @ResponseStatus(HttpStatus.UNAUTHORIZED) public ModelAndView processUnauthenticatedException(NativeWebRequest request, UnauthorizedException e) { ModelAndView mv = new ModelAndView(); mv.addObject("exception", e); mv.setViewName("unauthorized"); return mv; }

資源

跟我學 Shiro 目錄貼


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 美国av免费看 | 91国内精品久久久久免费影院 | 久久精品在线免费观看 | 成人午夜一区 | 欧美 日韩 中文 | 国产精品久久久久久久久久东京 | 久久亚洲精品国产一区 | 国产精品99久久久久久久 | av在线一区二区三区四区 | 黄色免费大片 | 中文日韩字幕 | 性少妇videosexfreexx入片 | 精品免费国产一区二区三区 | 欧美成人精品一区 | 国产精品久久久久久久久岛 | 91久久国产综合久久91猫猫 | 哪里可以看免费的av | 毛片在线免费观看完整版 | 成年人精品视频 | 黄色网址在线视频 | av在线在线 | 蜜桃视频在线免费播放 | 一级黄色影片在线观看 | 毛片在线免费观看完整版 | 久久久久99999 | 美女视频黄视大全视频免费网址 | 欧美a久久 | 精品国产一区二区三区久久久蜜月 | 国产成人在线播放视频 | 亚洲无线看 | 国产一区二区精品在线观看 | 国产精品一区免费在线观看 | 黑人一区二区三区四区五区 | 欧产日产国产精品99 | 国产一区二区精品在线观看 | 一级电影在线免费观看 | 精品国产96亚洲一区二区三区 | 国产超碰人人做人人爱 | h网站在线观看 | 久久6国产| 久久精品观看 |