一 、底层环境搭建
1、项目结构:
2、shrio的maven依赖
<dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.3</version> </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.2.2</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.2.2</version> </dependency>
3、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" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 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>TestShiro</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <!-- 防止发生java.beans.Introspector内存泄露,应将它配置在ContextLoaderListener的前面 --> <!-- 详细描述见http://blog.csdn.net/jadyer/article/details/11991457 --> <listener> <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class> </listener> <!-- 实例化Spring容器 --> <!-- 应用启动时,该监听器被执行,它会读取Spring相关配置文件,其默认会到WEB-INF中查找applicationContext.xml --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 配置编码过滤器 --> <filter> <filter-name>characterEncodingFilter</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>characterEncodingFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- 配置Shiro过滤器,先让Shiro过滤系统接收到的请求 --> <!-- 这里filter-name必须对应applicationContext.xml中定义的<bean id="shiroFilter"/> --> <!-- 使用[/*]匹配所有请求,保证所有的可控请求都经过Shiro的过滤 --> <!-- 通常会将此filter-mapping放置到最前面(即其他filter-mapping前面),以保证它是过滤器链中第一个起作用的 --> <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> <!-- SpringMVC核心分发器 --> <servlet> <servlet-name>dispatcherServlet</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> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>/index.jsp</welcome-file> </welcome-file-list> </web-app>
2、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: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:cache="http://www.springframework.org/schema/cache" xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns:jpa="http://www.springframework.org/schema/data/jpa" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-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/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd" default-lazy-init="true"> <context:component-scan base-package="com.libm" > <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller" /> </context:component-scan> <context:property-placeholder location="classpath:jdbc.properties"/> <!-- c3p0连接 --> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="${jdbc.driverClassName}" /> <property name="jdbcUrl" value="${jdbc.url}" /> <property name="user" value="${jdbc.username}" /> <property name="password" value="${jdbc.password}" /> </bean> <!-- JPA实体管理器工厂 --> <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" /> <!-- 加入定制化包路径, 此种写法不需要配置persistence.xml,会自动扫描实体类 --> <property name="packagesToScan" value="com.libm.domain" /> <property name="jpaProperties"> <props> <prop key="hibernate.current_session_context_class">thread</prop> <prop key="hibernate.hbm2ddl.auto">update</prop><!-- validate/update/create --> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">false</prop> <!-- 建表的命名规则 --> <!-- <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop> --> </props> </property> </bean> <!-- 设置JPA实现厂商的特定属性 --> <bean id="hibernateJpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"> <property name="databasePlatform" value="org.hibernate.dialect.MySQL5Dialect"/> </bean> <!-- Jpa 事务配置 --> <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="entityManagerFactory"/> </bean> <!-- Spring Data Jpa配置 --> <jpa:repositories base-package="com.libm" transaction-manager-ref="transactionManager" entity-manager-factory-ref="entityManagerFactory"/> <!-- 使用annotation定义事务 --> <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" /> <!-- /////////////////////////////////////////////////////////////////////////////////// --> <!-- shiro --> <bean id="myShiro" class="com.libm.service.MyShiro"></bean> <!-- 配置权限管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <!-- ref对应我们写的realm MyShiro --> <property name="realm" ref="myShiro"/> <!-- 使用下面配置的缓存管理器 --> <property name="cacheManager" ref="cacheManager"/> </bean> <!-- 配置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.do"/> <!-- 配置我们在登录页登录成功后的跳转地址,如果你访问的是非/login地址,则跳到您访问的地址 --> <property name="successUrl" value="/home.do"/> <!-- 如果您请求的资源不再您的权限范围,则跳转到/403请求地址 --> <!-- <property name="unauthorizedUrl" value="/403"/> --> <!-- 权限配置 --> <property name="filterChainDefinitions"> <value> <!-- anon表示此地址不需要任何权限即可访问 --> /index.do = anon /login.do = authc /home.do = authc </value> </property> </bean> <bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" /> <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /> </beans>
3、spring-mvc.xml的配置
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:mvc="http://www.springframework.org/schema/mvc" 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-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/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd" > <!-- 启动springMVC注解 --> <mvc:annotation-driven/> <context:component-scan base-package="com.libm"> <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" /> <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service" /> </context:component-scan> <!-- 自定义tiles --> <bean id="tilesConfigurer" class="org.springframework.web.servlet.view.tiles3.TilesConfigurer"> <property name="definitions"> <list> <value>classpath:titles.xml</value> </list> </property> </bean> <bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver"> <property name="viewClass"> <value> org.springframework.web.servlet.view.tiles3.TilesView </value> </property> </bean> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="viewClass" value="org.springframework.web.servlet.view.JstlView" /> <property name="prefix" value="/" /> <property name="suffix" value=".jsp" /> </bean> <!-- <mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/*.do"/> <mvc:exclude-mapping path="/index.do"/> <mvc:exclude-mapping path="/login.do"/> <bean class="com.libm.interceptor.LoginInterceptor" /> </mvc:interceptor> </mvc:interceptors> --> <!-- 静态资源加载 --> <mvc:resources location="/css/" mapping="/css/**" /> <mvc:resources location="/js/" mapping="/js/**"/> <mvc:resources location="/images/" mapping="/images/**" /> </beans>
一 、实现
1、实体类
import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; @Entity public class User { private Integer id; private String username; private String password; @Id @GeneratedValue(strategy=GenerationType.IDENTITY) public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
2、 自定义MyShiro 身份验证
import java.util.List; 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.UsernamePasswordToken; 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; import org.springframework.stereotype.Service; import com.libm.domain.User; @Service public class MyShiro extends AuthorizingRealm { @Autowired private UserService userService; @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { return null; } @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { // UsernamePasswordToken对象用来存放提交的登录信息 UsernamePasswordToken token = (UsernamePasswordToken) authcToken; String username = token.getUsername(); String password = String.valueOf(token.getPassword()); // 查出是否有此用户 ,此处查询数据库 User user = userService.chekLogin(username,password); if (user != null) { // 若存在,将此用户存放到登录认证info中 return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName()); } return null; } }
3、index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Login</title> <script type="text/javascript" src="js/jquery-1.8.3.min.js"></script> </head> <body> <form action="login.do" method="post"> <div align="center"> <table> <tr> <td>username</td> <td><input type="text" name="username"/> </td> </tr> <tr> <td>password</td> <td><input type="password" name="password"/> </td> </tr> </table> <button type="submit" id="loginBtn">login</button> </div> </form> </body> </html>
4、LoginController
package com.libm.controller; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.UsernamePasswordToken; import org.apache.shiro.subject.Subject; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.libm.domain.User; @Controller public class LoginController { @RequestMapping(value="login") public String login(User user){ Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword()); try{ token.setRememberMe(true); subject.login(token); return "redirect:/home.do"; }catch(Exception e){ return "redirect:/index.do"; } } @RequestMapping(value="home") public ModelAndView home(){ ModelAndView mv = new ModelAndView("home"); return mv; } @RequestMapping(value="index") public ModelAndView index(){ ModelAndView mv = new ModelAndView("index"); return mv; } @RequestMapping(value="logout") public String logout(){ Subject subject = SecurityUtils.getSubject(); subject.logout(); return "redirect:/index.do"; } }