1. 程式人生 > >idea ssm整合shiro shiro的基本用法

idea ssm整合shiro shiro的基本用法

http://www.jianshu.com/p/6786ddf54582
參照此篇文章進行設定,此篇文章介紹了一個基本的shiro進行身份驗證和許可權驗證的方法,實測可用,寫這篇部落格的目的為了複習自己配置shiro的基本流程
首先我們要有一個ssm maven專案,搭建ssm專案參照之前的部落格
1.加入pom.xml
http://mvnrepository.com/ maven倉庫的地址

 <dependency>
       <dependency>
        <groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId> <version>1.2.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.2.2</version>
</dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.4.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-ehcache -->
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.2.3</version> </dependency>

2.shiro配置檔案配置

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"
>
    <!-- 繼承自AuthorizingRealm的自定義Realm,即指定Shiro驗證使用者登入的類為自定義的ShiroDbRealm.java -->
    <bean id="myRealm" class="com.pack.shiro.ShiroManager"/>

    <!-- Shiro預設會使用Servlet容器的Session,可通過sessionMode屬性來指定使用Shiro原生Session -->
    <!-- 即<property name="sessionMode" value="native"/>,詳細說明見官方文件 -->
    <!-- 這裡主要是設定自定義的單Realm應用,若有多個Realm,可使用'realms'屬性代替 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="myRealm"/>
    </bean>
    <!-- Shiro主過濾器本身功能十分強大,其強大之處就在於它支援任何基於URL路徑表示式的、自定義的過濾器的執行 -->
    <!-- Web應用中,Shiro可控制的Web請求必須經過Shiro主過濾器的攔截,Shiro對基於Spring的Web應用提供了完美的支援 -->
    <bean id="shiroFilter" name="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- Shiro的核心安全介面,這個屬性是必須的 -->
        <property name="securityManager" ref="securityManager"/>
        <!-- 要求登入時的連結(可根據專案的URL進行替換),非必須的屬性,預設會自動尋找Web工程根目錄下的"/login.jsp"頁面 -->
        <property name="loginUrl" value="/"/>
        <!-- 登入成功後要跳轉的連線(本例中此屬性用不到,因為登入成功後的處理邏輯在LoginController裡硬編碼為main.jsp了) -->
        <!-- <property name="successUrl" value="/system/main"/> -->
        <!-- 使用者訪問未對其授權的資源時,所顯示的連線 -->
        <!-- 若想更明顯的測試此屬性可以修改它的值,如unauthor.jsp,然後用[玄玉]登入後訪問/admin/listUser.jsp就看見瀏覽器會顯示unauthor.jsp -->
        <property name="unauthorizedUrl" value="/"/>
        <!-- Shiro連線約束配置,即過濾鏈的定義 -->
        <!-- 此處可配合我的這篇文章來理解各個過濾連的作用http://blog.csdn.net/jadyer/article/details/12172839 -->
        <!-- 下面value值的第一個'/'代表的路徑是相對於HttpServletRequest.getContextPath()的值來的 -->
        <!-- anon:它對應的過濾器裡面是空的,什麼都沒做,這裡.do和.jsp後面的*表示引數,比方說login.jsp?main這種 -->
        <!-- authc:該過濾器下的頁面必須驗證後才能訪問,它是Shiro內建的一個攔截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter -->
        <property name="filterChainDefinitions">
            <value>
                <!-- anon表示此地址不需要任何許可權即可訪問 -->
                /static/**=anon
                <!-- perms[user:query]表示訪問此連線需要許可權為user:query的使用者 -->
                <!--/user=perms[user:query]-->
                <!-- roles[manager]表示訪問此連線需要使用者的角色為manager -->
                <!--/user/add=roles[manager]-->
                <!--所有的請求(除去配置的靜態資源請求或請求地址為anon的請求)都要通過登入驗證,如果未登入則跳到/login-->
                /** = authc
            </value>
        </property>
    </bean>

    <!-- 保證實現了Shiro內部lifecycle函式的bean執行 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
    <!-- 開啟Shiro的註解(如@RequiresRoles,@RequiresPermissions),需藉助SpringAOP掃描使用Shiro註解的類,並在必要時進行安全邏輯驗證 -->
    <!-- 配置以下兩個bean即可實現此功能 -->
    <!-- Enable Shiro Annotations for Spring-configured beans. Only run after the lifecycleBeanProcessor has run -->
    <bean class="org.apache.shiro.spring.security.intrceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>
</beans>

3.在mybatis配置檔案中進行配置

<?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:p="http://www.springframework.org/schema/p"  
    xmlns:context="http://www.springframework.org/schema/context"  
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans    
                        http://www.springframework.org/schema/beans/spring-beans-3.1.xsd    
                        http://www.springframework.org/schema/context    
                        http://www.springframework.org/schema/context/spring-context-3.1.xsd    
                        http://www.springframework.org/schema/tx 
                        http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
                       ">
    <!-- 自動掃描 -->
    <context:component-scan base-package="com.pack"><!-- base-package 如果多個,用“,”分隔 -->
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    <!-- 引入配置檔案 -->  
    <bean id="propertyConfigurer"  
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
        <property name="location" value="classpath:jdbc.properties" />  
    </bean>  

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"  
        destroy-method="close">  
        <property name="driverClassName" value="${driver}" />  
        <property name="url" value="${url}" />  
        <property name="username" value="${username}" />  
        <property name="password" value="${password}" />  
    </bean>  

    <!-- spring和MyBatis完美整合,不需要mybatis的配置對映檔案 -->  
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
        <property name="dataSource" ref="dataSource" />  
        <!-- 自動掃描mapping.xml檔案 -->  
        <property name="mapperLocations" value="classpath:mapping/*.xml"></property>
    </bean>  

    <!-- DAO介面所在包名,Spring會自動查詢其下的類 -->  
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">  
        <property name="basePackage" value="com.pack.dao" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>  
    </bean>  

    <!-- (事務管理)transaction manager, use JtaTransactionManager for global tx -->  
    <bean id="transactionManager"  
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">  
        <property name="dataSource" ref="dataSource" />  
    </bean>  
   <tx:annotation-driven transaction-manager="transactionManager"  proxy-target-class="true"/>

    <!-- 配置自定義Realm -->

    <bean id="myRealm" class="com.pack.shiro.ShiroManager"/>

    <!-- 安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="myRealm"/>
    </bean>
    <!-- Shiro過濾器 核心-->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- Shiro的核心安全介面,這個屬性是必須的 -->
        <property name="securityManager" ref="securityManager"/>
        <!-- 身份認證失敗,則跳轉到登入頁面的配置 -->
        <property name="loginUrl" value="/login"/>
        <!-- 許可權認證失敗,則跳轉到指定頁面 -->
        <property name="unauthorizedUrl" value="/angular.jsp"/>
        <!-- Shiro連線約束配置,即過濾鏈的定義 -->
        <property name="filterChainDefinitions">
            <value>
                <!--anon 表示匿名訪問,不需要認證以及授權-->
                /loginAdmin=anon
                <!--authc表示需要認證 沒有進行身份認證是不能進行訪問的-->
                /admin*=authc
                /student=roles[teacher]
                /teacher=perms["user:create"]
            </value>
        </property>
    </bean>

    <!-- 保證實現了Shiro內部lifecycle函式的bean執行 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    <!-- 開啟Shiro註解 -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor">
     <property name="proxyTargetClass" value="true"/>
    </bean>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>
    <!-- remenberMe配置 -->
    <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
        <constructor-arg value="rememberMe" />
        <property name="httpOnly" value="true" />
        <!-- 預設記住7天(單位:秒) -->
        <property name="maxAge" value="604800" />
    </bean>
    <!-- rememberMe管理器 -->
    <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
        <property name="cipherKey" value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}" />
        <property name="cookie" ref="rememberMeCookie" />
    </bean>
</beans>  

4.web.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
  <display-name>Archetype Created Web Application</display-name>
  <!-- Spring和mybatis的配置檔案 -->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring-mybatis.xml</param-value>
  </context-param>
  <!-- 編碼過濾器 -->
  <filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <async-supported>true</async-supported>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

  <!-- shiro過濾器定義 -->
  <filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <init-param>
      <!-- 該值預設為false,表示生命週期由SpringApplicationContext管理,設定為true則表示由ServletContainer管理 -->
      <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>

  <!-- Spring監聽器 -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <!-- 防止Spring記憶體溢位監聽器 -->
  <listener>
    <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
  </listener>

  <!-- Spring MVC servlet -->
  <servlet>
    <servlet-name>SpringMVC</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
    <async-supported>true</async-supported>
  </servlet>
  <servlet-mapping>
    <servlet-name>SpringMVC</servlet-name>
    <!-- 此處可以可以配置成*.do,對應struts的字尾習慣 -->
    <url-pattern>/</url-pattern>
  </servlet-mapping>
  <context-param>
    <param-name>log4jConfigLocation</param-name>
    <param-value>classpath:log4j.properties</param-value>
  </context-param>
  <session-config>
    <session-timeout>15</session-timeout>
  </session-config>
  <listener>
    <listener-class>org.springframework.web.util.Log4jConfigListener</listener-class>
  </listener>
</web-app>

5.spring-mvc配置

<?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-4.0.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-4.0.xsd
                        http://www.springframework.org/schema/mvc
                        http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
                            "
>
    <!-- Spring MVC所掃描的路徑 -->
    <context:component-scan base-package="com.pack" use-default-filters="false"><!-- base-package 如果多個,用“,”分隔 -->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!--避免IE執行AJAX時,返回JSON出現下載檔案 -->
    <bean id="mappingJacksonHttpMessageConverter"  
        class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">  
        <property name="supportedMediaTypes">  
            <list>  
                <value>text/html;charset=UTF-8</value>  
            </list>  
        </property>  
    </bean>

    <!--<mvc:interceptors>-->
            <!--<mvc:interceptor>-->
                <!--<mvc:mapping path="/**"/>-->
                <!--<mvc:exclude-mapping path="/user/loginsc"/>-->
                <!--<mvc:exclude-mapping path="/user/logout"/>-->
                <!--<mvc:exclude-mapping path="/styles/**"/>-->
                <!--<mvc:exclude-mapping path="/scripts/**"/>-->
                <!--<mvc:exclude-mapping path="/images/**"/>-->
                <!--<bean id="loginInterceptor" class="com.you.interceptor.LoginInterceptor"/>-->
            <!--</mvc:interceptor>-->
    <!--</mvc:interceptors>-->
    <!-- 定義無Controller的path<->view直接對映 -->
    <!--<mvc:view-controller path="/" view-name="redirect:/user/first"/>-->

   <mvc:annotation-driven>
       <mvc:message-converters register-defaults="true">
           <bean class="org.springframework.http.converter.StringHttpMessageConverter">
             <property name="supportedMediaTypes" value = "text/plain;charset=UTF-8" />
           </bean>
       </mvc:message-converters>
      </mvc:annotation-driven>

    <!--靜態資源對映-->
    <mvc:resources mapping="/static/**" location="/static/" />

    <!-- 啟動SpringMVC的註解功能,完成請求和註解POJO的對映 -->
    <bean  
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">  
        <property name="messageConverters">  
            <list>  
                <ref bean="mappingJacksonHttpMessageConverter" /> <!-- JSON轉換器 -->  
            </list>  
        </property>  
    </bean>  
    <!-- 定義跳轉的檔案的前後綴 ,檢視模式配置-->  
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
        <!-- 這裡的配置我的理解是自動給後面action的方法return的字串加上字首和字尾,變成一個 可用的url地址 -->  
        <property name="prefix" value="/WEB-INF/jsp/" />  
        <property name="suffix" value=".jsp" />
    </bean>

    <!-- 配置檔案上傳,如果沒有使用檔案上傳可以不用配置,當然如果不配,那麼配置檔案中也不必引入上傳元件包 -->  
    <bean id="multipartResolver"    
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">    
        <!-- 預設編碼 -->  
        <property name="defaultEncoding" value="utf-8" />    
        <!-- 檔案大小最大值 -->  
        <property name="maxUploadSize" value="10485760000" />    
        <!-- 記憶體中的最大值 -->  
        <property name="maxInMemorySize" value="40960" />    
    </bean>

<!--此配置一定要在spingmvc的配置檔案中進行配置-->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
        <property name="proxyTargetClass" value="true" />
    </bean>

    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                <prop key="org.apache.shiro.authz.UnauthorizedException">error/403</prop>
                <prop key="java.lang.Throwable">error/500</prop>
            </props>
        </property>
    </bean>

</beans>

6.建立登入頁面
這裡使用了bootstrap以及一個生成svg影象的外掛trianglify,以及彈出框的layer

<%@ page language="java" contentType="text/html; charset=utf-8"
         pageEncoding="utf-8" import="java.util.*"%>
<%@ include file="/WEB-INF/include/taglib.jsp"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <base href="<%=request.getContextPath()%>/" />
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>登入</title>
    <%@ include file="/WEB-INF/include/header.jsp"%>
    <style></style>
</head>
<body>
<div class="container">

    <form role="form" class="col-md-4 center-block" style="margin:120px auto 0 auto;float:none">
        <div class="form-group">
            <label for="name">使用者名稱</label>
            <input type="text" class="form-control" id="name" placeholder="Enter userName" style="padding:20px;">
        </div>
        <div class="form-group">
            <label for="password">密碼</label>
            <input type="password" class="form-control" id="password" placeholder="Password" style="padding:20px;">
        </div>
        <div class="checkbox">
            <label>
                <input type="checkbox" id="che"> 記住密碼
            </label>
        </div>
        <div class="col-md-12" style="padding:0px;">
            <button type="button" class="btn btn-default btn-block" id="sub" style="padding:10px;">Sign in</button>
        </div>
        <div id="wordsShow" style="padding-top:20px;text-align: center;"> </div>
    </form>
</div>
</body>
<script type="text/javascript">
    var h = window.innerHeight, w = window.innerWidth;
    // set up the base pattern
    var pattern = Trianglify({
        height: h,
        width: w,
        cell_size: 30 + Math.random() * 50});
    // png
    var png = document.createElement('img');
    $("body")[0].background=pattern.png();

    $("#sub").click(function(){
        var name = $("#name").val();
        var password = $("#password").val();
        $.get("/user/login",{name:name,password:password},function (text) {
                if(text==="2"){
                    layer.alert('使用者名稱或密碼錯誤', {
                        skin: 'layui-layer-lan'
                        ,closeBtn: 0
                        ,anim: 4 //動畫型別
                    });
                }else{
                    window.location.href="/user/tree";
                }
        });
    })
    var msgArr = ["有事做有所期待,日子就是幸福的。",
        "生活如此難,要怎麼過?一笑而過。",
        "碧波盪漾一抹香,茶不醉人人自醉。",
        "只要把心放寬,快樂其實很簡單。",
        "生活不能等待別人來安排,要自己去爭取與奮鬥!",
        "每天都應該是有收穫的,哪怕只是一句話。",
        "只要路是對的,就不怕路遠。",
        "開心了就笑,不開心就過會再笑。",
        "生活的小處,總是藏有大觀。",
        "總有一種期待,是家的味道。",
        "學會在浮躁中思考,你才知道在喧囂中走向哪裡。",
        "萬家燈火中,總有一盞為你點亮。",
        "有時候、寧願像個孩子,不肯看太多的事,聽太多的不是,單純的過一輩子多好!",
        "用心每一天,不忘初心,方能走遠。",
        "即使沒有翅膀,心也要飛翔。",
        "積一時之跬步,臻千里之遙程。",
        "不開心時,記得要讓心情轉個彎。",
        "偷偷擠進的一縷斜陽,送來滿滿的幸福。",
        "只要堅持,事情再小也擋不住巨集大的夢。",
        "優等的心,不必華麗,但必須堅固。",
        "天再高,踮起腳尖就能更接近陽光!",
        "與未知的相遇,七分歡喜三分孤寂。",
        "有事做有所期待,日子就是幸福的。",
        "天時人事日相催,冬至陽生春又來",
        "一串淡然的心情,一份純粹的快樂。",
        "我不要做普通人。"
    ];
    var index = parseInt(Math.random() * (msgArr.length - 1));
    var currentMsg = msgArr[index];
   $("#wordsShow").html(currentMsg);
</script>
</html>

7.資料庫結構,使用者表,許可權表,角色表

CREATE TABLE `user` (
        `id` VARCHAR(64) NOT NULL PRIMARY KEY,
        `name` VARCHAR(20) DEFAULT NULL,
        `password` VARCHAR(20) DEFAULT NULL,
        `role_Id` INT(11) DEFAULT NULL,
        `CREATE_BY` VARCHAR(64) DEFAULT NULL,
        `CREATE_DATE` DATETIME(6) DEFAULT NULL,
        `UPDATE_BY` VARCHAR(64) DEFAULT NULL,
        `UPDATE_DATE` DATETIME(6) DEFAULT NULL,
        `REMARKS` VARCHAR(255) DEFAULT NULL,
        `DEL_FLAG` CHAR(1) NOT NULL,
        KEY `id` (`id`)
        ) ENGINE=INNODB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

CREATE TABLE `permission` (
         id int(11) NOT NULL AUTO_INCREMENT,
        `permission_name` varchar(50) DEFAULT NULL,
        `roleId` int(11) DEFAULT NULL,
        `CREATE_BY` VARCHAR(64) DEFAULT NULL