shiro整合spring

本文是对CSDN开涛大神的shiro教程第十二章——shiro整合spring的一个整理。
Shiro是最近非常流行的安全框架,比spring security要简单一些,轻量一些。但其功能相当强大,不仅提供权限管理、还集成了单点登录、分布式session等等。
下面是shiro和spring的整合流程。
一般来说权限管理系统可以设计5张表,user表,role表,permission表,他们两两之间分别是一对多的关系,即一个用户可以拥有多个角色,一个角色可以拥有多个权限。因此还需建立user_role_relation表和role_permission
表。
SSM整合shiro首先把这五张表的dao层写好。用户量较小时,可以使用spring JDBCTemplate写dao层。
shiro提供了SimpleHash,他是一个加密工具,使用起来非常方便。

    private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();
    private String algorithmName = "md5";
    private int hashIterations = 2;

  public void encryptPassword(User user) {

        user.setSalt(randomNumberGenerator.nextBytes().toHex());
/*
shiro提供的simpleHash,分别赋值加密算法、密码、盐、加密循环次数。并转为16进制返回。
 */
        String newPassword = new SimpleHash(
                algorithmName,
                user.getPassword(),
                //CredentialsSalt在实体类中由username+salt构成
                ByteSource.Util.bytes(user.getCredentialsSalt()),
                hashIterations).toHex();

        user.setPassword(newPassword);
    }

SimpleHash构造函数里有五个参数,分别是算法名称(这里使用的MD5),加密数据,盐,加密循环次数。这样我们在service层插入用户时,就可以使用这个encryptPassword方法将用户密码加密后插入DB了。至于service层无非也是调用dao做一些CURD的操作,不做一一阐述了。重点是下面的Realm

 @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        /**
        *@Author hfismyangel@163.com
        *@Description:
         * 保存登陆成功后的信息
        *@Date: 8:46 2017/8/18
           * @param principals
        */
        String username = (String)principals.getPrimaryPrincipal();
        //简单授权信息,保存用户登录状态
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(userService.findRoles(username));
        authorizationInfo.setStringPermissions(userService.findPermissions(username));

        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        /**
        *@Author hfismyangel@163.com
        *@Description:
         * 验证是否能登录
        *@Date: 8:47 2017/8/18
           * @param token
        */
        //直接从token里拿用户名
        String username = (String)token.getPrincipal();

        User user = userService.findByUsername(username);

        if(user == null) {
            throw new UnknownAccountException();//没找到帐号
        }

        if(Boolean.TRUE.equals(user.getLocked())) {
            throw new LockedAccountException(); //帐号锁定
        }

        //交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                user.getUsername(), //用户名
                user.getPassword(), //密码
                ByteSource.Util.bytes(user.getCredentialsSalt()),//salt=username+salt
                getName()  //realm name
        );
        return authenticationInfo;
    }

这个Realm可以理解为对于是否登录/拥有权限做逻辑判断的一层。首先自定义一个类,继承Shiro的AuthorizingRealm父类。重写doGetAuthorizationInfo和doGetAuthenticationInfo方法即可,注意两个方法互为重载方法。一个是用于保存登陆成功后的信息,一个是用于判断是否登录。
注意第二个doGetAuthorizationInfo方法里调用的token.getPrincipal()方法,是直接从token中拿到用户名,而第一个doGetAuthorizationInfo方法里token.getPrincipal()是从PrincipalCollection通过遍历器拿到第一个用户名,PrincipalCollection 是个身份集合,保存各种身份信息,具体实现可以看源码。
最简单的代码配置就到此为止,再配置一下spring-shiro.xml的配置文件,在web.xml里配置一个shiro的过滤器就可以进行测试了。
下面是shiro与srpring整合的配置文件,原文注释写的比较清晰,不作解释了。另外最好根据这个shiro流程图来理解。
shiro工作流程

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:util="http://www.springframework.org/schema/util"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
    <!--dao层、passwordHelper类、与shiro-web无关-->

    <!-- 缓存管理器 使用Ehcache实现 -->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
        <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
    </bean>

    <!-- 凭证匹配器 ,用于管理密码重试次数-->
    <bean id="credentialsMatcher"
          class="com.github.zhangkaitao.shiro.chapter12.credentials.RetryLimitHashedCredentialsMatcher">
        <constructor-arg ref="cacheManager"/>
        <property name="hashAlgorithmName" value="md5"/>
        <property name="hashIterations" value="2"/>
        <property name="storedCredentialsHexEncoded" value="true"/>
    </bean>

    <!-- Realm实现,包含两部分AuthenticationToken和AuthenticationInfo-->
    <bean id="userRealm" class="com.github.zhangkaitao.shiro.chapter12.realm.UserRealm">
        <property name="userService" ref="userService"/>
        <property name="credentialsMatcher" ref="credentialsMatcher"/>
        <property name="cachingEnabled" value="true"/>
        <property name="authenticationCachingEnabled" value="true"/>
        <property name="authenticationCacheName" value="authenticationCache"/>
        <property name="authorizationCachingEnabled" value="true"/>
        <property name="authorizationCacheName" value="authorizationCache"/>
    </bean>

    <!-- 会话ID生成器,指定使用uuid生成-->
    <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/>

    <!-- 会话Cookie模板 -->
    <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
        <constructor-arg value="sid"/>
        <property name="httpOnly" value="true"/>
        <property name="maxAge" value="180000"/>
    </bean>

    <!-- 会话DAO,管理session。
    shiro的session都是存在缓存中的,所有会有一个sessionDAO的类EnterpriseCacheSessionDAO来做CRUD操作-->
    <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO">
        <property name="activeSessionsCacheName" value="shiro-activeSessionCache"/>
        <property name="sessionIdGenerator" ref="sessionIdGenerator"/>
    </bean>

    <!-- 会话验证调度器 -->
    <!--shiro提供了会话验证调度器,用于定期的验证会话是否已过期,如果过期将停止会话;出于性能考虑,
    一般情况下都是获取会话时来验证会话是否过期并停止会话的;但是如在web环境中,如果用户不主动退出是不知道会话是否过期的,
    因此需要定期的检测会话是否过期,Shiro提供了会话验证调度器SessionValidationScheduler。-->
    <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler">
        <!--设置调度时间间隔,单位毫秒,默认是1小时-->
        <property name="sessionValidationInterval" value="1800000"/>
        <property name="sessionManager" ref="sessionManager"/>
    </bean>
    <!--==============================================================================================================-->
    <!-- 会话管理器 -->
    <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
        <property name="globalSessionTimeout" value="1800000"/>
        <property name="deleteInvalidSessions" value="true"/>
        <property name="sessionValidationSchedulerEnabled" value="true"/>
        <property name="sessionValidationScheduler" ref="sessionValidationScheduler"/>
        <property name="sessionDAO" ref="sessionDAO"/>
        <property name="sessionIdCookieEnabled" value="true"/>
        <!--存储sessionID的jsessionId-->
        <property name="sessionIdCookie" ref="sessionIdCookie"/>
    </bean>


    <!-- 安全管理器,安全框架的核心组件,统筹realm/sessionManager/cache-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="userRealm"/>
        <property name="sessionManager" ref="sessionManager"/>
        <property name="cacheManager" ref="cacheManager"/>
    </bean>

    <!-- 通过MethodInvokingFactoryBean工厂Bean,可以将指定方法返回值注入成为目标Bean的属性值。
     将SecurityUtils的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"/>

    <!--==============================================================================================================-->


    <!-- 基于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="/login.jsp"/>
    </bean>

    <!-- Shiro的Web过滤器 -->
    <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="filters">
            <util:map>
                <!--拦截表单,通过认证才能登录-->
                <entry key="authc" value-ref="formAuthenticationFilter"/>
            </util:map>
        </property>
        <property name="filterChainDefinitions">
            <!--
        ①[urls]部分的配置,其格式为:url=拦截器[参数],拦截器[参数]。
     ②如果当前请求的url匹配[urls]部分的某个url模式,将会执行器配置的拦截器。
     ③anon(anonymous)拦截器表示可以匿名访问。
     ④authc(authencation)拦截器标识需要身份认证通过后才能访问。
     ⑤logout(logout)拦截器表示登出/退出登录,它会清空shiro缓存信息。
        ⑥url模式使用 Ant 风格模式:
          [1]?匹配一个字符;
          [2]*匹配零个或多个字符;
          [3]**匹配路径中的零个或多个路径;-->
            <value>
                /index.jsp = anon
                /unauthorized.jsp = anon
                /login.jsp = authc
                /logout = logout
                /** = user
            </value>
        </property>
    </bean>



</beans>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值