版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}
}