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项目

SpringMvc-Httl-shiro的整合

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

就可以浏览了

SpringMvc-Httl-shiro的整合

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>

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

SpringMvc-Httl-shiro的整合

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

最后附上项目的目录结构

SpringMvc-Httl-shiro的整合

SpringMvc-Httl-shiro的整合

 

你可能感兴趣的:(springMVC)