• SpringMvc-Httl-shiro的整合


    来到新的公司一个月,以前实习公司的用的是srping+hibernate+struts2,而在这里不在用的这些了,而是用的springMVC和jdbc模板来操作数据了,所以又用了一段时间去慢慢融入这个新的体系中去;但终究这些技术是万变不离其宗的,学习也是很快的事,所以我也就很快的就融入了这个团队;

    进入正题吧!我这里其实就是想把学习新东西自己记录下来,这有助于我的学习也有助于大家的学习;把springmvc+httl+shiro+maven给整合起来;我刚来到新公司这里已经是搭建好了这个项目;所以我也在空闲时间之余把这些知识给过了一遍,也有助于我开发效率的提高;

    我使用的开发工具室MyEclipse(开发工具的使用都是大同小异);

    至于httl和shiro的优势我就不多说了有兴趣的看:

    http://www.open-open.com/open342321.htm;

    http://blog.csdn.net/boonya/article/details/8233303

    废话不多说,开始搭建吧。。。

    1:首先建立一个javaweb项目

    2:配置pom.xml导入必须的jar包

    <dependencies>
              <!-- junit核心jar包 -->
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
            </dependency>
            <!-- springMVC核心jar包 -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-webmvc</artifactId>
                <version>4.0.5.RELEASE</version>
            </dependency>
    
            <!-- httl 核心jar包  -->
            <dependency>
                <groupId>com.github.httl</groupId>
                <artifactId>httl-springmvc</artifactId>
                <version>1.0.10</version>
            </dependency>
            <dependency>
                <groupId>com.github.httl</groupId>
                <artifactId>httl</artifactId>
                <version>1.0.11</version>
            </dependency>
            
            <!--当你运行的环境是jre是时;httl模板必须加入这个jar包;还有就是必须在httl的 httl.properties注入属性值:
            compiler=httl.spi.compilers.JavassistCompiler。。这点很重要,不然当你启动tomcat时会一直抛classnotfound异常-->
            <dependency>
                <groupId>org.javassist</groupId>
                <artifactId>javassist</artifactId>
                <version>3.18.2-GA</version>
            </dependency>
            
             <dependency>  
                <groupId>commons-logging</groupId>  
                <artifactId>commons-logging</artifactId>  
                <version>1.1.3</version>  
            </dependency>  
            <!-- shiro -->
            <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-ehcache</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-quartz</artifactId>
                <version>1.2.2</version>
            </dependency>
            <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>javax.servlet-api</artifactId>
                <version>3.1.0</version>
            </dependency>
            
            <!-- spring aop -->
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
                <version>1.8.5</version>
            </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjweaver</artifactId>
                <version>1.8.5</version>
            </dependency>
      </dependencies>

    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></display-name>
        
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
              classpath:applicationContext-shiro.xml
            </param-value>
        </context-param>
        <!-- 配置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>
        
        
        <!-- 加载httl的属性文件 -->
        <context-param>
            <param-name>httl.properties</param-name>
            <param-value>classpath:httl.properties</param-value>
        </context-param>
        
        
        <!-- Character Encoding filter -->
        <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>
            <dispatcher>REQUEST</dispatcher>
            <dispatcher>FORWARD</dispatcher>
        </filter-mapping>
    
    
        <!-- Spring MVC Servlet 载入 -->
        <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>
            <load-on-startup>1</load-on-startup>
        </servlet>
        <servlet-mapping>
            <servlet-name>springMVC</servlet-name>
            <url-pattern>/</url-pattern>
        </servlet-mapping>
    
        <!-- 实例化Spring容器 -->
        <!-- 应用启动时,该监听器被执行,它会读取Spring相关配置文件,其默认会到WEB-INF中查找applicationContext.xml -->
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
    
        
    
    
        <welcome-file-list>
            <welcome-file>index.jsp</welcome-file>
        </welcome-file-list>
    </web-app>

    4:添加httl.properties文件

    import.packages+=com.lishun.controller

    template.directory=/WEB-INF/templates

    template.suffix=.httl

    input.encoding=utf-8

    output.encoding=utf-8

    reloadable=true

    precompiled=true

    compiler=httl.spi.compilers.JavassistCompiler

    import.methods+=com.lishun.httl.staticMethods.ShiroKit

     

    注:import.packages:领域模型包导入

        import.methods:这里可以封装在httl模板页面上使用的静态方法

        template.directory:模板文件目录;

        template.suffix:模板文件后缀

        input.encoding:资源加载编码

        output.encoding: 模板输出编码

        precompiled:是否预编译

        reloadable: 是否热加载;开发模式下建议开启

        compiler:(摘自httl官网)

         用于将模板类编译成字节码,缺省使用根据JDK版本自适应编译器:(缺省值不用配)

    1

    compiler=httl.spi.compilers.AdaptiveCompiler

       当前运行环境为JDK1.6以前版本时,AdaptiveCompiler将适配到JavassistCompiler,否则将适配到JdkCompiler。

       你可以强制指定使用jdk自带的编译器:(必需要用JDK运行,JRE不行,JDK比JRE多编译工具包)

    1

    compiler=httl.spi.compilers.JdkCompiler

      你也可以换成javassist编译:(如果为JRE运行,请使用javassist编译)

    1

    compiler=httl.spi.compilers.JavassistCompiler

      当然,也就需要增加javassist的jar包依赖:

      javassist-3.15.0-GA.jar

     

     

     

     

    <dependency>

        <groupId>org.javassist</groupId>

        <artifactId>javassist</artifactId>

        <version>3.15.0-GA</version>

    </dependency>

     

    5:编写applicationContext-shiro.xml 注:该文件是管理shiro的

    <!-- 这里别忘了配置,否则会导致自定义的Realm的属性值无法注入 -->
        <context:component-scan base-package="com.lishun"></context:component-scan>
        <!-- 继承自AuthorizingRealm的自定义Realm,即指定Shiro验证用户登录的类为自定义的UserRealm.java -->
         <bean id="shiroRealm" class="com.lishun.shiro.realm.UserRealm" >
         
         </bean> 
        
        <!-- 基于Form表单的身份验证过滤器 -->
        <bean id="formAuthenticationFilter"
            class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">
            <property name="usernameParam" value="username" />
            <property name="passwordParam" value="password" />
            <property name="loginUrl" value="/users/index.html" />
            <property name="successUrl" value="/index/index.html" />
        </bean>
        <context:component-scan base-package="com.lishun"></context:component-scan>
        <bean
            class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
            depends-on="lifecycleBeanPostProcessor">
            <property name="proxyTargetClass" value="true" />
        </bean>
        
        <!-- 这里主要是设置自定义的单Realm应用,若有多个Realm,可使用'realms'属性代替 -->
        <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
            <property name="realm" ref="shiroRealm" />
        </bean>
        <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
            <!-- 调用自定义的权限管理器 -->
            <property name="securityManager" ref="securityManager" />
    
            <!-- 配置登陆成功后跳转地址 -->
            <property name="successUrl" value="/index/index" />
    
            <!-- 配置登陆时请求的地址 -->
            <property name="loginUrl" value="/users/index" />
    
            <!-- 如果请求的资源不再你的权限范围内,则跳转到error.htm -->
            <property name="unauthorizedUrl" value="/users/noAuth" />
    
            <property name="filters">
                <map>
                    <entry key="authc" value-ref="formAuthenticationFilter"></entry>
                </map>
            </property>
            <property name="filterChainDefinitions">
                <value>
                    <!-- anon表示此地址不需要任何权限即可访问 -->
                    /users/*=anon
                    <!--login页面和logout页面不需要验证 -->
                    /login* = anon
                    <!--访问所有文件,authc必须通过验证后才能访问 -->
                    /** = authc
                </value>
            </property>
        </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>
        <!-- Shiro生命周期处理器 -->
        <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

    6.编写spring-mvc.xml文件 注:该文件是管理springmvc的

    <!-- 自动扫描且只扫描@Controller -->
        <context:component-scan base-package="com.lishun"
            use-default-filters="false">
            <context:include-filter type="annotation"
                expression="org.springframework.stereotype.Controller" />
            <context:include-filter type="annotation"
                expression="org.springframework.web.bind.annotation.ControllerAdvice" />
        </context:component-scan>
    
        <!-- 启用SpringMVC的注解功能,它会自动注册HandlerMapping、HandlerAdapter、ExceptionResolver的相关实例 -->
        <mvc:annotation-driven />
    
        <!-- 配置SpringMVC的视图解析器 httl视图 -->
        <bean id="viewResolver" class="httl.web.springmvc.HttlViewResolver">
            <property name="contentType" value="text/html; charset=UTF-8" />
        </bean>
    
        <!-- 在spring-mvc.xml配置文件添加Shiro Spring AOP权限注解的支持: -->
        <aop:config proxy-target-class="true"></aop:config>
        <bean
            class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
            <property name="securityManager" ref="securityManager" />
        </bean>
        <!-- 当前用户没有权限时跳转到的页面: -->
        <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">    
            <property name="exceptionMappings">    
                <props>    
                    <prop key="org.apache.shiro.authz.UnauthorizedException">/users/unauthorizedView</prop>  
                </props>    
            </property>    
        </bean>

    7:编写用户实体(User)和角色实体(Role)

    public class User {
        private String name;
        private String password;
        private Role role;
        @Override
        public String toString() {
            return "User [name=" + name + ", password=" + password + ", role="
                    + role + "]";
        }
        public String getName() {
            return name;
        }
        public User() {
            super();
        }
        public void setName(String name) {
            this.name = name;
        }
        public User(String name, String password) {
            super();
            this.name = name;
            this.password = password;
        }
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public Role getRole() {
            return role;
        }
    
        public void setRole(Role role) {
            this.role = role;
        }
    }
    ---------------------------------------------------分割线
    
    public class Role {
        private String roleName;
        private Set<String> rolePermissions;
        public Set<String> getRolePermissions() {
            return rolePermissions;
        }
        public void setRolePermissions(Set<String> rolePermissions) {
            this.rolePermissions = rolePermissions;
        }
        public String getRoleName() {
            return roleName;
        }
        public void setRoleName(String roleName) {
            this.roleName = roleName;
        }
    }

    8:在httl模板上执行静态函数的类

    /*
     * 在httl模板上可以直接使用的函数
     */
    public class ShiroKit {
        /**
         * 禁止初始化
         */
        private ShiroKit() {
        }
        /**
         * 获取 Subject
         * 
         * @return Subject
         */
        protected static Subject getSubject() {
            return SecurityUtils.getSubject();
        }
        /**
         * 验证当前用户是否拥有指定权限,使用时与lacksPermission 搭配使用
         * 
         * @param permission
         *            权限名
         * @return 拥有权限:true,否则false
         */
        public static boolean hasPermission(String permission) {
            boolean ret = getSubject() != null && permission != null && permission.length() > 0 && getSubject().isPermitted(permission);
            return ret;
        }
    
        /**
         * 与hasPermission标签逻辑相反,当前用户没有制定权限时,验证通过。
         * 
         * @param permission
         *            权限名
         * @return 拥有权限:true,否则false
         */
        public static boolean lacksPermission(String permission) {
            return !hasPermission(permission);
        }
    
    }

    9:自定义用户验证规则(必须继承AuthorizingRealm)

    public class UserRealm extends AuthorizingRealm {
        
    
        @Autowired
        @Qualifier("userDao")
        private UserDao userDao;
        
        
        /*
         * 权限认证
         */
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(
                PrincipalCollection principals) {
            // 根据用户配置用户与权限
            if (principals == null) {
                throw new AuthorizationException(
                        "PrincipalCollection method argument cannot be null.");
            }
            String name = (String) getAvailablePrincipal(principals);
            List<String> roles = new ArrayList<String>();
            User user = userDao.getUserByName(name);
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            // 把当前用户的角色保存到Subject中
            roles.add(user.getRole().getRoleName());
            info.addRoles(roles);
            // 把当前用户的权限保存到Subject中
            info.setStringPermissions(user.getRole().getRolePermissions());
            return info;
        }
    
        /*
         * 登陆认证
         */
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(
                AuthenticationToken authcToken) throws AuthenticationException {
            UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
            //获取页面输入用户名
            String username=(String) token.getPrincipal();
            //从dao层获取该用户
            System.out.println(userDao);
            User user = userDao.getUserByName(username);
            if (user == null) {
                throw new AuthorizationException();
            }
            
            SimpleAuthenticationInfo info = null;
            //存储令牌信息
            if (user.getName().equals(token.getUsername())) {
                info = new SimpleAuthenticationInfo(user.getName(),
                        user.getPassword(), getName());
            }
            return info;
        }
        
    
    }

    10:编写dao层

    /*
     * 这里我就不查询数据数据了,侧重点不在这里,所以写死用户数据
     */
    public class UserDao {
        
        private static List<User> list=new ArrayList<User>();
        private static Set<String> userPermissions=new HashSet<String>();
        private static Set<String> adminPermissions=new HashSet<String>();
        static {
            //lishun普通用户
            User lishun =new User();
            lishun.setName("lishun");
            lishun.setPassword("123");
            Role lishunRole=new Role();
            lishunRole.setRoleName("user");
            //lishun普通用户只拥有一个权限
            userPermissions.add("user:lishun:view");
            lishunRole.setRolePermissions(userPermissions);
            lishun.setRole(lishunRole);
            
            //admin超级用户
            User admin =new User();
            admin.setName("admin");
            admin.setPassword("123");
            Role adminRole=new Role();
            adminRole.setRoleName("admin");
            //admin用户拥有所有权限
            adminPermissions.add("user:lishun:view");
            adminPermissions.add("manager:lishun:view");
            adminRole.setRolePermissions(adminPermissions);
            admin.setRole(adminRole);
            list.add(admin);
            list.add(lishun);
        }
        public User getUserByName(String name){
            for (User u : list) {
                if(u.getName().equals(name)){
                    return u;
                }
            }
            return null;
        }

    11:编写控制器:用户登陆控制器

    //不用任何权限都可以访问该控制器的方法
    @Controller
    public class UserController {
    
        /*
         * 登陆页面
         */
        @RequestMapping(value = "users/index", method = RequestMethod.GET)
        public String index() {
            
            return "users/login";
        }
        /*
         * 验证用户
         */
        @RequestMapping(value = "users/login", method = RequestMethod.POST)
        public String login(String username,String password,Model model){
            //获取到当前用户的的Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            
            String error = null;
            try {
                //验证登陆
                subject.login(token);
            } catch (AuthenticationException e) {
                error = "warning message:Login failed,please check your username and password"; 
                model.addAttribute("errorMessage", error);
            }
            if (error==null) {        
                return "redirect:../index/index";
            } else {
                return "redirect:index";
            }
        }
        /*
         * 没有权限后跳转的页面
         */
        @RequestMapping(value = "users/unauthorizedView", method = RequestMethod.GET)
        public String unauthorizedView() {
            return "users/unauthorizedView";
        }
    }

    12:login.httl文件

    <!--#set(String msg="httl模板测试") -->
    <!--#set(String manageHost = request.getScheme()+"://"+request.serverName+":"+"a".valueOf(request.serverPort)+request.getContextPath())-->
    
    <html>
    <body>
        <form action="${manageHost}/users/login" method="post">
            <label style="color: red">${errorMessage}</label>
            <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>
                <tr>
                    <td colspan="2"><input type="submit" value="Login" />
                    </td>
                </tr>
            </table>
        </form>
    </body>
    </html> 
    -----------------------分隔符

    至于httl的语法大家可以去官网上浏览,我这里就不多说,http://httl.github.io/zh/syntax.html

        打开url:http://localhost:8080/SpringMvc-Httl-shiro/users/login

    就可以浏览了

    13 编写控制器:用户主页控制器

    @Controller
    public class IndexController {
        
        /*
         * 普通用户就可以访问该页面
         */
        @RequiresPermissions("user:lishun:view")
        @RequestMapping(value = "index/index", method = RequestMethod.GET)
        public String index() {
            System.out.println(SecurityUtils.getSubject().isPermitted("user:lishun:view"));
            return "index/index";
        }
    }
    -------------------------------------------分割线

    用户主页模板index.httl

    <!--#set(String msg="httl模板测试") -->
    <!--#set(String manageHost = request.getScheme()+"://"+request.serverName+":"+"a".valueOf(request.serverPort)+request.getContextPath())-->
    
    <html>
    <body>
        #if(hasPermission("manager:lishun:view"))
            超级用户登陆
            <a href="${manageHost}/manager/user">管理用户</a>
        #else(hasPermission("user:lishun:view"))
            普通用户登陆
        #end
    </body>
    </html>

    14 编写控制器:管理员控制器

    @Controller
    @RequestMapping("manager")
    public class ManagerController {
    
        /*
         * 只有管理员才有权限查看本页面
         */
        @RequiresPermissions("manager:lishun:view")
        @RequestMapping(value = "/user", method = RequestMethod.GET)
        public String index() {
            
            return "manager/userManager";
        }
        
    }
    -------------------------------------------分割线

    管理用户模板userManager.httl

    <!--#set(String msg="httl模板测试") -->
    <!--#set(String manageHost = request.getScheme()+"://"+request.serverName+":"+"a".valueOf(request.serverPort)+request.getContextPath())-->
    
    <html>
    <body>
        <h1>只有admin角色才可以访问</h1>
    </body>
    </html>

    当你是普通用户访问该页面时因没有权限而跳转到无权限页面

     由于本人水平有限,若文章在表述和代码方面如有不妥之处,欢迎批评指正。留下你的脚印,欢迎评论!希望能互相学习。需要源码的留下邮箱

    最后附上项目的目录结构

  • 相关阅读:
    模拟打车
    atm转账
    python字符串,列表,字典,集合的常用方法
    while和for的简单使用
    数据库的基本命令
    jmeter监控linux的性能
    jmeter的错误解决Cannot create PoolableConnectionFactory (Access denied for user 'root'@'localhost' (using password: YES))
    jmeter的正则参数化
    jmeter的参数化关联
    使用Python解析JSON
  • 原文地址:https://www.cnblogs.com/lishun1005/p/4581146.html
Copyright © 2020-2023  润新知