七.springmvc+shiro整合

来源:互联网 发布:数据库营销系统 编辑:程序博客网 时间:2024/06/08 13:22

一.mavne的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>com.tiglle</groupId>  <artifactId>springmvc-shiro</artifactId>  <packaging>war</packaging>  <version>0.0.1-SNAPSHOT</version>  <name>springmvc-shiro Maven Webapp</name>  <url>http://maven.apache.org</url>  <!-- 全局属性 -->  <properties>      <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>      <spring.version>3.1.2.RELEASE</spring.version>    </properties>    <dependencies>    <!-- springmvc的依赖 -->    <dependency>          <groupId>org.springframework</groupId>          <artifactId>spring-webmvc</artifactId>          <version>${spring.version}</version>      </dependency>      <dependency>          <groupId>org.springframework</groupId>          <artifactId>spring-web</artifactId>          <version>${spring.version}</version>      </dependency>      <!-- shiro-spring整合 -->    <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>     <!-- https://mvnrepository.com/artifact/jstl/jstl -->    <dependency>        <groupId>jstl</groupId>        <artifactId>jstl</artifactId>        <version>1.2</version>    </dependency>    <!-- spring开启自动代理需要的包 -->    <dependency>        <groupId>org.aspectj</groupId>        <artifactId>aspectjweaver</artifactId>        <version>1.8.10</version>    </dependency>    <dependency>        <groupId>cglib</groupId>        <artifactId>cglib-nodep</artifactId>        <version>3.2.5</version>    </dependency>    <!-- shiro缓存:结合ehcache -->      <!-- https://mvnrepository.com/artifact/net.sf.ehcache/ehcache-core -->    <dependency>        <groupId>net.sf.ehcache</groupId>        <artifactId>ehcache-core</artifactId>        <version>2.6.11</version>    </dependency>    <dependency>        <groupId>org.apache.shiro</groupId>        <artifactId>shiro-ehcache</artifactId>        <version>1.4.0</version>    </dependency>    <!-- scope=provicer:在编译和测试的过程有效,最后生成war包时不会加入,诸如:servlet-api,因为servlet-api,tomcat等web服务器已经存在了,如果再打包会冲突  -->    <dependency>        <groupId>javax.servlet</groupId>        <artifactId>javax.servlet-api</artifactId>        <version>3.0.1</version>        <scope>provided</scope>    </dependency>      <dependency>         <groupId>javax.servlet.jsp</groupId>         <artifactId>javax.servlet.jsp-api</artifactId>         <version>2.3.1</version>         <scope>provided</scope>     </dependency>  </dependencies>  <build>    <finalName>springmvc-shiro</finalName>  </build></project>

二.tomcat的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"         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>Archetype Created Web Application</display-name>  <!-- Spring MVC 核心 -->  <servlet>    <servlet-name>springmvc</servlet-name>    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>    <!--以下init-param是自定义SpringMVC的配置文件的位置 -->    <!--         1.可以通过contextConfigLocation来自定义SpringMVC配置文件的位置,如不指定,则默认在WEB-INF目录下,名称为[<servlet-name>]-servlet.xml,此时文件名必须为[<servlet-name>]-servlet.xml,否则会出错        2.如果使用了contextConfigLocation自定义SpringMVC配置文件的位置,spring便不会加载默认/WEB-INF/[<servlet-name>]-servlet.xml文件,需注意    -->    <!-- <init-param>      <param-name>contextConfigLocation</param-name>      <param-value>classpath:applicationContext.xml</param-value>    </init-param> -->    <load-on-startup>1</load-on-startup>  </servlet>  <!-- 拦截设置 -->  <servlet-mapping>    <servlet-name>springmvc</servlet-name>    <!-- 此处可以可以配置成*.do,对应struts的后缀习惯 -->    <url-pattern>/</url-pattern>  </servlet-mapping>  <!-- Spring MVC 核心配置结束 -->  <!--配置监听器-->  <!-- 读取Spring配置文件;applicationContext-shiro.xml -->  <context-param>    <param-name>contextConfigLocation</param-name>    <!-- 如果是监听多个文件,可用‘,’隔开-->    <param-value>classpath:applicationContext-shiro.xml</param-value>  </context-param>   <!--Spring监听器 ApplicationContext 载入 -->  <listener>    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  </listener>  <!-- Spring字符集过滤器 -->  <filter>    <filter-name>encoding</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>  </filter>  <filter-mapping>    <filter-name>encoding</filter-name>    <url-pattern>/*</url-pattern>  </filter-mapping>  <!-- shiro配置 -->  <!-- shiro的filter -->  <filter>    <!-- 任意,但注入spring的时候ref名字要和这个相同,或者通过targetBeanName修改 -->    <filter-name>shiroFilter</filter-name>    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>    <!-- 是否由servlet容器控制filter的生命周期true:是 -->    <init-param>        <!-- 覆盖DelegatingFilterProxy的属性默认配置或赋值 -->        <param-name>targetFilterLifecycle</param-name>        <param-value>true</param-value>    </init-param>    <!-- 修改spring容器注入filter时的id名字,如果不设置,则用filter-name标签的值 -->    <init-param>        <param-name>targetBeanName</param-name>        <param-value>shiroFilter</param-value>    </init-param>  </filter>  <!-- 过滤设置 -->  <filter-mapping>    <filter-name>shiroFilter</filter-name>    <url-pattern>/*</url-pattern>  </filter-mapping></web-app>

三.springmvc的配置文件springmvc-servlet.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:context="http://www.springframework.org/schema/context"      xmlns:mvc="http://www.springframework.org/schema/mvc"      xmlns:p="http://www.springframework.org/schema/p"     xmlns:aop="http://www.springframework.org/schema/aop"      xsi:schemaLocation="http://www.springframework.org/schema/beans              http://www.springframework.org/schema/beans/spring-beans.xsd              http://www.springframework.org/schema/mvc              http://www.springframework.org/schema/mvc/spring-mvc.xsd              http://www.springframework.org/schema/context              http://www.springframework.org/schema/context/spring-context.xsd             http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"            default-lazy-init="true">     <!-- 开启注解模式驱动 -->    <mvc:annotation-driven></mvc:annotation-driven>    <!-- 扫包 -->    <context:component-scan base-package="com.tiglle.*"></context:component-scan>    <!-- 开启shiro注解的配置 -->    <!-- spring方面:开启aop代理 -->    <aop:config proxy-target-class="true"></aop:config>    <!-- shiro方面:开启shiro注解支持 -->    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">        <property name="securityManager" ref="securityManager"/>    </bean>    <!-- 视图渲染 jsp/freemaker/velocity-->    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">        <!-- 制定页面存放的路径 -->        <property name="prefix" value="/"></property>        <!-- 文件的后缀 -->        <property name="suffix" value=".jsp"></property>    </bean></beans>

四.springmvc和shiro的整合配置applicationContext-shiro.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:context="http://www.springframework.org/schema/context"      xmlns:mvc="http://www.springframework.org/schema/mvc"      xmlns:p="http://www.springframework.org/schema/p"      xsi:schemaLocation="http://www.springframework.org/schema/beans              http://www.springframework.org/schema/beans/spring-beans.xsd              http://www.springframework.org/schema/mvc              http://www.springframework.org/schema/mvc/spring-mvc.xsd              http://www.springframework.org/schema/context              http://www.springframework.org/schema/context/spring-context.xsd"              default-lazy-init="true">     <!-- 将web.xml配置的shiroFilter注入到spring容器        id和web.xml的filter-name的值相同,或者和targetBeanName值相同     -->    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">        <!-- 覆盖或赋值ShiroFilterFactoryBean的属性 -->        <!-- 指定securityManager -->        <property name="securityManager" ref="securityManager"/>        <!-- 认证提交地址,如果用户没有认证或认证失效,需要进行表单提交请求此地址进行身份认证(由formAuthentication进行表单认证)默认会自动寻找Web工程根目录下的"/login.jsp"页面 -->        <property name="loginUrl" value="/login"/>        <!-- 指定没有权限时跳转的页面(或者一个控制器的连接) -->        <property name="unauthorizedUrl" value="/refuse.jsp"/>        <!-- 指定认证成功的跳转页面,如果不设置,默认跳回上一个url-->        <property name="successUrl" value="/WEB-INF/page/main.jsp"/>        <!-- shiro的自定义filter配置,会从上往下一个个过滤 -->        <property name="filters">            <map>                <!-- 所有自定义filter都在这配置,将自定义的FormAuthenticationFilter注入shiro的filter中 -->                <entry key="authc" value-ref="formAuthenticationFilter" />            </map>        </property>        <!-- 过滤规则,从上到下顺序执行,一般将/**放在最下面 -->        <property name="filterChainDefinitions">            <value>                <!-- /**:所有的地址   anon:匿名访问   所有地址都可以匿名访问-->                <!-- /login=authc -->                <!-- 指定访问shiro自带的退出登录的连接,shiro会清除session /logout:url  logout:shiro自带的退出登陆的方法-->                /logout=logout                <!-- 首页可以匿名访问 -->                /codeImage.jsp=anon                <!-- 配置记住我或有认证信息可以访问的连接,user权限就是 -->                /main = user <!-- 只有main能在记住我状态和用户信息不为空的情况下能访问,其他连接会往下走authc认证 -->                <!--                 需要授权的连接 格式:连接 = perms[权限字符串标示] ,认证失败,会跳转unauthorizedUrl的地址,只有这里配置的连接才会去realm检测权限                 缺点:配置太多                解决方法:注解和jsp标签方式配置,注解需要在spring配置文件开启,然后在controller上添加注解                -->                <!-- /items/query = perms[item:query] --><!-- 换成使用注解方式配置 -->                <!-- /**:所有的地址   authc:需要认证 -->                /**=authc            </value>        </property>    </bean>    <!-- securityManager安全管理器 -->    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">        <!-- 使用自定义realm认证 -->        <property name="realm" ref="customRealm"/>        <!-- 注入缓存管理器,第一次授权会请求realm,后面的授权都不会请求realm -->        <property name="cacheManager" ref="cacheManager" />        <!-- 注入session管理器 -->        <property name="sessionManager" ref="sessionManager"/>        <!-- 注入记住我remeberMeManager管理器 -->        <property name="rememberMeManager" ref="rememberMeManager"/>    </bean>    <!-- 自定义realm -->    <bean id="customRealm" class="com.tiglle.shiro.CustomRealm">        <!-- 将凭证匹配器注入到realm-->        <property name="credentialsMatcher" ref="credentialsMatcher"/>    </bean>    <!-- 配置凭证匹配器:指定散列算法,散列次数 -->    <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">        <!-- 散列算法 -->        <property name="hashAlgorithmName" value="md5"/>        <!-- 散列次数 -->        <property name="hashIterations" value="1"/>    </bean>    <!-- ehcache缓存管理器   value为ehcache配置文件位置-->    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">        <property name="cacheManagerConfigFile" value="classpath:shiro-ehcache.xml" />    </bean>    <!-- 会话管理,session交给shiro管理 -->       <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">        <!-- session的超时时间  毫秒-->        <property name="globalSessionTimeout" value="500000"/>        <!-- 是否删除已经失效的session数据 -->        <property name="deleteInvalidSessions" value="true"/>    </bean>    <!-- 配置form认证过滤器为自定义的,不配置会使用系统默认的,也可以直接配置系统默认的,并修改账号密码的字段名 -->    <bean id="formAuthenticationFilter" class="com.tiglle.shiro.CustomFormAuthenticationFilter">        <!-- 设置表单中账号的input的name值 -->        <property name="usernameParam" value="username"/>        <!-- 设置表单中密码的input的name值 -->        <property name="passwordParam" value="password"/>        <!-- 设置记住我的input的name值 -->        <property name="rememberMeParam" value="rememberMe"/>    </bean>    <!-- remenerMeManager管理器,写cookie,取cookie,生成用户信息 -->    <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">        <property name="cookie" ref="rememberMeCookie" />    </bean>    <!-- 记住我cookie信息 -->    <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">        <!-- 生成cookie的名字 -->        <constructor-arg value="remeberMe" />        <!-- cookie的存在时间(30天)  秒-->        <property name="maxAge" value="2592000"/>    </bean></beans>

五.ehcache的缓存配置shiro-ehcache.xml:

<?xml version="1.0" encoding="UTF-8"?><ehcache     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">    <!-- diskStore:缓存数据持久化的目录地址 -->    <diskStore path="F:\ehcache\store" />    <defaultCache         maxElementsInMemory="1000"         eternal="false"         timeToIdleSeconds="120"         timeToLiveSeconds="120"        overflowToDisk="false"         diskSpoolBufferSizeMB="30"         maxElementsOnDisk="10000000"        diskPersistent="false"         diskExpiryThreadIntervalSeconds="120"        memoryStoreEvictionPolicy="LRU"/></ehcache>

六.自定义reaml的java类和自定义Form认证过滤器:
1.自定义reaml的java类CustomRealm.java:

package com.tiglle.shiro;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import org.apache.shiro.SecurityUtils;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.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.apache.shiro.util.ByteSource;import com.tiglle.bean.User;/** * 自定义realm,覆盖默认realm(需要配置),让授权数据从数据库或其他地方获取 * @author Administrator * */public class CustomRealm extends AuthorizingRealm{    /**     * 设置realm的名称,模拟用     */    @Override    public void setName(String name) {        super.setName("customRealm");    }    /**     * 认证     */    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {        //token是用户输入的信息        //1.从token中取出用户身份信息,也就是登陆页面的username        String username = (String) token.getPrincipal();        System.out.println("---username:"+username);        //2.根据用户身份信息从数据库查询用户信息        //.......根据userCode查询数据库        //模拟查了数据库,获得了User对象        User user = new User();        //User user = userService.getUserByUsername(username);        //模拟从数据库查询了用户信息,设置用户信息        user.setNickname("小明");        user.setUname(username);        user.setUpass("bacbc96d57da0555dc8b58beadbc2d93");//123456+qwert        user.setSalt("qwert");        //3.查询不到,请返回null        if(user==null){            return null;        }        //模拟从数据库查询了用户菜单信息        Map<String,String> menus = new HashMap<String, String>();        //Map<String,String> menus = userService.getUserMenusById(user.getId());        menus.put("商品列表","items/query");        menus.put("增加商品","items/toAdd");        menus.put("编辑商品","items/toUpdate");        user.setMenus(menus);        //密码        String password = user.getUpass();        //盐        String salt = user.getSalt();        //4.查询到,返回AuthenticationInfo,将user设置进去,盐设置j进去,别忘了在spring配置文件配置凭证匹配器,可以在控制器通过Subject获取        SimpleAuthenticationInfo simpleAuthenticationInfo =                 new SimpleAuthenticationInfo(user,password,ByteSource.Util.bytes(salt),this.getName());        return simpleAuthenticationInfo;    }    /**     * 授权     */    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {        //认证成功后授权        //从principals中获取主身份信息,上面认证成功后存入的省份信息        @SuppressWarnings("unused")        User user = (User) principals.getPrimaryPrincipal();        //根据身份信息从数据库查询权限信息        //模拟查询了数据库...        //根据身份获得了用户所有的权限信息(List为获取的权限集合)        List<String> permission = new ArrayList<String>();        //List<String> permission = userService.findPermissionsByUserId(user.getId());        permission.add("user:add");//=user:create:*        permission.add("user:create:1");        permission.add("items:query");        permission.add("items:add");        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();        //返回用户所有的权限        simpleAuthorizationInfo.addStringPermissions(permission);        return simpleAuthorizationInfo;    }    /**     * 手动清空shiro授权缓存的方法,供service调用     * 清除后,授权会再次请求realm     */    public void clearCached(){        PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();        super.clearCache(principals);    }}

2.自定义form认证过滤器的javaCustomFormAuthenticationFilter.java:

package com.tiglle.shiro;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;public class CustomFormAuthenticationFilter extends FormAuthenticationFilter {    @Override    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {        // 在这里进行验证码的校检,或者session中数据的校检        //将ServletRequest转为HttpServletRequest        HttpServletRequest httpServletRequest = (HttpServletRequest) request;        //获取session        HttpSession session = httpServletRequest.getSession();        //取出session中的验证码        String code = (String) session.getAttribute("code");        //取出页面的验证码(从ServletRequest获取)        String pageCode = httpServletRequest.getParameter("code");        if(pageCode!=null&&!"".equals(pageCode)&&!pageCode.equals(code)){            //如果验证码为空或者验证码与session中的不相等,手动设置异常            httpServletRequest.setAttribute("shiroLoginFailure", "CodeErrorException");            //拒绝访问,不在继续验证账号密码            return true;        }        //否则,继续验证账号密码(父类方法)        return super.onAccessDenied(request, response);    }}

七.存放用户信息的实体类User.java:

package com.tiglle.bean;import java.io.Serializable;import java.util.Map;//shiro的remeberMe需要用户身份实体类实现Serializable以便序列化和反序列化public class User implements Serializable{    private String id;    private String uname;    private String upass;    private String salt;    private String nickname;    private Map<String,String> menus;    public String getUname() {        return uname;    }    public void setUname(String uname) {        this.uname = uname;    }    public String getUpass() {        return upass;    }    public void setUpass(String upass) {        this.upass = upass;    }    public String getNickname() {        return nickname;    }    public void setNickname(String nickname) {        this.nickname = nickname;    }    public String getId() {        return id;    }    public void setId(String id) {        this.id = id;    }    public Map<String, String> getMenus() {        return menus;    }    public void setMenus(Map<String, String> menus) {        this.menus = menus;    }    public String getSalt() {        return salt;    }    public void setSalt(String salt) {        this.salt = salt;    }}

八.springmvc的控制器controller:
1.LoginController.java:

package com.tiglle.controller;import javax.servlet.http.HttpServletRequest;import org.apache.shiro.authc.IncorrectCredentialsException;import org.apache.shiro.authc.UnknownAccountException;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;@Controllerpublic class LoginController {    /**     *  登陆原理:     *  使用FormAuthenticationFilter过虑器实现 ,原理如下:     *  将用户没有认证时,请求loginurl进行认证,用户身份和用户密码提交数据到loginurl     *  FormAuthenticationFilter拦截住取出request中的username和password(两个参数名称是可以配置的)     *  FormAuthenticationFilter调用realm传入一个token(username和password)     *  realm认证时根据username查询用户信息(在Activeuser中存储,包括 userid、usercode、username、menus)。     *  如果查询不到,realm返回null,FormAuthenticationFilter向request域中填充一个参数(记录了异常信息)     * @throws Exception      */    //此控制器只有自定义realm认证失败才会进入,认证成功自动跳转到上一次访问的连接    @RequestMapping("login")    public String login(HttpServletRequest request) throws Exception{        //如果登陆失败,shiro把异常放入request中,key为shiroLoginFailure,value为异常的全限定名(包名.类名)        String exceptionName = (String) request.getAttribute("shiroLoginFailure");        //根据shiro返回的的异常类名判断异常信息        if(exceptionName!=null){            if(UnknownAccountException.class.getName().equals(exceptionName)){                //账号不存在异常                throw new Exception("账号不存在");            }else if(IncorrectCredentialsException.class.getName().equals(exceptionName)){                //用户名/密码错误                throw new Exception("用户名/密码错误");            }else if("CodeErrorException".equals(exceptionName)){                throw new Exception("验证码错误");            }else{                throw new Exception("未知异常");            }        }        return "WEB-INF/page/login";    }}

2.MainController.java:

package com.tiglle.controller;import org.apache.shiro.SecurityUtils;import org.apache.shiro.subject.Subject;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.RequestMapping;import com.tiglle.bean.User;@Controllerpublic class MainController {    @RequestMapping("main")    public String main(Model model){        //从shiro中获取放入的user信息        Subject subject = SecurityUtils.getSubject();        User user = (User) subject.getPrincipal();        model.addAttribute("user", user);        return "/WEB-INF/page/main";    }}

3.ItemsController.java:

package com.tiglle.controller;import org.apache.shiro.authz.annotation.RequiresPermissions;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;@Controller@RequestMapping("/items")public class ItemsController {    //shiro权限注解的使用,只有拥有对应的权限才能执行控制器,否则到配置文件中配置的授权失败的连接(或者报没有权限的异常...)    //执行到注解时,会到自定义realm中授权    /**     * 到商品列表     * @return     */    @RequestMapping("/query")    @RequiresPermissions("items:query")//shiro权限注解,表示只有items:query权限才能进此控制器    public String query(){        return "/WEB-INF/page/itemsList";    }    /**     * 到编辑商品页     * @return     */    @RequiresPermissions("items:add")//shiro权限注解,表示只有items:add权限才能进此控制器    @RequestMapping("/toAdd")    public String toAdd(){        return "/WEB-INF/page/addItems";    }    /**     * 确定编辑商品     * @return     */    @RequestMapping("/add")    @RequiresPermissions("items:add")//shiro权限注解,表示只有items:add权限才能进此控制器    public String add(){        return "/WEB-INF/page/itemsList";    }    /**     * 到编辑商品页     * @return     */    @RequestMapping("/toUpdate")    @RequiresPermissions("items:update")//shiro权限注解,表示只有items:update权限才能进此控制器    public String toUpdate(){        return "/WEB-INF/page/updateItems";    }    /**     * 确定编辑商品     * @return     */    @RequestMapping("/update")    @RequiresPermissions("items:update")//shiro权限注解,表示只有items:update权限才能进此控制器    public String update(){        return "/WEB-INF/page/itemsList";    }}

4.TestRemoveShiroCache.java:

package com.tiglle.controller;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import com.tiglle.shiro.CustomRealm;@Controllerpublic class TestRemoveShiroCache {    /**     * 手动情况shiro授权缓存(shiro默认关闭认证缓存,开启授权缓存,授权缓存需配置)     * 正常手动清空授权缓存应该在service层,当用户权限改变时调用     */    //注入自定义realm    @Autowired    private CustomRealm realm;    @RequestMapping("clearShiroCache")    public String clearShiroCache(){        realm.clearCached();        return "success";    }}

九.webapps下的页面:
1.首页index.jsp:

<%@ page language="java" contentType="text/html; charset=utf-8"    pageEncoding="utf-8"%><html><body><centeer><h1>首页面</h1></centeer><a href="main">系统管理</a></body></html>

2.没有权限配置的无权页面refuse.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=ISO-8859-1"><title>Insert title here</title></head><body>无权访问</body></html>

3.生成验证码的codeImage.jsp:

<%@ page contentType="image/jpeg" import="java.awt.*,java.awt.image.*,java.util.*,javax.imageio.*" pageEncoding="utf-8"%> <%! Color getRandColor(int fc,int bc) { Random random = new Random(); if(fc>255) fc=255; if(bc>255) bc=255; int r=fc+random.nextInt(bc-fc); int g=fc+random.nextInt(bc-fc); int b=fc+random.nextInt(bc-fc); return new Color(r,g,b); } %> <% out.clear();//这句针对resin服务器,如果是tomacat可以不要这句 response.setHeader("Pragma","No-cache"); response.setHeader("Cache-Control","no-cache"); response.setDateHeader("Expires", 0); int width=60, height=20; BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics g = image.getGraphics(); Random random = new Random(); g.setColor(getRandColor(200,250)); g.fillRect(0, 0, width, height); g.setFont(new Font("Times New Roman",Font.PLAIN,18)); g.setColor(getRandColor(160,200)); for (int i=0;i<155;i++) { int x = random.nextInt(width); int y = random.nextInt(height); int xl = random.nextInt(12); int yl = random.nextInt(12); g.drawLine(x,y,x+xl,y+yl); } String sRand=""; for (int i=0;i<4;i++){ String rand=String.valueOf(random.nextInt(10)); sRand+=rand; g.setColor(new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110))); g.drawString(rand,13*i+6,16); } // 将认证码存入SESSION session.setAttribute("code",sRand); g.dispose(); ImageIO.write(image, "JPEG", response.getOutputStream()); %>

十.WEB-INF/page下的页面:
1.登陆页面login.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=ISO-8859-1"><title>Insert title here</title></head><body><form action="login" method="post"><br/>    账号:<input type="text" name="username"><br/>    密码:<input type="password" name="password"><br/>    验证码:<input type="text" name="code"><img alt="验证码" src="/springmvc-shiro/codeImage.jsp" onclick="changeCode(this)"><br/>    <input type="checkbox" name="rememberMe"/>自动登陆(记住我)<br/>    <input type="submit" value="登陆"></form></body></html><script type="text/javascript">    function changeCode(o){        o.src="/springmvc-shiro/codeImage.jsp?d="+new Date().getTime();    }</script>

2.登陆成功的主页面main.jsp:

<%@ page language="java" contentType="text/html; charset=utf-8"    pageEncoding="utf-8"%><%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %><!-- 使用shiro的jsp标签需要的 --><%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro" %><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head><title>系统管理</title></head><body><h3><c:if test="${empty user }"><a href="login">请登录</a></c:if><c:if test="${not empty user }">欢迎您:${user.nickname }</c:if>    </h3><center>    <h1>系统管理</h1>    <!-- shiro的jsp权限判断标签 -->    <!-- 执行到此标签处会到自定义realm中检测权限-->    <shiro:hasPermission name="items:query">        <h4>拥有到商品列表的权限</h4>    </shiro:hasPermission>    <shiro:hasPermission name="items:add">        <h4>拥有添加商品的权限</h4>    </shiro:hasPermission>    <shiro:hasPermission name="items:update">        <h4>拥有修改商品的权限</h4>    </shiro:hasPermission>    <c:forEach items="${user.menus }" var="menu">        <h2><a href="${menu.value }">${menu.key }</a></h2>    </c:forEach>    <!-- jsp的shiro标签 -->    <code>    标签名称    标签条件(均是显示标签内容)    shiro:authenticated 登录之后    shiro:notAuthenticated  不在登录状态时    shiro:guest 用户在没有RememberMe时    shiro:user  用户在RememberMe时    shiro:hasAnyRoles name="abc,123"    在有abc或者123角色时    shiro:hasRole name="abc"    拥有角色abc    shiro:lacksRole name="abc"  没有角色abc    shiro:hasPermission name="abc"  拥有权限资源abc    shiro:lacksPermission name="abc"    没有abc权限资源    shiro:principal 显示用户身份名称    shiro:principal property="username"     显示用户身份中的属性值    </code>    <!-- shiro --></center><a href="logout">退出登陆</a><a href="clearShiroCache">清除shiro缓存</a></body></html>

3.添加商品的页面addItems.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=ISO-8859-1"><title>Insert title here</title></head><body><center>    <h1>增加商品页</h1>    <h2><a href="add">确定增加</a></h2></center></body></html>

4.更新商品的页面updateItems.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=ISO-8859-1"><title>Insert title here</title></head><body><center>    <h1>编辑商品页</h1>    <h2><a href="update">确定编辑</a></h2></center></body></html>

5.商品列表页面itemsList.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=ISO-8859-1"><title>Insert title here</title></head><body><center>    <h1>商品列表页</h1></center></body></html>