Spring 自带内存缓存配置,校验密码输入次数锁定账户10分钟(一)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_18808965/article/details/82319621

1、beans 配置

<?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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
          http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
" default-lazy-init="true">
	 <!-- 安全管理器 -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="myRealm"/>
    	<!-- 使用下面配置的缓存管理器 -->
        <property name="cacheManager" ref="cacheManager"/>
    </bean>
    
    <!-- 凭证匹配器 -->
	<bean id="credentialsMatcher" class="com.etop.shiro.RetryLimitCredentialsMatcher">
		<constructor-arg index="0" ref="cacheManager" />
		<constructor-arg index="1" value="2" />
		<property name="hashAlgorithmName" value="md5" />
		<property name="hashIterations" value="0" />
		<property name="storedCredentialsHexEncoded" value="true"/>
	</bean>
    <!--自定义Realm-->
    <bean id="myRealm" class="com.etop.shiro.MyRealm">
    	<property name="credentialsMatcher" ref="credentialsMatcher"/>  
        <property name="cachingEnabled" value="false"/> 
	</bean>
    <!-- 配置shiro的过滤器工厂类,id- shiroFilter要和我们在web.xml中配置的过滤器一致 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <!-- 调用我们配置的权限管理器 -->
        <property name="securityManager" ref="securityManager"/>
        <!-- 配置我们的登录请求地址 -->
        <property name="loginUrl" value="/login.html"/>
        <!-- 配置我们在登录页登录成功后的跳转地址,如果你访问的是非/login地址,则跳到您访问的地址 -->
        <property name="successUrl" value="/user.html"/>
        <!-- 如果您请求的资源不再您的权限范围,则跳转到/403请求地址 -->
        <property name="unauthorizedUrl" value="/403.html"/>
        <!-- 权限配置 拦截表单进行认证和授权,通过才走controller,注释后:请求先进过controller再认证和授权-->
        <!-- <property name="filterChainDefinitionMap" ref="chainDefinitionSectionMetaSource"/> -->
    </bean>
    
    <!--自定义filterChainDefinitionMap-->
    <!-- <bean id="chainDefinitionSectionMetaSource" class="com.etop.shiro.ChainDefinitionSectionMetaSource"/> -->
    <!--shiro缓存管理器,用户授权信息Cache,缓存在本机内存,不支持集群-->
    <bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager"/>
    <!-- Shiro生命周期处理器--> 
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    <bean id="propertyConfigurer"
          class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations" value="classpath:jdbc.properties"/>
    </bean>

    <!--hibernate session工厂设置-->
    <bean id="sessionFactory"
          class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="packagesToScan">
            <list>
                <value>com.etop.pojo</value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
                <prop key="hibernate.generate_statistics">false</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.format_sql">false</prop>
                <prop key="hibernate.jdbc.batch_size">50</prop>
                <prop key="jdbc.use_scrollable_resultset">false</prop>
                <prop key="javax.persistence.validation.mode">none</prop>
                <prop key="hibernate.cache.use_second_level_cache">true</prop>
                <prop key="hibernate.cache.use_query_cache">true</prop>
                <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
                <prop key="jdbc.use_scrollable_resultset">false</prop>
            </props>
        </property>
    </bean>

    <!-- c3p0 configuration -->
    <bean id="mainDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
        <property name="driverClass" value="${jdbc.driverClass}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="minPoolSize" value="${jdbc.minPoolSize}"/>
        <property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>
        <property name="checkoutTimeout" value="${jdbc.checkoutTimeout}"/>
        <property name="maxStatements" value="${jdbc.maxStatements}"/>
        <property name="testConnectionOnCheckin" value="${jdbc.testConnectionOnCheckin}"/>
        <property name="idleConnectionTestPeriod" value="${jdbc.idleConnectionTestPeriod}"/>
    </bean>

    <bean id="dataSource"
          class="org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy">
        <property name="targetDataSource">
            <ref bean="mainDataSource"/>
        </property>
    </bean>
    <context:annotation-config/>
    <context:component-scan base-package="com.etop">
        <context:exclude-filter type="regex" expression="com.cn.controller.*"/>
    </context:component-scan>

    <bean id="transactionManager"
          class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref bean="sessionFactory"/>
        </property>
    </bean>

    <!-- 拦截配置 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--说明事务类别 -->
            <tx:method name="delete*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
            <tx:method name="save*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
            <tx:method name="add*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
            <tx:method name="update*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
            <tx:method name="batch*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
            <tx:method name="sendOpen*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
            <tx:method name="sendClose*" propagation="REQUIRED" read-only="false" rollback-for="java.lang.Exception"/>
            <tx:method name="find*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="get*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="load*" propagation="REQUIRED" read-only="true"/>
            <tx:method name="*" read-only="true"/>
        </tx:attributes>
    </tx:advice>

    <!-- 切入点 -->
    <aop:config expose-proxy="true" proxy-target-class="true">
        <!-- service层事务 -->
        <aop:advisor id="serviceTx" advice-ref="txAdvice"
                     pointcut="execution(public * com.etop.service.*.*(..))" order="1"/>
    </aop:config>

    <tx:annotation-driven/>

</beans>

RetryLimitCredentialsMatcher.java

package com.etop.shiro;

import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
 
import java.util.concurrent.atomic.AtomicInteger;
 
/**
 * 验证器,增加了登录次数校验功能
 */
@SuppressWarnings("unused")
public class RetryLimitCredentialsMatcher extends HashedCredentialsMatcher {
    private static final Logger log = LoggerFactory.getLogger(RetryLimitCredentialsMatcher.class);
 
    //集群中可能会导致出现验证多过5次的现象,因为AtomicInteger只能保证单节点并发
    private Cache<String, AtomicInteger> lgoinRetryCache;
 
	private int maxRetryCount = 2;
 
    private String lgoinRetryCacheName;
 
    public void setMaxRetryCount(int maxRetryCount) {
        this.maxRetryCount = maxRetryCount;
        
    }
 
    public RetryLimitCredentialsMatcher(CacheManager cacheManager,String lgoinRetryCacheName) {
        this.lgoinRetryCacheName = lgoinRetryCacheName;
        lgoinRetryCache = cacheManager.getCache(lgoinRetryCacheName);
    }
 
    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        String username = (String) token.getPrincipal();
        //retry count + 1
        AtomicInteger retryCount = lgoinRetryCache.get(username);
        if (null == retryCount) {
            retryCount = new AtomicInteger(0);
            lgoinRetryCache.put(username, retryCount);
        }
        if (retryCount.incrementAndGet() > 2) {
            log.warn("username: " + username + " tried to login more than 5 times in period");
            log.info("username: " + username + " 试图在一段时间内登录超过2次,当前登录次数:{}",retryCount);
            throw new ExcessiveAttemptsException("username: " + username + " tried to login more than 5 times in period"
            );
        }
        boolean matches = super.doCredentialsMatch(token, info);
        if (matches) {
            //clear retry data
            lgoinRetryCache.remove(username);
        }
        return matches;
    }
}

猜你喜欢

转载自blog.csdn.net/qq_18808965/article/details/82319621
今日推荐