SSM集成shiro 導致Controller沒法自動註冊service

因爲shiro在web.xml中配置屬於過濾器,其中在web.xml中的加載順序爲: <context-param>(上下文) > listener > filter > servlet>interceptor,css

可見shiroFilter是早於SpringMVC的,因此Controller沒法註冊service,同時Realm中註冊的service爲空,我百度的各類方法都試過了仍然很差用。java

最終我把spring整合shiro的配置直接所有拉到了spring.xml(整合mabatis,redis)配置文件的最下面。mysql

若是你們想看能夠參考下面web

spring.xmlredis

<?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"
       xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
            http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.0.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
       default-autowire="byName" default-lazy-init="false">

    <!-- 配置註解處理器 -->
    <context:annotation-config/>

    <!-- 自動註冊service -->
    <context:component-scan base-package="com.smart.service"/>
    <!--掃描redis配置文件-->
    <context:property-placeholder ignore-unresolvable="true" location="classpath:redis.properties"/>

    <!--Spring整合Redis-->
    <!--設置鏈接池-->
    <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <!-- 最大空閒鏈接數 -->
        <property name="maxIdle" value="${redis.maxIdle}"/>
        <!-- 最大鏈接數 -->
        <property name="maxTotal" value="${redis.maxTotal}" />
        <!-- 每次釋放鏈接的最大數目 -->
        <property name="numTestsPerEvictionRun" value="${redis.numTestsPerEvictionRun}" />
        <!-- 釋放鏈接的掃描間隔(毫秒) -->
        <property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}" />
        <!-- 鏈接最小空閒時間 -->
        <property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}" />
        <!-- 獲取鏈接時的最大等待毫秒數,小於零:阻塞不肯定的時間,默認-1 -->
        <property name="maxWaitMillis" value="${redis.maxWaitMillis}" />
        <!-- 在獲取鏈接的時候檢查有效性, 默認false -->
        <property name="testOnBorrow" value="${redis.testOnBorrow}" />
        <property name="testOnReturn" value="${redis.testOnReturn}" />
        <!-- 在空閒時檢查有效性, 默認false -->
        <property name="testWhileIdle" value="${redis.testWhileIdle}" />
        <!-- 鏈接耗盡時是否阻塞, false報異常,ture阻塞直到超時, 默認true -->
        <property name="blockWhenExhausted" value="${redis.blockWhenExhausted}" />
    </bean>

    <!-- jedis客戶端單機版 -->
    <bean id="redisClient" class="redis.clients.jedis.JedisPool">
        <constructor-arg name="host" value="${redis.host}"></constructor-arg>
        <constructor-arg name="port" value="${redis.port}"></constructor-arg>
        <constructor-arg name="password" value="${redis.password}"></constructor-arg>
        <constructor-arg name="poolConfig" ref="poolConfig"></constructor-arg>
        <constructor-arg name="timeout" value="100000"></constructor-arg>
    </bean>
    <bean id="JedisClient" class="com.smart.redis.JedisClientSingle"/>

    <!--Spring整合Mabatis-->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
          destroy-method="close" p:driverClassName="com.mysql.jdbc.Driver"
          p:url="jdbc:mysql://localhost:3306/bookmanager?characterEncoding=utf8"
          p:username="root" p:password="960521" p:maxActive="10" p:maxIdle="10"
          p:validationQuery="SELECT 1"  p:testOnBorrow="true">
    </bean>

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

    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--dataSource屬性指定要用到的鏈接池-->
        <property name="dataSource" ref="dataSource" />
        <!--configLocation屬性指定mybatis的核心配置文件-->
        <property name="configLocation" value="classpath:mybatis.xml" />
        <!-- 全部配置的mapper文件 -->
        <property name="mapperLocations" value="classpath*:mapper/*.xml" />
    </bean>

    <!-- DAO接口所在包名,Spring會自動查找其下的類 -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.smart.dao"/>
    </bean>

    <!-- 開啓註解方式聲明事務 -->
    <tx:annotation-driven transaction-manager="transactionManager" />



<!--這裏開始整合redis--> <!--Spring整合shiro--> <!-- 配置shiro的過濾器工廠類,id- shiroFilter要和咱們在web.xml中配置的過濾器一致 --> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <!-- 調用咱們配置的權限管理器 --> <property name="securityManager" ref="securityManager" /> <!-- 配置咱們的登陸請求地址 --> <property name="loginUrl" value="/login" /> <!-- 配置咱們在登陸頁登陸成功後的跳轉地址,若是你訪問的是非/login地址,則跳到您訪問的地址 --> <property name="successUrl" value="/maSystem" /> <!-- 若是您請求的資源再也不您的權限範圍,則跳轉到/403請求地址 --> <property name="unauthorizedUrl" value="/error" /> <property name="filters"> <util:map> <entry key="logout" value-ref="logoutFilter" /> </util:map> </property> <!-- 權限配置 --> <property name="filterChainDefinitions"> <value> <!-- anon表示此地址不須要任何權限便可訪問 --> /error=anon /meList=anon /maSystem=anon /login=anon /listBook.do=anon /UserType.do=anon /style/**=anon /logout=logout <!--全部的請求(除去配置的靜態資源請求或請求地址爲anon的請求)都要經過登陸驗證,若是未登陸則跳到/login --> /** = authc </value> </property> </bean> <bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter"> <property name="redirectUrl" value="/login" /> </bean> <!-- 憑證匹配器 <bean id="passwordMatcher" class="org.apache.shiro.authc.credential.PasswordMatcher"> <property name="passwordService" ref="passwordService" /> </bean> <bean id="passwordService" class="org.apache.shiro.authc.credential.DefaultPasswordService"> <property name="hashService" ref="hashService"></property> <property name="hashFormat" ref="hashFormat"></property> <property name="hashFormatFactory" ref="hashFormatFactory"></property> </bean> <bean id="hashService" class="org.apache.shiro.crypto.hash.DefaultHashService"></bean> <bean id="hashFormat" class="org.apache.shiro.crypto.hash.format.Shiro1CryptFormat"></bean> <bean id="hashFormatFactory" class="org.apache.shiro.crypto.hash.format.DefaultHashFormatFactory"> </bean>--> <!-- 緩存管理器 使用Ehcache實現 <bean id="shiroEhcacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"> <property name="cacheManagerConfigFile" value="classpath:ehcache-shiro.xml"/> </bean>--> <!-- 會話ID生成器--> <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator" /> <!-- 會話Cookie模板 關閉瀏覽器當即失效--> <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"> <constructor-arg value="sid" /> <property name="httpOnly" value="true" /> <property name="maxAge" value="-1" /> </bean> <!-- 會話DAO--> <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"> <property name="sessionIdGenerator" ref="sessionIdGenerator" /> </bean> <!-- 會話驗證調度器,每30分鐘執行一次驗證 ,設定會話超時及保存--> <bean name="sessionValidationScheduler" class="org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler"> <property name="interval" value="1800000" /> <property name="sessionManager" ref="sessionManager" /> </bean> <!-- 會話管理器--> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <!-- 全局會話超時時間(單位毫秒),默認30分鐘--> <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="cacheManager" ref="cacheManager" /> <property name="sessionManager" ref="sessionManager" /> </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> <!-- 註冊自定義的Realm,並把密碼匹配器注入,使用註解的方式自動註解會沒法正確匹配密碼 --> <bean id="userRealm" class="com.smart.shiro.UserRealm" lazy-init="false"> <!-- <property name="credentialsMatcher" ref="passwordMatcher"/> <property name="cachingEnabled" value="false"/>--> </bean> <bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" /> <!-- Shiro生命週期處理器 --> <!-- 保證明現了Shiro內部lifecycle函數的bean執行 --> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> </beans>

SpringMVC.xmlspring

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc" 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
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context-3.0.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd">

    <!--自動掃描controller-->
    <context:component-scan base-package="com.smart.controller" />
    <!--開啓註解-->
    <mvc:annotation-driven />


    <!--視圖解析-->
    <bean
            class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix">
            <value>/WEB-INF/views/</value>
        </property>
        <property name="suffix">
            <value>.jsp</value>
        </property>
    </bean>

    <bean id="multipartResolver"
          class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <!-- 上傳文件大小上限,單位爲字節(10MB) -->
        <property name="maxUploadSize">
            <value>10485760</value>
        </property>
        <!-- 請求的編碼格式,必須和jSP的pageEncoding屬性一致,以便正確讀取表單的內容,默認爲ISO-8859-1 -->
        <property name="defaultEncoding">
            <value>UTF-8</value>
        </property>
    </bean>

<!--Shiro配置--> <!-- 1.配置lifecycleBeanPostProcessor,能夠在Spring IOC容器中調用shiro的生命週期方法.--> <bean class="org.apache.shiro.spring.LifecycleBeanPostProcessor" id="lifecycleBeanPostProcessor" /> <!-- 2.啓用Spring IOC容器Shiro註解,但必須配置了lifecycleBeanPostProcessor後才能夠使用--> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor" /> <!-- 3.開啓Spring AOC Shiro註解支持--> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"> <property name="securityManager" ref="securityManager"/> </bean> </beans>

而後把這兩個文件在web.xml中加載便可(同整合SSM時同樣,無需改變),而後再添加shiro的過濾器便可sql

<?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" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_4.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_4.xsd"
         id="WebApp_ID" version="2.4">

<!--其中在web.xml中的加載順序爲:  <context-param>(上下文) > listener > filter > servlet>interceptor-->
  <display-name>SSM</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>

  <!--加載配置文件-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:spring.xml</param-value>
  </context-param>

  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <listener>
    <listener-class>org.springframework.web.context.ContextCleanupListener</listener-class>
  </listener>

  <!--字符過濾器-->
  <filter>
    <filter-name>encodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <!--字符過濾器-->
  <filter-mapping>
    <filter-name>encodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>


  <!-- shiro 安全過濾器
     DelegatingFilterProxy做用是自動到spring容器查找名字爲shiroFilter(filter-name)的bean並把全部Filter的操做委託給它-->
  <filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <async-supported>true</async-supported>
    <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-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/style/*</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/public/*</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.js</url-pattern>
  </servlet-mapping>
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>*.css</url-pattern>
  </servlet-mapping>

  <!--Spring MVC 核心控制器DispatcherServlet-->
  <servlet>
    <servlet-name>spring-mvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!--若是springMVC配置文件名字爲spring-mvc-servlet.xml,且和web.xml在同一級目錄下無需配置下面內容,不然須要配置-->
    <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:spring-mvc.xml</param-value>
    </init-param>

    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>spring-mvc</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

</web-app>

既然都寫到這份上了,我就索性把全部代碼都寫一下apache

UserRealm瀏覽器

package com.smart.shiro;

import javax.annotation.Resource;

import com.smart.bean.User;
import com.smart.service.UserService;
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.UnknownAccountException;
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 org.springframework.beans.factory.annotation.Autowired;

public class UserRealm extends AuthorizingRealm {


    @Autowired
    private UserService userService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        String username = (String)principals.getPrimaryPrincipal();
        System.out.println(username);
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        if(userService==null){
                userService = SpringBeanFactoryUtils.getBean("userService");
        }else {
            System.out.println("UserRealm is not NULL");
        }
        authorizationInfo.setRoles(userService.findRoles(username));
        authorizationInfo.setStringPermissions(userService.findPermissions(username));

        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        String username = (String)token.getPrincipal();
        System.out.println(username);
        if(userService==null){
            userService = SpringBeanFactoryUtils.getBean("userService");
        }else {
            System.out.println("UserRealmsss is not NULL");
        }
        System.out.println(username);
        User user = userService.findByGeNumber(username);

        if(user == null) {
            throw new UnknownAccountException();//沒找到賬號
        }

        //交給AuthenticatingRealm使用CredentialsMatcher進行密碼匹配,若是以爲人家的很差能夠自定義實現
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                user.getGeNumber(),//用戶名
                user.getPassword(),
                getName()  //realm name
        );

        return authenticationInfo;
    }

}
View Code

Controllerspring-mvc

@RequestMapping(value = "/UserType.do")
    @ResponseBody
    public Map<String,Object> Login(String geNumber, String password){
        System.out.println(geNumber+","+password);
        Map<String,Object> map = new HashMap<String,Object>();
        //主體,當前狀態爲沒有認證的狀態「未認證」
        Subject subject = SecurityUtils.getSubject();
        // 登陸後存放進shiro token
        UsernamePasswordToken token=new UsernamePasswordToken(geNumber,password);
        //登陸方法(認證是否經過)
        //使用subject調用securityManager,安全管理器調用Realm
        try {
            //利用異常操做
            //須要開始調用到Realm中
            System.out.println("========================================");
            System.out.println("一、進入認證方法");
            subject.login(token);
            System.out.println("登陸完成");
        } catch (Exception e) {
            map.put("tip","error");
            return map;
        }
        map.put("tip","success");
        return map;
    }
View Code

 

若是解決了你的問題,請勞駕給個推薦,謝謝!

相關文章
相關標籤/搜索