因爲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;
}
}
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; }
若是解決了你的問題,請勞駕給個推薦,謝謝!