shiro權限控制(一):shiro介紹以及整合SSM框架

  shiro安全框架是目前爲止做爲登陸註冊最經常使用的框架,由於它十分的強大簡單,提供了認證、受權、加密和會話管理等功能 。java

  shiro能作什麼?web

       認證:驗證用戶的身份 算法

       受權:對用戶執行訪問控制:判斷用戶是否被容許作某事 spring

       會話管理:在任何環境下使用 Session API,即便沒有 Web 或EJB 容器。 數據庫

       加密:以更簡潔易用的方式使用加密功能,保護或隱藏數據防止被偷窺 express

       Realms:彙集一個或多個用戶安全數據的數據源 apache

       單點登陸(SSO)功能。 安全

       爲沒有關聯到登陸的用戶啓用 "Remember Me「 服務session

  Shiro 的四大核心部分架構

      Authentication(身份驗證):簡稱爲「登陸」,即證實用戶是誰。

      Authorization(受權):訪問控制的過程,即決定是否有權限去訪問受保護的資源。

      Session Management(會話管理):管理用戶特定的會話,即便在非 Web 或 EJB 應用程序。

      Cryptography(加密):經過使用加密算法保持數據安全

  shiro的三個核心組件:     

      Subject :正與系統進行交互的人,或某一個第三方服務。全部 Subject 實例都被綁定到(且這是必須的)一個SecurityManager 上。

      SecurityManager:Shiro 架構的心臟,用來協調內部各安全組件,管理內部組件實例,並經過它來提供安全管理的各類服務。當 Shiro 與一個 Subject 進行交互時,實質上是幕後的 SecurityManager 處理全部繁重的 Subject 安全操做。

      Realms :本質上是一個特定安全的 DAO。當配置 Shiro 時,必須指定至少一個 Realm 用來進行身份驗證和/或受權。Shiro 提供了多種可用的 Realms 來獲取安全相關的數據。如關係數據庫(JDBC),INI 及屬性文件等。能夠定義本身 Realm 實現來表明自定義的數據源。

 

  shiro整合SSM框架:

      1.加入 jar 包:如下jar包自行百度下載

      

      2.配置 web.xml 文件

      在web.xml中加入如下代碼—shiro過濾器。

<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>

 

      3.在 Spring 的配置文件中配置 Shiro

      Springmvc配置文件中:

<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>

      Spring配置文件中導入shiro配置文件:

<!-- 包含shiro的配置文件 -->
          <import resource="classpath:applicationContext-shiro.xml"/>

      新建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="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <!-- 指定 ehcache 的配置文件,下面會給到 -->
        <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/>
    </bean>

    <!-- 配置進行受權和認證的 Realm,要新增一個java類來實現,下面會有,class=包名.類名,init-methood是初始化的方法 -->
    <bean id="myRealm"
        class="shiro.MyRealm"
        init-method="setCredentialMatcher"></bean>

    <!-- 配置 Shiro 的 SecurityManager Bean. -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="cacheManager" ref="cacheManager"/>
        <property name="realm" ref="myRealm"/>
    </bean>
    
    <!-- 配置 Bean 後置處理器: 會自動的調用和 Spring 整合後各個組件的生命週期方法. -->
    <bean id="lifecycleBeanPostProcessor" 
        class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    <!-- 配置 ShiroFilter bean: 該 bean 的 id 必須和 web.xml 文件中配置的 shiro filter 的 name 一致  -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- 裝配 securityManager -->
        <property name="securityManager" ref="securityManager"/>
        <!-- 配置登錄頁面 -->
        <property name="loginUrl" value="/index.jsp"/>
        <!-- 登錄成功後的一面 -->
        <property name="successUrl" value="/shiro-success.jsp"/>
        <property name="unauthorizedUrl" value="/shiro-unauthorized.jsp"/>
        <!-- 具體配置須要攔截哪些 URL, 以及訪問對應的 URL 時使用 Shiro 的什麼 Filter 進行攔截.  -->
        <property name="filterChainDefinitions">
            <value>
                <!-- 配置登出: 使用 logout 過濾器 -->
                /shiro-logout = logout
                /shiro-* = anon
                /user.jsp = roles[user]
                /admin.jsp = roles[admin]
                /** = authc
            </value>
        </property>
    </bean>

</beans>

     導入ehcache-shiro.xml配置文件:

<!--
  ~ 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.
  -->

<!-- EhCache XML configuration file used for Shiro spring sample application -->
<ehcache>

    <!-- Sets the path to the directory where cache .data files are created.

If the path is a Java System Property it is replaced by
its value in the running VM.

The following properties are translated:
user.home - User's home directory
user.dir - User's current working directory
java.io.tmpdir - Default temp file path -->
    <diskStore path="java.io.tmpdir/shiro-spring-sample"/>


    <!--Default Cache configuration. These will applied to caches programmatically created through
    the CacheManager.

    The following attributes are required:

    maxElementsInMemory            - Sets the maximum number of objects that will be created in memory
    eternal                        - Sets whether elements are eternal. If eternal,  timeouts are ignored and the
                                     element is never expired.
    overflowToDisk                 - Sets whether elements can overflow to disk when the in-memory cache
                                     has reached the maxInMemory limit.

    The following attributes are optional:
    timeToIdleSeconds              - Sets the time to idle for an element before it expires.
                                     i.e. The maximum amount of time between accesses before an element expires
                                     Is only used if the element is not eternal.
                                     Optional attribute. A value of 0 means that an Element can idle for infinity.
                                     The default value is 0.
    timeToLiveSeconds              - Sets the time to live for an element before it expires.
                                     i.e. The maximum time between creation time and when an element expires.
                                     Is only used if the element is not eternal.
                                     Optional attribute. A value of 0 means that and Element can live for infinity.
                                     The default value is 0.
    diskPersistent                 - Whether the disk store persists between restarts of the Virtual Machine.
                                     The default value is false.
    diskExpiryThreadIntervalSeconds- The number of seconds between runs of the disk expiry thread. The default value
                                     is 120 seconds.
    memoryStoreEvictionPolicy      - Policy would be enforced upon reaching the maxElementsInMemory limit. Default
                                     policy is Least Recently Used (specified as LRU). Other policies available -
                                     First In First Out (specified as FIFO) and Less Frequently Used
                                     (specified as LFU)
    -->

    <defaultCache
            maxElementsInMemory="10000"
            eternal="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            overflowToDisk="false"
            diskPersistent="false"
            diskExpiryThreadIntervalSeconds="120"
            />

    <!-- We want eternal="true" (with no timeToIdle or timeToLive settings) because Shiro manages session
expirations explicitly.  If we set it to false and then set corresponding timeToIdle and timeToLive properties,
ehcache would evict sessions without Shiro's knowledge, which would cause many problems
(e.g. "My Shiro session timeout is 30 minutes - why isn't a session available after 2 minutes?"
Answer - ehcache expired it due to the timeToIdle property set to 120 seconds.)

diskPersistent=true since we want an enterprise session management feature - ability to use sessions after
even after a JVM restart.  -->
    <cache name="shiro-activeSessionCache"
           maxElementsInMemory="10000"
           eternal="true"
           overflowToDisk="true"
           diskPersistent="true"
           diskExpiryThreadIntervalSeconds="600"/>

    <cache name="org.apache.shiro.realm.SimpleAccountRealm.authorization"
           maxElementsInMemory="100"
           eternal="false"
           timeToLiveSeconds="600"
           overflowToDisk="false"/>

</ehcache>

      到這一步,配置文件都基本準備好了,接下來要寫Realm方法了,新建shiro包,在包下新建MyRealm.java文件繼承AuthorizingRealm

package shiro;

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.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import bean.user;
import dao.userdao;

public class MyRealm extends AuthorizingRealm {
    @Autowired
    private userdao userdao;    
    String pass;

    /**
     * 受權:
     * 
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();        
        Object principal = principalCollection.getPrimaryPrincipal();//獲取登陸的用戶名    
        if("admin".equals(principal)){               //兩個if根據判斷賦予登陸用戶權限
            info.addRole("admin");
        }
        if("user".equals(principal)){
            info.addRole("list");
        }
        
        info.addRole("user");
        
        return info;
    }

    /*
     * 用戶驗證
     * 
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {   
        //1. token 中獲取登陸的 username! 注意不須要獲取password.
        Object principal = token.getPrincipal();
                
        //2. 利用 username 查詢數據庫獲得用戶的信息. 
        user user=userdao.findbyname((String) principal);
        if(user!=null){
            pass=user.getPass();
        }
        String credentials = pass;
        //3.設置鹽值 ,(加密的調料,讓加密出來的東西更具安全性,通常是經過數據庫查詢出來的。 簡單的說,就是把密碼根據特定的東西而進行動態加密,若是別人不知道你的鹽值,就解不出你的密碼)
        String source = "abcdefg";
        ByteSource credentialsSalt = new Md5Hash(source);
   
        
        //當前 Realm 的name
        String realmName = getName();
        //返回值實例化
        SimpleAuthenticationInfo info = 
                new SimpleAuthenticationInfo(principal, credentials, 
                        credentialsSalt, realmName);
        
        return info;
    }

    //init-method 配置. 
    public void setCredentialMatcher(){
        HashedCredentialsMatcher  credentialsMatcher = new HashedCredentialsMatcher();    
        credentialsMatcher.setHashAlgorithmName("MD5");//MD5算法加密
        credentialsMatcher.setHashIterations(1024);//1024次循環加密      
        setCredentialsMatcher(credentialsMatcher);
    }
    
    
    //用來測試的算出密碼password鹽值加密後的結果,下面方法用於新增用戶添加到數據庫操做的,我這裏就直接用main得到,直接數據庫添加了,省時間
    public static void main(String[] args) {
        String saltSource = "abcdef";    
        String hashAlgorithmName = "MD5";
        String credentials = "passwor";
        Object salt = new Md5Hash(saltSource);
        int hashIterations = 1024;            
        Object result = new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
        System.out.println(result);
    }

}

     好了,接下來咱們寫一個簡單的action來經過shiro登陸驗證。

//登陸認證
    @RequestMapping("/shiro-login")
    public String login(@RequestParam("username") String username, 
            @RequestParam("password") String password){
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);        
        try {
            //執行認證操做. 
            subject.login(token);
        }catch (AuthenticationException ae) {
            System.out.println("登錄失敗: " + ae.getMessage());
            return "/index";
        }
        
        return "/shiro-success";
    }

//舒適提示:記得在註冊中密碼存入數據庫前也記得加密哦,提供一個utils方法
//進行shiro加密,返回加密後的結果
public static String md5(String pass){
String saltSource = "blog";    
String hashAlgorithmName = "MD5";
Object salt = new Md5Hash(saltSource);
int hashIterations = 1024;    
Object result = new SimpleHash(hashAlgorithmName, pass, salt, hashIterations);
String password = result.toString();
return password;
}

好了,shiro登陸驗證到這裏完了,這個簡單的實例也應該能讓你們初步瞭解了

相關文章
相關標籤/搜索