Spring集成Shiro HelloWorld之初步实现登陆及验证

来源:互联网 发布:星际淘宝网笔下 编辑:程序博客网 时间:2024/05/21 18:41

    • 加入相关jar包
    • 在webxml中进行相关配置
      • 配置Spring的Listener
      • 配置由Spring委托接管Shiro的Filter
      • 配置SpringMVC的DispatcherServlet
    • 配置Spring的applicationContextxml文件
    • 配置SpringMVC的springDispatcherServlet-servletxml
    • 编写SpringMVC处理请求的Handler类

今天抽空复习了一下Shiro这个权限框架与Spring的集成, 顺便写了个HelloWorld例子, 作为个人笔记记录同时也提供给需要的朋友参考.

加入相关jar包

加入相关jar包 见脚注: 1
Shiro版本: shiro-root-1.2.2-source-release
Spring版本: spring-framework-4.0.0.RELEASE-dist

在web.xml中进行相关配置

配置Spring的Listener

<!-- needed for ContextLoaderListener --><context-param>    <param-name>contextConfigLocation</param-name>    <param-value>classpath:applicationContext.xml</param-value></context-param><!-- Bootstraps the root web application context before servlet initialization --><listener>    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>

配置由Spring委托接管Shiro的Filter

Filter配置可以从Shiro的源码中下的shiro-root-1.2.2-source-release\shiro-root-1.2.2\samples\spring\src\main\webapp\WEB-INF下的web.xml中找到.

<filter>    <filter-name>shiroFilter</filter-name>    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>    <init-param>        <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的DispatcherServlet

    <!-- The front controller of this Spring Web application        这个Spring WEB应用的前端控制器,         responsible for handling all application requests        负责处理所有应用请求.    -->    <!-- 配置SpringMVC的DispatcherServlet -->    <servlet>        <servlet-name>springDispatcherServlet</servlet-name>        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>        <load-on-startup>1</load-on-startup>    </servlet>    <!--         Map all requests to the DispatcherServlet for handling        将所有请求映射给DispatcherServlet以便处理.    -->    <servlet-mapping>        <servlet-name>springDispatcherServlet</servlet-name>        <url-pattern>/</url-pattern>    </servlet-mapping>

配置Spring的applicationContext.xml文件

从shiro-root-1.2.2-source-release\shiro-root-1.2.2\samples\spring\src\main\webapp\WEB-INF下的applicationContext.xml找到相关配置.

  1. 配置SecurityManager

     <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">     <property name="cacheManager" ref="cacheManager"/>     <!-- 配置自定义的Realm -->     <property name="realm" ref="realm"/> </bean>

    配置securityManager中引用的CacheManager和自定义的Realm, cacheManager和realm要配置在securityManager的代码上方.

    1. 配置自定义的Realm, 来让上面的SecurityManager引用管理

      <bean id="realm" class="com.al0n4k.shiro.helloworld.reaml.MyRealm"></bean>

      我们需要新建一个类来继承类实现其中的授权和验证方法

      package com.al0n4k.shiro.helloworld.reaml;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.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;/** * @author AL0n4k * AuthorizingRealm继承自AuthencatingRealm类. */public class MyRealm extends AuthorizingRealm{    /**     * 该方法继承自 AuthorizingRealm抽象类(用于授权的Realm)     */    @Override    protected AuthorizationInfo doGetAuthorizationInfo(            PrincipalCollection principals) {        return null;    }    /**     * 该方法继承自 AuthencatingRealm抽象类(用于认证的Realm)     */    @Override    protected AuthenticationInfo doGetAuthenticationInfo(            AuthenticationToken token1) throws AuthenticationException {        UsernamePasswordToken token = (UsernamePasswordToken) token1;        /**从token中获取username, 然后根据username从数据中读取指定的密码.         * 之后使用从数据库中查询出的账号密码信息创建SimpleAuthenticationInfo,          * 然后将这个对象返回时, shiro内部会帮我们跟token中username和password进行对比判断是否成功登陆!         参考Shiro方法实现: org.apache.shiro.authc.credential.SimpleCredentialsMatcher.doCredentialsMatch(AuthenticationToken, AuthenticationInfo)         具体到底层比较的算法是:         // 将token中的密码和Credentials中的密码转成byte数组进行比较          public static boolean equals(byte[] a, byte[] a2) {                先比较引用值, 如果内存引用值一样, 返回true                if (a==a2)                    return true;                    如果其中一个为null返回false                if (a==null || a2==null)                    return false;                // 否则获取两个的长度进行对比, 如果长度不一样, 返回false.                int length = a.length;                if (a2.length != length)                    return false;                // 否则长度一样的话, 就比较每一个字符是否一样.                      for (int i=0; i<length; i++)                    if (a[i] != a2[i])                        return false;                return true;}         * */        String username = token.getUsername();        // 模拟查询数据库        System.out.println("从数据中根据用户名查询密码");        /**         * 如果从数据库中找不到用户名, 那么直接返回null.         * 否则就创建SimpleAuthenticationInfo对象来将从数据库中读取到的账号密码封装为pricipal(当前登录负责人)和credentials(凭证)         * 但我们这里因为是简单的helloworld就默认将请求中的username和password设置到这个对象的构造器参数中.         * 如果返回null, 那么shiro框架则认为从token中根据username找不到对应的账号,参见Shiro实现方法: org.apache.shiro.authc.pam.ModularRealmAuthenticator.doSingleRealmAuthentication(Realm, AuthenticationToken)        Object principal = username;        Object credentials = "1234";        String realmName = getName();        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(principal, credentials, realmName);        return info;    }}
    2. 配置缓存

      <!-- 配置缓存. --><bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">    <property name="cacheManagerConfigFile" value="classpath:ehcache.xml" /></bean>
  2. 配置Spring提供的可以自动调用Shiro对象的init()和destroy()方法的beanProcessor

    <!-- 配置可以自动调用Shiro对象的init()和destroy()方法 --><bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" /><!-- Enable Shiro Annotations for Spring-configured beans.  Only run after the lifecycleBeanProcessor has run:开启Shiro的注解在Spring已经配置的bean对象上, 但需要在LifecycleBeanPostProcessor这个bean已经配置的情况下才可以运行--><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>
  3. 配置ShiroFilter

    <!-- 配置Shiro的Filter, 来拦截资源的请求. --><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">    <property name="securityManager" ref="securityManager" />    <!-- 配置登陆页面 -->    <property name="loginUrl" value="login.jsp" />    <!-- 配置未授权的页面 -->    <property name="unauthorizedUrl" value="unauthorized.jsp" />    <!-- 配置过滤器链定义 格式: 资源地址 = 访问的需要的权限 -->    <property name="filterChainDefinitions">        <value>            /favicon.ico = anon            /logo.png = anon            /shiro.css = anon            /s/login =            anon            # allow WebStart to pull the jars for the swing app:            /*.jar =            anon            # everything else requires authentication:            /** = authc        </value>    </property></bean>

    ShiroFilter的过滤书写格式
    ShiroFilter的过滤书写格式

配置SpringMVC的springDispatcherServlet-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:util="http://www.springframework.org/schema/util"    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-4.0.xsd        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">    <!-- 配置需要让SpringMVC自动扫描的包 -->    <context:component-scan base-package="com.al0n4k.shiro.helloworld.reaml"></context:component-scan>    <!-- 配置Spring提供的内部视图解析器 -->    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">        <property name="prefix" value="/"></property>        <property name="suffix" value=".jsp"></property>    </bean>    <!-- 配置SpringMVC的注解驱动 -->    <mvc:annotation-driven></mvc:annotation-driven>    <!--         配置默认的Servlet处理器        Configures a handler for serving static resources by forwarding to the Servlet container's default         Servlet. Use of this handler allows using a "/" mapping with the DispatcherServlet while still         utilizing the Servlet container to serve static resources. This handler will forward all requests         to the default Servlet. Therefore it is important that it remains last in the order of all other         URL HandlerMappings. That will be the case if you use the "annotation-driven" element or         alternatively if you are setting up your customized HandlerMapping instance be sure to set its         "order" property to a value lower than that of the DefaultServletHttpRequestHandler, which is         Integer.MAX_VALUE.    -->    <mvc:default-servlet-handler/></beans>

编写SpringMVC处理请求的Handler类

package com.al0n4k.shiro.helloworld.handler;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.mgt.SubjectFactory;import org.apache.shiro.subject.Subject;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;/** * @author AL0n4k */@Controllerpublic class ShiroHandler {    @RequestMapping( "/login" )    public String login(@RequestParam( "username" )    String username, @RequestParam( "password" )    String password) {        Subject currentUser = SecurityUtils.getSubject();        Class<? extends Subject> class1 = currentUser.getClass();        System.out.println(class1);        if (!currentUser.isAuthenticated()) {            UsernamePasswordToken token = new UsernamePasswordToken(username,                    password);            //token.setRememberMe(true);            try {                // login方法会帮我们判断账号是否为空, 如果为空则抛出IllegalStateException异常.                currentUser.login(token);            } catch ( AuthenticationException e ) { // 该异常是指验证token是否为null时 token为null.                System.out.println("验证账号密码时不匹配, 登陆失败!");                return "forward:/failure.jsp";            }         }        return "success";    }}

  1. 一般直接把shiro自带和spring下required文件夹中的jar包都加入即可.
    com.springsource.net.sf.cglib-2.2.0.jar
    com.springsource.org.aopalliance-1.0.0.jar
    com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
    commons-logging-1.1.3.jar
    ehcache-core-2.4.3.jar Shiro的源码包中不自带这个包,需要手动找到添加至项目.
    log4j-1.2.15.jar
    shiro-aspectj-1.2.2.jar
    shiro-cas-1.2.2.jar
    shiro-core-1.2.2.jar
    shiro-ehcache-1.2.2.jar
    shiro-guice-1.2.2.jar
    shiro-quartz-1.2.2.jar
    shiro-spring-1.2.2.jar
    shiro-tools-hasher-1.2.2-cli.jar
    shiro-web-1.2.2.jar
    slf4j-api-1.6.1.jar
    slf4j-log4j12-1.6.1.jar
    spring-aop-4.0.0.RELEASE.jar
    spring-aspects-4.0.0.RELEASE.jar
    spring-beans-4.0.0.RELEASE.jar
    spring-context-4.0.0.RELEASE.jar
    spring-core-4.0.0.RELEASE.jar
    spring-expression-4.0.0.RELEASE.jar
    spring-jdbc-4.0.0.RELEASE.jar
    spring-orm-4.0.0.RELEASE.jar
    spring-tx-4.0.0.RELEASE.jar
    spring-web-4.0.0.RELEASE.jar
    spring-webmvc-4.0.0.RELEASE.jar
0 0
原创粉丝点击