主要内容
shiro整合spring
依然是创建一个web项目,把必要的包入到到项目中。需要的包如下:
编写web.xml配置文件
和spring集成的时候,我们使用的过滤器是DelegatingFilterProxy
,这个过滤器的作用是从当前的上下文中获取和此过滤器名称相同的bean,另外,既然我们是和spring集成,那必须要做的一件事就是加载spring的配置文件,这个由ContextLoaderListener
负责。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<!--加载spring配置文件--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <filter> <!--从applicatoinContext中加载名称为shiroFilter的bean--> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
编写applicationContext配置文件
前面说过,web.xml文件中的DelegatingFilterProxy在applicationContext中寻找一个id和它的名字相同的bean,这里使用的是shiroFilter,所以,applicationContext文件中首先要定义一个id为shiroFilter的bean,这个bean类型是ShiroFilterFactoryBean,它是shiro的主要类,用于配置url的访问规则:例如登录入口,url的访问权限等。
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 |
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="loginUrl" value="/login"/> <property name="unauthorizedUrl" value="/error"/> <property name="securityManager" ref="securityManager"/> <property name="filterChainDefinitions"> <value> /login=anon /admin=authc </value> </property> </bean> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="jdbcRealm"/> </bean> <!--使用jdbcRealm从数据库获取用户账号信息--> <bean id="jdbcRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm"> <property name="dataSource" ref="dataSource"/> <property name="authenticationQuery" value="select password from user where username = ?"/> </bean> <!--配置数据源--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="username" value="root"/> <property name="password" value=""/> <property name="url" value="jdbc:mysql:///shiro?useSSL=true"/> </bean> |
由于我们的账号信息需要从数据库中取出来,最简单的方式就是使用预定义的JdbcRealm
类,连接数据库之前必须要配置数据源,所以,applicationContext文件中可以看到数据源的配置信息。另外,ShiroFilterFactoryBean中的SecurityManager类型必须是WebSecurityManager接口的子类。
需要注意的是:JdbcRealm默认使用sql语句select password from users where username=?
查询账户信息。如果你希望根据需求使用不同的语句,需要明确设置JdbcRealm的authenticationQuery
的属性值。
至此,shiro整合spring完成。
整合SpringMVC
既然已经整合了spring,那么,使用servlet作为控制器已经没有什么好处。可选的替代方案有struts2和springmvc,这里选择的是springmvc。整合springmvc还需要导入两个包:spring-webmvc和spring-aop。
编写web.xml配置文件
springmvc的入口是DispatcherServlet,由于前面我们使用的配置文件名称为applicationContext.xml,而DispatcherServlet默认的配置文件名称是:它的名称-servlet.xml。例如如果DispatcherServlet的servlet-name是springmvc,那么配置文件名称就是springmvc-sevlet.xml
。所以我们必须明确设置配置文件的名称。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> |
springmvc中的url-pattern不能是 /*,否则会报错导致程序运行不起来。
编写applicationContext配置文件
applicationContext文件的主要功能是配置web控制器,springmvc有多种方式设置控制器,最简单的就是使用注解控制器,使用注解控制器的前提是开启组件扫描。下面是applicationContext文件新增的springmvc部分的配置。
1 2 3 4 5 6 7 8 |
<!--开启组件扫描 并设置扫描的基础包--> <context:component-scan base-package="cn.sharpcode" /> <!--设置模板解析器--> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/" /> <property name="suffix" value=".jsp" /> </bean> |
开启控制器shiro注解支持
1 2 3 4 5 6 7 |
<bean id="lifeCycleBeanPostProcess" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> <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> |
注意:shrio的注解对servlet不起作用,只对springmvc的控制器生效。
编写测试控制器
下面是控制器的伪代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
package cn.sharpcode.web.controller; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import javax.servlet.http.HttpServletRequest; @Controller public class LoginController { @RequestMapping(value = "/login") public String doLogin(HttpServletRequest request, Model model){ if login successful redirect to admin else try to login again } } |
完整项目代码
web.xml
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 |
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <!--加载spring配置文件--> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <filter> <!--从applicatoinContext中加载名称为shiroFilter的bean--> <filter-name>shiroFilter</filter-name> <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <servlet> <servlet-name>springmvc</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/applicationContext.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>springmvc</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping> </web-app> |
applicationContext.xml
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 |
<?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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="cn.sharpcode"/> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/"/> <property name="suffix" value=".jsp"/> </bean> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="loginUrl" value="/login"/> <property name="unauthorizedUrl" value="/error"/> <property name="securityManager" ref="securityManager"/> <property name="filterChainDefinitions"> <value> /login=anon /admin=authc </value> </property> </bean> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="realm" ref="jdbcRealm"/> </bean> <!--使用jdbcRealm从数据库获取用户账号信息--> <bean id="jdbcRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm"> <property name="dataSource" ref="dataSource"/> <property name="authenticationQuery" value="select password from user where username = ?"/> </bean> <!--配置数据源--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="username" value="root"/> <property name="password" value=""/> <property name="url" value="jdbc:mysql:///shiro?useSSL=true"/> </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 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 |
package cn.sharpcode.web.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @Controller public class LoginController { @RequestMapping(value = "/login", method = {RequestMethod.GET, RequestMethod.POST}) public String doLogin(HttpServletRequest request, HttpServletResponse response, Model model){ if ("GET".equals(request.getMethod())){ return doGet(request, model); } else { return doPost(request, model); } } @RequestMapping(value = "/admin") public String doManager(Model model){ model.addAttribute("welcome", "welcome admin"); return "admin"; } private String doGet(HttpServletRequest request, Model model) { return "log"; } private String doPost(HttpServletRequest request, Model model) { String username = request.getParameter("username"); String password = request.getParameter("password"); Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(username, password); String errorMessage; try{ subject.login(token); if (subject.isAuthenticated()){ return "redirect: /admin"; } } catch (AuthenticationException e){ errorMessage = e.getMessage(); model.addAttribute("error", errorMessage); return "log"; } return null; } } |
log.jsp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> <form action="${pageContext.request.contextPath}/login" method="post"> username: <input type="text" name="username" /> password <input type="password" name="password"/> <input type="submit" value="login" /> </form> ${error} </body> </html> |
admin.jsp
1 2 3 4 5 6 7 8 9 |
<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>Title</title> </head> <body> ${welcome} </body> </html> |