版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/c_royi/article/details/82015039
Springboot(2.0)整合shiro 配置EnCache,remember me和密码校验次数
配置时,请先阅读springboot整合shiro文章,
项目github地址:https://github.com/Plumblumpb/springboot-2.0–shiro.git
encache
由于每次的授权shiro都会重新范围数据库,导致查询频繁所以使用EnCache进行缓存
重点:记得将要缓存的类序列化
1.1配置maven
<!--cache-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--EhCache作为缓存-->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
1.2配置shirConfig
@Bean
public EhCacheManager ehCacheManager(){
EhCacheManager cacheManager = new EhCacheManager();
cacheManager.setCacheManagerConfigFile("classpath:config/ehcache.xml");
return cacheManager;
}
@Bean
public SecurityManager securityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//设置Realm,用于获取认证凭证
securityManager.setRealm(userRealm());
//注入缓存管理器
securityManager.setCacheManager(ehCacheManager());
//注入Cookie(记住我)管理器(remenberMeManager)
securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
1.3配置EnCached.xml
(具体看github,这个不全)
<!-- 登录记录缓存 -->
<cache name="passwordRetryCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="600"
timeToLiveSeconds="0"
overflowToDisk="false"
statistics="true">
</cache>
remember me
1.1配置shiroConfig
@Bean
public SimpleCookie rememberMeCookie(){
//这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
//如果httyOnly设置为true,则客户端不会暴露给客户端脚本代码,使用HttpOnly cookie有助于减少某些类型的跨站点脚本攻击;
simpleCookie.setHttpOnly(true);
//记住我cookie生效时间,默认30天 ,单位秒:60 * 60 * 24 * 30
simpleCookie.setMaxAge(259200);
return simpleCookie;
}
/**
* cookie管理器;
* @return
*/
@Bean
public CookieRememberMeManager rememberMeManager(){
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
//rememberme cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位),通过以下代码可以获取
//KeyGenerator keygen = KeyGenerator.getInstance("AES");
//SecretKey deskey = keygen.generateKey();
//System.out.println(Base64.encodeToString(deskey.getEncoded()));
byte[] cipherKey = Base64.decode("wGiHplamyXlVB11UXWol8g==");
cookieRememberMeManager.setCipherKey(cipherKey);
cookieRememberMeManager.setCookie(rememberMeCookie());
return cookieRememberMeManager;
}
并加入securityManager
1.2配置Controller
密码校验次数
1.2配置RetryLimitCredentialsMatcher
继承HashedCredentialsMatcher,并修改密码验证的流程
/**
* @Auther: cpb
* @Date: 2018/8/14 11:09
* @Description:
*/
public class RetryLimitCredentialsMatcher extends HashedCredentialsMatcher {
private static final Logger logger = LoggerFactory.getLogger(RetryLimitCredentialsMatcher.class);
//集群中可能会导致出现验证多过5次的现象,因为AtomicInteger只能保证单节点并发
private Cache<String,AtomicInteger> passwordRetryCache;
//最大校验次数。
private int maxRetryCount = 3;
public RetryLimitCredentialsMatcher(CacheManager cacheManager) {
passwordRetryCache = cacheManager.getCache("passwordRetryCache");
}
@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
String username = (String) token.getPrincipal();
//retry count + 1
AtomicInteger retryCount = passwordRetryCache.get(username);
if (null == retryCount) {
retryCount = new AtomicInteger(0);
passwordRetryCache.put(username, retryCount);
}
if (retryCount.incrementAndGet() > 3) {
logger.warn("用户: " + username + " tried to login more than 3 times in period");
throw new ExcessiveAttemptsException("用户名: " + username + " tried to login more than 3 times in period"
);
}
boolean matches = super.doCredentialsMatch(token, info);
if (matches) {
//clear retry data
passwordRetryCache.remove(username);
}
return matches;
}
}
1.2配置shiroConfig
/**
* 凭证匹配器
* (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了
* )
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
// HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
HashedCredentialsMatcher hashedCredentialsMatcher = new RetryLimitCredentialsMatcher(ehCacheManager());
hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法;
hashedCredentialsMatcher.setHashIterations(2);//散列的次数,比如散列两次,相当于 md5(md5(""));
return hashedCredentialsMatcher;
}