Shiro系列文章:
【Shiro】Apache Shiro架構之身份認證(Authentication)
【Shiro】Apache Shiro架構之權限認證(Authorization)
【Shiro】Apache Shiro架構之集成web
【Shiro】Apache Shiro架構之自定義realm
寫在前面:前面陸陸續續對Shiro的使用做了一些總結,如題,這篇博文主要是總結一下如何將Shiro運用到實際項目中,也就是將Shiro整到Spring中進行開發。後來想想既然要整,就索性把SpringMVC和MyBatis也整進去吧,整個比較完整的,也能幫助更多的初學者。所以本文實際是將Shiro整到SSM中(基於maven)。
其實Shiro整合到Spring中並沒有想象的那麼困難,整到Spring中後,我們自定義的realm啊、securityManager啊等等都會交給spring去管理了,包括我們需要指定哪些url需要做什麼樣的驗證,都是交給spring,也就是說,完全可以擺脫原來的那個.ini配置文件了,會覺得非常清爽,非常有邏輯。好了,下面開始整,Shiro部分參考了它的官方文檔:http://shiro.apache.org/spring.html。
1. 整個工程目錄結構
首先看一下整個工程的目錄結構,先在宏觀上對整體有個把握。
2. 配置文件
首先來完成一些配置文件,先從pom.xml開始,我已經用註釋將它們歸歸類了,很清晰。
2.1 pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>demo.shiro</groupId>
<artifactId>ShiroSpring</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>ShiroSpring Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<!-- shiro核心包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.2.5</version>
</dependency>
<!-- 添加shiro web支持 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.5</version>
</dependency>
<!-- 添加shiro spring支持 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.5</version>
</dependency>
<!-- 添加sevlet支持 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
</dependency>
<!-- 添加jsp支持 -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
</dependency>
<!-- 添加jstl支持 -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- 添加log4j日誌 -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<!-- 添加spring支持 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>4.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>4.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>4.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>4.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>4.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>4.3.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.0.RELEASE</version>
</dependency>
<!-- 添加mybatis支持 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<!-- mysql -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<finalName>ShiroSpring</finalName>
</build>
</project>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
2.2 log4j.properties
這個文件,我都是直接從官方拷貝過來的,也貼一下:
log4j.rootLogger=DEBUG, Console
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
log4j.logger.java.sql.ResultSet=INFO
log4j.logger.org.apache=INFO
log4j.logger.java.sql.Connection=DEBUG
log4j.logger.java.sql.Statement=DEBUG
log4j.logger.java.sql.PreparedStatement=DEBUG
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
2.3 web.xml
接下來在web.xml中添加Spring監聽器、Shiro過濾器和SpringMVC支持:
<?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" id="WebApp_ID" version="3.0">
<display-name>ShiroSpring</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- spring監聽器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!-- 添加springmvc支持 -->
<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>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-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>
<!-- 編碼過濾器 -->
<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>
</web-app>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
2.4 applicationContext.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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
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/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!-- 自動掃描 -->
<context:component-scan base-package="demo.service" />
<!-- 配置數據源 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/db_shiro"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!-- 配置mybatis的sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 自動掃描mappers.xml文件 -->
<property name="mapperLocations" value="classpath:demo/mappers/*.xml"></property>
<!-- mybatis配置文件 -->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
</bean>
<!-- DAO接口所在包名,Spring會自動查找其下的類 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="demo.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>
<!-- 自定義Realm -->
<bean id="myRealm" class="demo.realm.MyRealm"/>
<!-- 安全管理器 -->
<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.jsp"/>
<!-- 權限認證失敗,則跳轉到指定頁面 -->
<property name="unauthorizedUrl" value="/unauthorized.jsp"/>
<!-- Shiro連接約束配置,即過濾鏈的定義 -->
<property name="filterChainDefinitions">
<value>
/login=anon
/user/admin*=authc
/user/student*/**=roles[teacher]
/user/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"/>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
<!-- 配置事務通知屬性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<!-- 定義事務傳播屬性 -->
<tx:attributes>
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="edit*" propagation="REQUIRED" />
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="new*" propagation="REQUIRED" />
<tx:method name="set*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="change*" propagation="REQUIRED" />
<tx:method name="check*" propagation="REQUIRED" />
<tx:method name="get*" propagation="REQUIRED" read-only="true" />
<tx:method name="find*" propagation="REQUIRED" read-only="true" />
<tx:method name="load*" propagation="REQUIRED" read-only="true" />
<tx:method name="*" propagation="REQUIRED" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- 配置事務切面 -->
<aop:config>
<aop:pointcut id="serviceOperation"
expression="execution(* demo.service.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceOperation" />
</aop:config>
</beans>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
spring的配置文件中,我主要來說明一下shiro這一部分,因爲其他部分都一樣,掃描bean,配置數據源相關的,配置事務等等。我把上面shiro部分截圖下來了:
從這部分的配置可以看出,其實就是和上一節中在.ini文件中配置的一樣的,只不過現在換成讓spring去管理了,也很好理解,當然這裏自定義的MyRealm還沒寫,因爲MyRealm中需要有關於數據庫的操作,所以下面先把mybatis部分整合好(其實加上MyRealm,shiro部分已經整合完了~)。
3. 整合MyBatis
3.1 全局配置文件
首先配置一下mybatis的全局配置文件mybatis-config.xml,因爲數據源啥的都交給spring管理了,所以全局配置文件就比較清爽了,當然還有一些設置上的東西,就不配置了,這個要看具體實際中使用的時候在配置。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<!-- 別名 -->
<typeAliases>
<package name="demo.entity"/>
</typeAliases>
</configura
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
3.2 配置mapper映射文件
配置一下UserMapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="demo.dao.UserDao">
<!--
<resultMap type="User" id="UserResult">
<result property="id" column="id"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
</resultMap>
-->
<select id="getByUsername" parameterType="String" resultType="User">
select * from t_user where username=#{username}
</select>
<select id="getRoles" parameterType="String" resultType="String">
select r.rolename from t_user u,t_role r where u.role_id=r.id and u.username=#{username}
</select>
<select id="getPermissions" parameterType="String" resultType="String">
select p.permissionname from t_user u,t_role r,t_permission p where u.role_id=r.id and p.role_id=r.id and u.username=#{username}
</select>
</mapper>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
由配置可知,我們指定的是demo.dao.UserDao這個類,掃描mapper類是交給spring管理的,所以mapper接口可以不用和mapper映射文件同名且放到同一目錄下,如果是交給mybatis管理我測試過是需要這麼做的,在我之前mybatis的博文中也有提到這些。接下來就是寫dao接口了(其實就是mapper映射文件對應的mapper接口)。
3.3 mapper接口
public interface UserDao {
public User getByUsername(String username);
public Set<String> getRoles(String username);
public Set<String> getPermissions(String username);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
只需要寫接口即可,不需要寫實現,spring的配置文件中會去掃描mapper,會自動創建一個代理對象來執行相應的方法,要注意的是這個接口中的方法名要和上面mapper映射文件中的id號一樣的,否則是無法映射到具體的statement上面的,會報錯的。
3.4 po類
這裏就寫一個簡單的User類,數據庫中的存儲信息可以參考上一篇博文,跟那邊一樣的。
public class User {
private Integer id;
private String username;
private String password;
//省略get set方法
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
3.5 完成service
順帶着把service層也完善了,這裏我就寫實現類了,接口就不寫了。
@Service("userService")
public class UserServiceImpl implements UserService{
@Resource
private UserDao userDao;
public User getByUsername(String username) {
return userDao.getByUsername(username);
}
public Set<String> getRoles(String username) {
return userDao.getRoles(username);
}
public Set<String> getPermissions(String username) {
return userDao.getPermissions(username);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
在service的實現類中,注入剛剛寫好的dao接口即可調用其中的方法了,使用的是spring自動創建的代理對象去執行的。
4 整合SpringMVC
4.1 配置文件
上面的工作做完了後,其實需要寫一個測試程序來測試一下能否正確訪問數據庫,因爲整合必須步步爲營。由於這個比較簡單,我就不寫測試程序了。因爲前面web.xml配置中已經加入springmvc的支持了,所以這裏直接寫一下spring-mvc.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:p="http://www.springframework.org/schema/p"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
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/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
<!-- 使用註解的包,包括子集 -->
<context:component-scan base-package="demo.controller" />
<!-- 視圖解析器 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/" />
<property name="suffix" value=".jsp"></property>
</bean>
</beans>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
我這裏只配置了掃描包,沒有配映射器和適配器,也沒有寫那個<mvc:annotation-driven></mvc:annotation-driven>
註解驅動,也是可以執行的,我在網上沒查到原因,也沒去看源碼,我的猜測是springmvc中可能有默認的映射器和適配器。如果有看過源碼的朋友,請不吝賜教。
4.2 完成controller
配置好了後,就完成controller了,一個controller即可,因爲一個controller中可以寫很多方法。
@Controller
@RequestMapping("/user")
public class UserController {
//用戶登錄
@RequestMapping("/login")
public String login(User user, HttpServletRequest request) {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
try{
subject.login(token);//會跳到我們自定義的realm中
request.getSession().setAttribute("user", user);
return "success";
}catch(Exception e){
e.printStackTrace();
request.getSession().setAttribute("user", user);
request.setAttribute("error", "用戶名或密碼錯誤!");
return "login";
}
}
@RequestMapping("/logout")
public String logout(HttpServletRequest request) {
request.getSession().invalidate();
return "index";
}
@RequestMapping("/admin")
public String admin(HttpServletRequest request) {
return "success";
}
@RequestMapping("/student")
public String student(HttpServletRequest request) {
return "success";
}
@RequestMapping("/teacher")
public String teacher(HttpServletRequest request) {
return "success";
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
4.2 完成自定義realm
終於可以寫自己的realm了,上面用戶登錄會執行一個subject.login(token);
這裏會跳轉到我們自定義的realm中,接下來就來定義一下我們自己的realm,由於這裏是和mybatis整合了,所以不需要原來的那個DbUtil去連接數據庫了,直接使用mybatis中的mapper接口,也就是上面我們寫的dao。
public class MyRealm extends AuthorizingRealm {
@Resource
private UserService userService;
// 爲當前登陸成功的用戶授予權限和角色,已經登陸成功了
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
String username = (String) principals.getPrimaryPrincipal(); //獲取用戶名
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setRoles(userService.getRoles(username));
authorizationInfo.setStringPermissions(userService.getPermissions(username));
return authorizationInfo;
}
// 驗證當前登錄的用戶,獲取認證信息
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal(); // 獲取用戶名
User user = userService.getByUsername(username);
if(user != null) {
AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), "myRealm");
return authcInfo;
} else {
return null;
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
這個自定義realm的原理和上一節是一樣的,只不過這裏使用注入的是service,然後service中使用的是dao接口中的方法去操作數據庫。
5. 幾個jsp頁面
接下來就剩幾個jsp頁面了,我簡單弄一下:
<!-- 這是login.jsp中的 -->
<body>
<form action="${pageContext.request.contextPath }/user/login.do" method="post">
username:<input type="text" name="username"/><br>
password:<input type="password" name="password"/><br>
<input type="submit" value="登陸">${error }
</form>
</body>
<!-- 這是success.jsp中的 -->
<body>
歡迎你${user.username }
<a href="${pageContext.request.contextPath }/user/logout.do">退出</a>
</body>
<!-- 這是unauthorized.jsp中的 -->
<body>
認證未通過,或者權限不足
<a href="${pageContext.request.contextPath }/user/logout.do">退出</a>
</body>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
6. 測試
根據spring的配置文件中對shiro的url攔截配置,我們首先請求:http://localhost:8080/ShiroSpring/user/admin.do來測試身份認證,然後會跳轉到登錄頁面讓我們登陸,登陸成功後,再次請求這個url就會進入success.jsp頁面了。
再測試角色和權限認證,可以先後輸入http://localhost:8080/ShiroSpring/user/student.do來測試角色認證,輸入http://localhost:8080/ShiroSpring/user/teacher.do來測試權限認證。通過登陸不同的用戶去測試即可。