1、使用css
1.搭建基礎環境html
(1)導入 Spring 和 Shiro 的 Jar 包java
(2)配置文件web
(3)檢測spring
2.登陸sql
(1)添加登陸頁面數據庫
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <h4> Login Page </h4> <form action="shiro-login" method="post"> <input name="userName" type="text"/> <input name="password" type="password"/> <input type="submit" value="submit"> </form> </body> </html>
(2)對應 Handler 方法express
@RequestMapping("/shiro-login") public String login(String userName, String password) { System.out.println("userName:" + userName + ", password:" + password); Subject currentUser = SecurityUtils.getSubject(); if(!currentUser.isAuthenticated()) { UsernamePasswordToken token = new UsernamePasswordToken(userName, password); token.setRememberMe(true); try { currentUser.login(token); } catch(UnknownAccountException uae) { System.out.println("用戶名不正確!"); } catch(IncorrectCredentialsException ice) { System.out.println("密碼不匹配!"); } catch(LockedAccountException lae) { System.out.println("帳戶被鎖定!"); } catch(AuthenticationException ae) { System.out.println("認證失敗!"); } } return "success"; }
這裏參考的是官方的 demo :shiro-root-1.2.2\samples\quickstart\src\main\java\Quickstart.javaapache
/* * 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. */ import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.config.IniSecurityManagerFactory; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.session.Session; import org.apache.shiro.subject.Subject; import org.apache.shiro.util.Factory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Simple Quickstart application showing how to use Shiro's API. * * @since 0.9 RC2 */ public class Quickstart { private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class); public static void main(String[] args) { // The easiest way to create a Shiro SecurityManager with configured // realms, users, roles and permissions is to use the simple INI config. // We'll do that by using a factory that can ingest a .ini file and // return a SecurityManager instance: // Use the shiro.ini file at the root of the classpath // (file: and url: prefixes load from files and urls respectively): Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); SecurityManager securityManager = factory.getInstance(); // for this simple example quickstart, make the SecurityManager // accessible as a JVM singleton. Most applications wouldn't do this // and instead rely on their container configuration or web.xml for // webapps. That is outside the scope of this simple quickstart, so // we'll just do the bare minimum so you can continue to get a feel // for things. SecurityUtils.setSecurityManager(securityManager); // Now that a simple Shiro environment is set up, let's see what you can do: // get the currently executing user: Subject currentUser = SecurityUtils.getSubject(); // Do some stuff with a Session (no need for a web or EJB container!!!) Session session = currentUser.getSession(); session.setAttribute("someKey", "aValue"); String value = (String) session.getAttribute("someKey"); if (value.equals("aValue")) { log.info("-->Retrieved the correct value! [" + value + "]"); } // let's login the current user so we can check against roles and permissions: if (!currentUser.isAuthenticated()) { UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa"); token.setRememberMe(true); try { currentUser.login(token); } catch (UnknownAccountException uae) { log.info("-->There is no user with username of " + token.getPrincipal()); } catch (IncorrectCredentialsException ice) { log.info("-->Password for account " + token.getPrincipal() + " was incorrect!"); } catch (LockedAccountException lae) { log.info("The account for username " + token.getPrincipal() + " is locked. " + "Please contact your administrator to unlock it."); } // ... catch more exceptions here (maybe custom ones specific to your application? catch (AuthenticationException ae) { //unexpected condition? error? } } //say who they are: //print their identifying principal (in this case, a username): log.info("-->User [" + currentUser.getPrincipal() + "] logged in successfully."); //test a role: if (currentUser.hasRole("schwartz")) { log.info("-->May the Schwartz be with you!"); } else { log.info("Hello, mere mortal."); } //test a typed permission (not instance-level) if (currentUser.isPermitted("lightsaber:weild")) { log.info("-->You may use a lightsaber ring. Use it wisely."); } else { log.info("Sorry, lightsaber rings are for schwartz masters only."); } //a (very powerful) Instance Level permission: if (currentUser.isPermitted("winnebago:drive:eagle5")) { log.info("-->You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'. " + "Here are the keys - have fun!"); } else { log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!"); } //all done - log out! currentUser.logout(); System.exit(0); } }
說明一下:bootstrap
官方 demo 演示的是一個 java 項目,而不是一個 web 項目,不一樣點是:web 項目下,shiro 的大管家是由容器去建立的,而不須要咱們手動去獲取。
(3)檢測可否正常運行,若能,則證實登陸測試成功。
3.認證
(1)實現自定義 Realm 的 認證方法。
@Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("開始認證!"); UsernamePasswordToken upToken = (UsernamePasswordToken) token; String username = upToken.getUsername(); Object credentials = "123456"; SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(username, credentials, this.getName()); return info; }
或
@Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("開始認證!"); UsernamePasswordToken upToken = (UsernamePasswordToken) token; String username = upToken.getUsername(); User user = new User(); user.setId(1000); user.setUserName(username); user.setPassword("123456"); user.getRoleNames().add("admin"); return new SimpleAuthenticationInfo(user, user.getPassword(), this.getName()); }
說明一下:
其中 username 是從頁面獲取到的,而密碼是經過查詢數據庫獲取的。注意標紅加粗的地方。
實現的參考:org.apache.shiro.realm.jdbc.JdbcRealm
(2)測試,此時密碼不爲 "123456"可否登陸。測試認證是否成功。
4.受權
(1)實現自定義 Realm 的受權方法。
@Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("開始受權!"); String username = (String)this.getAvailablePrincipal(principalCollection); System.out.println("userName:" + username); Set<String> roleNames = new HashSet<>(); roleNames.add("admin"); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames); return info; }
或:User 對象已經包含角色信息,不須要再次查詢數據庫。
@Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("開始受權!"); User user = (User) principalCollection.getPrimaryPrincipal(); Set<String> roleNames = user.getRoleNames(); return new SimpleAuthorizationInfo(roleNames); }
實現的參考:org.apache.shiro.realm.jdbc.JdbcRealm
(2)測試,添加對應的頁面,而後在 Shiro 配置文件中配置訪問對應的頁面須要什麼樣的角色才能訪問。
5.認證和受權的資源數據從數據庫中獲取
(1)受保護資源和須要角色權限間的關係存在在 shiro.xml 文件中。
<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="filterChainDefinitions"> <value> /user.jsp = authc /admin.jsp = roles[admin] /** = anon </value> </property> </bean>
(2)要想改成從數據庫中獲取,思路就是:filterChainDefinitions 屬性值能從 Java 文件中獲取。
參看:filterChainDefinitions 屬性的官方使用
public void setFilterChainDefinitions(String definitions) { Ini ini = new Ini(); ini.load(definitions); Section section = ini.getSection("urls"); if(CollectionUtils.isEmpty(section)) { section = ini.getSection(""); } this.setFilterChainDefinitionMap(section); } public void setFilterChainDefinitionMap(Map<String, String> filterChainDefinitionMap) { this.filterChainDefinitionMap = filterChainDefinitionMap; }
實際上放的是一個 Map。那麼來看看具體的 Map 存放的是怎麼的一些數據格式?在標紅的代碼處打個斷點,能夠看到以下內容:
能夠看到, Map 內容的就是在 shiro.xml 經過屬性 filterChainDefinitions 定義的值。
(3)具體操做
/** * @author solverpeng * @create 2016-09-21-18:59 */ public class FilterChainDefinitionMapBuilder { public Map<String, String> getFilterChainDefinitionMap() { Map<String, String> filterChainDefinitionMap = new HashMap<>(); filterChainDefinitionMap.put("/admin.jsp", "roles[admin],authc"); filterChainDefinitionMap.put("/user.jsp", "authc"); filterChainDefinitionMap.put("/**", "anon"); return filterChainDefinitionMap; } }
更改配置:
<bean id="filterChainDefinitionMapBuilder" class="com.nucsoft.shiro.shiro.FilterChainDefinitionMapBuilder"/> <bean id="filterChainDefinitionMap" factory-bean="filterChainDefinitionMapBuilder" factory-method="getFilterChainDefinitionMap"/> <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="filterChainDefinitionMap" ref="filterChainDefinitionMap"/> </bean>
此時,資源信息能夠經過 Java 方法來處理,而此時,這些數據就能夠從數據庫中獲取。
6.鹽值加密
加密指的是對密碼的加密,用戶註冊時,將密碼使用必定的加密方式存放到數據庫中,用戶登陸的時候,一樣以相同的加密方式進行比對。
在什麼地方進行的對比?
注意:不是在自定義認證的時候對比的。在 MyRealm 中
@Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("開始認證!"); UsernamePasswordToken upToken = (UsernamePasswordToken) token; String username = upToken.getUsername(); User user = new User(); user.setId(1000); user.setUserName(username); user.setPassword("42e56621cf3adc9ecc261936188d31d7"); user.getRoleNames().add("admin"); String hashedCredentials = user.getPassword(); ByteSource credentialsSalt = ByteSource.Util.bytes("abcd"); String realmName = getName(); SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, hashedCredentials, credentialsSalt, realmName); return info; }
的這個方法的做用,只是根據傳入的 Token 獲取到 username,從而到數據庫中查詢對應的 User 對象,以及鹽值信息,而後返回封裝這些信息的 SimpleAuthenticationInfo 的對象。
密碼的對比是在這以後對比的,來看返回後,返回到了 org.apache.shiro.realm.AuthenticatingRealm#getAuthenticationInfo 這個方法
public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { AuthenticationInfo info = getCachedAuthenticationInfo(token); if (info == null) { //otherwise not cached, perform the lookup: info = doGetAuthenticationInfo(token); log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info); if (token != null && info != null) { cacheAuthenticationInfoIfPossible(token, info); } } else { log.debug("Using cached authentication info [{}] to perform credentials matching.", info); } if (info != null) { assertCredentialsMatch(token, info); } else { log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}]. Returning null.", token); } return info; }
其中第一處標紅的地方是調用咱們自定義 Realm 的 doGetAuthenticationInfo() 方法以及返回值。
第二處標紅的地方表示若是能夠緩存的話,就把此登陸帳戶進行緩存。
第三處纔是真正進行比較的地方,看看方法名和參數,見名知意。 token 爲表單提交過來的用戶信息,而 info 是咱們作認證時從數據庫查詢獲取到的。
詳細來看:org.apache.shiro.realm.AuthenticatingRealm#assertCredentialsMatch
protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException { CredentialsMatcher cm = getCredentialsMatcher(); if (cm != null) { if (!cm.doCredentialsMatch(token, info)) { //not successful - throw an exception to indicate this: String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials."; throw new IncorrectCredentialsException(msg); } } else { throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " + "credentials during authentication. If you do not wish for credentials to be examined, you " + "can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance."); } }
兩個核心的地方:
第一處標紅是:獲取憑證的匹配器(密碼的匹配器),來看這個接口中封裝了一下什麼信息。
public interface CredentialsMatcher { boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info); }
只有一個 doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) 的方法。
來看它的體系:
看到了 Md5CredentialsMatcher, 而後發現它是一個過時的類,HashedCredentialsMatcher 做爲對它的一個替代,須要 setHashAlgorithmName() 來指定加密方式。
這裏直接對 HashedCredentialsMatcher 給出說明:
(1)加密方式:setHashAlgorithmName(String hashAlgorithmName)
(2)加密次數:setHashIterations(int hashIterations)
說了這麼多,如何由咱們本身指定 CreaentialsMatcher ?
我自定義的 MyRealm 是 AuthenticatingRealm 它的子類,因此想法是,在 AuthenticatingRealm 調用 getCredentialsMatcher() 以前,就將 CreaentialsMatcher set到 Realm 中。
來看具體操做:
在 MyRealm 中定義一個初始化方法:
public void initCredentialsMatcher() { HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); credentialsMatcher.setHashAlgorithmName("MD5"); credentialsMatcher.setHashIterations(1000); setCredentialsMatcher(credentialsMatcher); }
指定了加密方式,而後加密次數,而後設置到了 Realm 中。
爲了保證在在 AuthenticatingRealm 調用 getCredentialsMatcher() 以前,就將 CreaentialsMatcher set到 Realm 中,在容器初始化的時候就設置。
applicationContext-shiro.xml 的配置:
<bean id="realm" class="com.nucsoft.shiro.shiro.MyRealm" init-method="initCredentialsMatcher"/>
第二處標紅進行的真正的密碼匹配:cm.doCredentialsMatch(token, info)
詳細來看:org.apache.shiro.authc.credential.HashedCredentialsMatcher#doCredentialsMatch
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { Object tokenHashedCredentials = hashProvidedCredentials(token, info); Object accountCredentials = getCredentials(info); return equals(tokenHashedCredentials, accountCredentials); }
其中 tokenHashedCredentials 是從表單提交過來的密碼經一樣的加密方式處理後的憑證;accountCredentials 是從數據庫中取出來的憑證信息。
關注點:是怎麼對錶單密碼進行加密處理的
詳細來看:
org.apache.shiro.authc.credential.HashedCredentialsMatcher#hashProvidedCredentials(org.apache.shiro.authc.AuthenticationToken, org.apache.shiro.authc.AuthenticationInfo)
protected Object hashProvidedCredentials(AuthenticationToken token, AuthenticationInfo info) { Object salt = null; if (info instanceof SaltedAuthenticationInfo) { salt = ((SaltedAuthenticationInfo) info).getCredentialsSalt(); } else { //retain 1.0 backwards compatibility: if (isHashSalted()) { salt = getSalt(token); } } return hashProvidedCredentials(token.getCredentials(), salt, getHashIterations()); }
org.apache.shiro.authc.credential.HashedCredentialsMatcher#hashProvidedCredentials(java.lang.Object, java.lang.Object, int)
protected Hash hashProvidedCredentials(Object credentials, Object salt, int hashIterations) { String hashAlgorithmName = assertHashAlgorithmName(); return new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations); }
hashAlgorithmName:這個就是在憑證匹配器中定義的加密方式。
核心:進行加密的就是這個:
new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations)
hashAlgorithmName: 加密方式
credentials:表單提交的密碼
salt:鹽值
hashIterations:加密次數
用戶註冊的時候,向數據庫存入密碼的時候,可使用此種方式對密碼進行加密。
來看一個測試:
public static void main(String[] args) { String hashAlgorithmName = "MD5"; Object credentials = "123456"; ByteSource salt = ByteSource.Util.bytes("abcd"); int hashIterations = 1000; SimpleHash simpleHash = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations); System.out.println(simpleHash); }
說了這麼多,尚未說 自定義認證方法的鹽值是如何添加的:
com.nucsoft.shiro.shiro.MyRealm#doGetAuthenticationInfo
來看:
@Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("開始認證!"); UsernamePasswordToken upToken = (UsernamePasswordToken) token; String username = upToken.getUsername(); User user = new User(); user.setId(1000); user.setUserName(username); user.setPassword("42e56621cf3adc9ecc261936188d31d7"); user.getRoleNames().add("admin"); String hashedCredentials = user.getPassword(); ByteSource credentialsSalt = ByteSource.Util.bytes("abcd"); String realmName = getName(); SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, hashedCredentials, credentialsSalt, realmName); return info; }
標紅的地方就是加鹽值後的處理方式。
在註冊的時候,隨機生成鹽值,同用戶信息存入數據庫中。
7.關於細粒度的基於註解的受權和基於標籤庫的受權,本篇文章不進行說明。
2、總結
介紹了 Spring 環境下 shiro 的使用,包括環境的搭建,以及是如何配置的,自定義 Realm 能夠完成自定義認證和自定義受權,也能夠完成憑證匹配器的設置。
以及具體是怎麼完成自定義認證和受權的,也將受保護的資源與訪問的權限從xml文件中轉到了 java 類中,爲後續從數據庫中讀取提供了方便。
也介紹了加密的方式:加密類型,加密次數,加密鹽值,以及具體是如何加密的。並無講明在真實項目中是如何使用的,之後有機會寫文章來講明。
3、詳細配置文件
1.web.xml
(1)shiro 官方 demo 中的 web.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- ~ 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. --> <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5"> <!-- ================================================================== Context parameters ================================================================== --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext.xml</param-value> </context-param> <!-- - Key of the system property that should specify the root directory of this - web app. Applied by WebAppRootListener or Log4jConfigListener. --> <context-param> <param-name>webAppRootKey</param-name> <param-value>spring-sample.webapp.root</param-value> </context-param> <!-- ================================================================== Servlet listeners ================================================================== --> <listener> <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class> </listener> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- ================================================================== Filters ================================================================== --> <!-- Shiro Filter is defined in the spring application context: --> <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> <!-- ================================================================== Servlets ================================================================== --> <servlet> <servlet-name>sample</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>sample</servlet-name> <url-pattern>/s/*</url-pattern> </servlet-mapping> <servlet> <servlet-name>remoting</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>remoting</servlet-name> <url-pattern>/remoting/*</url-pattern> </servlet-mapping> <!-- ================================================================== Welcome file list ================================================================== --> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
(2)真實的環境的下 web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext*.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Shiro Filter is defined in the spring application context: --> <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> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app>
2.spring-shiro.xml
(1)官方 demo 中的 applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?> <!-- ~ 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. --> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"> <!-- Sample RDBMS data source that would exist in any application - not Shiro related. --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="org.hsqldb.jdbcDriver"/> <property name="url" value="jdbc:hsqldb:mem:shiro-spring"/> <property name="username" value="sa"/> </bean> <!-- Populates the sample database with sample users and roles. --> <bean id="bootstrapDataPopulator" class="org.apache.shiro.samples.spring.BootstrapDataPopulator"> <property name="dataSource" ref="dataSource"/> </bean> <!-- Simulated business-tier "Manager", not Shiro related, just an example --> <bean id="sampleManager" class="org.apache.shiro.samples.spring.DefaultSampleManager"/> <!-- ========================================================= Shiro Core Components - Not Spring Specific ========================================================= --> <!-- Shiro's main business-tier object for web-enabled applications (use DefaultSecurityManager instead when there is no web environment)--> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="cacheManager" ref="cacheManager"/> <!-- Single realm app. If you have multiple realms, use the 'realms' property instead. --> <property name="sessionMode" value="native"/> <property name="realm" ref="jdbcRealm"/> </bean> <!-- Let's use some enterprise caching support for better performance. You can replace this with any enterprise caching framework implementation that you like (Terracotta+Ehcache, Coherence, GigaSpaces, etc --> <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <!-- Set a net.sf.ehcache.CacheManager instance here if you already have one. If not, a new one will be creaed with a default config: <property name="cacheManager" ref="ehCacheManager"/> --> <!-- If you don't have a pre-built net.sf.ehcache.CacheManager instance to inject, but you want a specific Ehcache configuration to be used, specify that here. If you don't, a default will be used.: <property name="cacheManagerConfigFile" value="classpath:some/path/to/ehcache.xml"/> --> </bean> <!-- Used by the SecurityManager to access security data (users, roles, etc). Many other realm implementations can be used too (PropertiesRealm, LdapRealm, etc. --> <bean id="jdbcRealm" class="org.apache.shiro.samples.spring.realm.SaltAwareJdbcRealm"> <property name="name" value="jdbcRealm"/> <property name="dataSource" ref="dataSource"/> <property name="credentialsMatcher"> <!-- The 'bootstrapDataPopulator' Sha256 hashes the password (using the username as the salt) then base64 encodes it: --> <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <property name="hashAlgorithmName" value="SHA-256"/> <!-- true means hex encoded, false means base64 encoded --> <property name="storedCredentialsHexEncoded" value="false"/> </bean> </property> </bean> <!-- ========================================================= Shiro Spring-specific integration ========================================================= --> <!-- Post processor that automatically invokes init() and destroy() methods for Spring-configured Shiro objects so you don't have to 1) specify an init-method and destroy-method attributes for every bean definition and 2) even know which Shiro objects require these methods to be called. --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <!-- Enable Shiro Annotations for Spring-configured beans. Only run after the lifecycleBeanProcessor has run: --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean> <!-- Secure Spring remoting: Ensure any Spring Remoting method invocations can be associated with a Subject for security checks. --> <bean id="secureRemoteInvocationExecutor" class="org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor"> <property name="securityManager" ref="securityManager"/> </bean> <!-- Define the Shiro Filter here (as a FactoryBean) instead of directly in web.xml - web.xml uses the DelegatingFilterProxy to access this bean. This allows us to wire things with more control as well utilize nice Spring things such as PropertiesPlaceholderConfigurer and abstract beans or anything else we might need: --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="loginUrl" value="/s/login"/> <property name="successUrl" value="/s/index"/> <property name="unauthorizedUrl" value="/s/unauthorized"/> <!-- The 'filters' property is not necessary since any declared javax.servlet.Filter bean defined will be automatically acquired and available via its beanName in chain definitions, but you can perform overrides or parent/child consolidated configuration here if you like: --> <!-- <property name="filters"> <util:map> <entry key="aName" value-ref="someFilterPojo"/> </util:map> </property> --> <property name="filterChainDefinitions"> <value> /favicon.ico = anon /logo.png = anon /shiro.css = anon /s/login = anon # allow WebStart to pull the jars for the swing app: /*.jar = anon # everything else requires authentication: /** = authc </value> </property> </bean> </beans>
(2)實驗中的 applicationContext-shiro.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="cacheManager" ref="cacheManager"/> <property name="realm" ref="realm"/> </bean> <bean id="realm" class="com.nucsoft.shiro.shiro.MyRealm"/> <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/> </bean> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean> <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="filterChainDefinitions"> <value> /user.jsp = authc /admin.jsp = roles[admin] /** = anon </value> </property> </bean> </beans>
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="cacheManager" ref="cacheManager"/> <property name="realm" ref="realm"/> </bean> <bean id="realm" class="com.nucsoft.shiro.shiro.MyRealm"/> <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/> </bean> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean> <bean id="filterChainDefinitionMapBuilder" class="com.nucsoft.shiro.shiro.FilterChainDefinitionMapBuilder"/> <bean id="filterChainDefinitionMap" factory-bean="filterChainDefinitionMapBuilder" factory-method="getFilterChainDefinitionMap"/> <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="filterChainDefinitionMap" ref="filterChainDefinitionMap"/> </bean> </beans>
3.springmvc.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:component-scan base-package="com.nucsoft.shiro.handler"/> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/"/> <property name="suffix" value=".jsp"/> </bean> <mvc:annotation-driven/> <mvc:default-servlet-handler/> </beans>
4、shiro 中默認的過濾器名稱以及使用
1.anno,匿名就能夠訪問,e:/admins/** = anno
2.authc,認證後能夠訪問,e:/user/** = authc
3.authcBasic,沒有參數,表示須要經過 httpBasic 驗證,若是不經過,跳轉到登陸頁面。e:/user/** = authcBasic
4.logout
5.noSessionCreation,阻止在請求期間建立新的會話,以保證無狀態的體驗。
6.perms,e1:/admins/**=perms[user:add:*] ,e2:/admins/users/**=perms["user:add:*,user:modify:*"]
7.post,指定請求訪問的端口,e:/admins/**=port[8080]
8.rest,根據請求的方法,e:/admins/user/**=perms[user.method],其中mothod 爲 post,get,delete 等。
9.roles,角色過濾器,判斷當前用戶是否擁有指定的角色。
10.ssl,沒有參數,表示協議爲 https。
11.user,表示必須存在用戶。