怎么读取shiro的ehcache shiro.xml缓存

你的位置: >
> Shiro 缓存机制
,我的理解是:让数据更接近于使用者;工作机制是:先从缓存中读取数据,如果没有再从慢速设备上读取实际数据(数据也会存入缓存);缓存什么:那些经常读取且不经常修改的数据/那些昂贵(CPU/IO)的且对于相同的请求有相同的计算结果的数据。如CPU&#–内存–磁盘就是一个典型的例子,CPU需要数据时先从L1/L2中读取,如果没有到内存中找,如果还没有会到磁盘上找。还有如用过的朋友都应该知道,我们找依赖的时候,先从本机仓库找,再从本地服务器仓库找,最后到远程仓库服务器找;还有如京东的物流为什么那么快?他们在各个地都有分仓库,如果该仓库有货物那么送货的速度是非常快的。
Shiro提供了类似于的Cache抽象,即Shiro本身不实现Cache,但是对Cache进行了又抽象,方便更换不同的底层Cache实现。
Shiro提供的Cache接口
public interface Cache&K, V& {
//根据Key获取缓存中的值
public V get(K key) throws CacheE
//往缓存中放入key-value,返回缓存中之前的值
public V put(K key, V value) throws CacheE
//移除缓存中key对应的值,返回该值
public V remove(K key) throws CacheE
//清空整个缓存
public void clear() throws CacheE
//返回缓存大小
public int size();
//获取缓存中所有的key
public Set&K& keys();
//获取缓存中所有的value
public Collection&V& values();
Shiro提供的CacheManager接口
public interface CacheManager {
//根据缓存名字获取一个Cache
public &K, V& Cache&K, V& getCache(String name) throws CacheE
Shiro还提供了CacheManagerAware用于注入CacheManager
public interface CacheManagerAware {
//注入CacheManager
void setCacheManager(CacheManager cacheManager);
Shiro内部相应的组件(DefaultSecurityManager)会自动检测相应的对象(如Realm)是否实现了CacheManagerAware并自动注入相应的CacheManager。
Shiro提供了CachingRealm,其实现了CacheManagerAware接口,提供了缓存的一些基础实现;另外AuthenticatingRealm及AuthorizingRealm分别提供了对AuthenticationInfo 和AuthorizationInfo信息的缓存。ini配置 代码如下:
userRealm=com.xttblog.shiro10.realm.UserRealm
userRealm.credentialsMatcher=$credentialsMatcher
userRealm.cachingEnabled=true
userRealm.authenticationCachingEnabled=true
userRealm.authenticationCacheName=authenticationCache
userRealm.authorizationCachingEnabled=true
userRealm.authorizationCacheName=authorizationCache
securityManager.realms=$userRealm
cacheManager=org.apache.shiro.cache.ehcache.EhCacheManager
cacheManager.cacheManagerConfigFile=classpath:shiro-ehcache.xml
securityManager.cacheManager=$cacheManager
userRealm.cachingEnabled:启用缓存,默认false;
userRealm.authenticationCachingEnabled:启用身份验证缓存,即缓存AuthenticationInfo信息,默认false;
userRealm.authenticationCacheName:缓存AuthenticationInfo信息的缓存名称;
userRealm. authorizationCachingEnabled:启用授权缓存,即缓存AuthorizationInfo信息,默认false;
userRealm. authorizationCacheName:缓存AuthorizationInfo信息的缓存名称;
cacheManager:缓存管理器,此处使用EhCacheManager,即Ehcache实现,需要导入相应的Ehcache依赖
测试用例代码如下:
public void testClearCachedAuthenticationInfo() {
login(u1.getUsername(), password);
userService.changePassword(u1.getId(), password + &1&);
RealmSecurityManager securityManager =
(RealmSecurityManager) SecurityUtils.getSecurityManager();
UserRealm userRealm = (UserRealm) securityManager.getRealms().iterator().next();
userRealm.clearCachedAuthenticationInfo(subject().getPrincipals());
login(u1.getUsername(), password + &1&);
首先登录成功(此时会缓存相应的AuthenticationInfo),然后修改密码;此时密码就变了;接着需要调用Realm的clearCachedAuthenticationInfo方法清空之前缓存的AuthenticationInfo;否则下次登录时还会获取到修改密码之前的那个AuthenticationInfo;
public void testClearCachedAuthorizationInfo() {
login(u1.getUsername(), password);
subject().checkRole(r1.getRole());
userService.correlationRoles(u1.getId(), r2.getId());
RealmSecurityManager securityManager =
(RealmSecurityManager) SecurityUtils.getSecurityManager();
UserRealm userRealm = (UserRealm)securityManager.getRealms().iterator().next();
userRealm.clearCachedAuthorizationInfo(subject().getPrincipals());
subject().checkRole(r2.getRole());
此处调用Realm的clearCachedAuthorizationInfo清空之前缓存的AuthorizationInfo;
另外还有clearCache,其同时调用clearCachedAuthenticationInfo和clearCachedAuthorizationInfo,清空AuthenticationInfo和AuthorizationInfo。
UserRealm还提供了clearAllCachedAuthorizationInfo、clearAllCachedAuthenticationInfo、clearAllCache,用于清空整个缓存。
Shiro&Session缓存
当我们设置了SecurityManager的CacheManager或者SessionManager。如下:
securityManager.cacheManager=$cacheManager
sessionManager=org.apache.shiro.session.mgt.DefaultSessionManager
securityManager.sessionManager=$sessionManager
如果securityManager实现了SessionsSecurityManager,其会自动判断SessionManager是否实现了CacheManagerAware接口,如果实现了会把CacheManager设置给它。然后sessionManager会判断相应的sessionDAO(如继承自CachingSessionDAO)是否实现了CacheManagerAware,如果实现了会把CacheManager设置给它;如前一篇的MySessionDAO就是带缓存的SessionDAO;其会先查缓存,如果找不到才查数据库。
对于CachingSessionDAO,可以通过如下配置设置缓存的名称:
sessionDAO=com.xttblog.shiro10.session.dao.MySessionDAO
sessionDAO.activeSessionsCacheName=shiro-activeSessionCache
activeSessionsCacheName默认就是shiro-activeSessionCache。
本文实例源代码下载链接: 密码:3k8x
相关文章推荐SSM框架的搭建就不在叙述了
本文主要是讲解在SSM基础上再加上ehcache
1:首先:pom.xml需要的jar
&dependency&
&groupId&org.mybatis&/groupId&
&artifactId&mybatis-ehcache&/artifactId&
&version&1.0.0&/version&
&/dependency&
&dependency&
&groupId&org.ehcache&/groupId&
&artifactId&ehcache&/artifactId&
&version&3.0.1&/version&
&/dependency&
2:在src/main/resources中添加ehcache.xml的配置文件,该路径跟随你的框架而定(大家都懂的)
&?xml version="1.0" encoding="UTF-8"?&
&ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
updateCheck="false"&
&diskStore path="java.io.tmpdir" /&
&defaultCache eternal="false" maxElementsInMemory="1000"
overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="0"
timeToLiveSeconds="600" memoryStoreEvictionPolicy="LRU" /&
&cache name="testCache" eternal="false" maxElementsInMemory="100"
overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="0"
timeToLiveSeconds="300" memoryStoreEvictionPolicy="LRU" /&
&/ehcache&
&!-- 这里是说明name:Cache的唯一标识
maxElementsInMemory:内存中最大缓存对象数
maxElementsOnDisk:磁盘中最大缓存对象数,若是0表示无穷大
eternal:Element是否永久有效,一但设置了,timeout将不起作用
overflowToDisk:配置此属性,当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中
timeToIdleSeconds:设置Element在失效前的允许闲置时间。仅当element不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大
timeToLiveSeconds:设置Element在失效前允许存活时间。最大时间介于创建时间和失效时间之间。仅当element不是永久有效时使用,默认是0.,也就是element存活时间无穷大
diskPersistent:是否缓存虚拟机重启期数据
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒
diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用) --&
3:在spring-mybatis.xml中假如encache的配置
&!-- 使用ehcache缓存 --&
&bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"&
&property name="configLocation" value="classpath:ehcache.xml" /&
--------重点来了---------
假如你的框架里面集成了shiro,这里就需要变下了,具体配置如下
&!-- MyBatis使用ehcache缓存 start --&
&bean id="ehCacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"&
&property name="configLocation" value="classpath:ehcache.xml" /&
&property name="shared" value="true"&&/property& &!-- 这里是关键!!!没有必错
&!-- end MyBatis使用ehcache缓存 --&
&!-- 缓存管理器 使用Ehcache实现 --&
&bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"&
&property name="cacheManager" ref="ehCacheManager" /&
4:最后在你的mapper.xml中配置encache,加入以下配置
&cache type="org.mybatis.caches.ehcache.LoggingEhcache" &
&property name="timeToIdleSeconds" value="3600"/&
&property name="timeToLiveSeconds" value="3600"/&
&property name="maxEntriesLocalHeap" value="1000"/&
&property name="maxEntriesLocalDisk" value=""/&
&property name="memoryStoreEvictionPolicy" value="LRU"/&
这里说明下,LoggingEhcache &这个会在打印log,如果不像要log的话可以使用EhcacheCache&
最后说明下,按照我这样配置的话,这个mapper.xml里面的操作是全局,默认为useCache="true" &都会有作用,
假如某个业务是不要缓存的,可以在当前业务下加上useCache="false"
&select id="selectByName" resultMap="BaseResultMap" parameterType="java.lang.String" useCache="false"&
---------本博文为博主根据互联网资料加上自己实际应用原创,可以转载但需说明出处--------
阅读(...) 评论()主题信息(必填)
主题描述(最多限制在50个字符)
申请人信息(必填)
申请信息已提交审核,请注意查收邮件,我们会尽快给您反馈。
如有疑问,请联系
CSDN &《程序员》编辑/记者,投稿&纠错等事宜请致邮
傻丫头和高科技产物小心翼翼的初恋
如今的编程是一场程序员和上帝的竞赛,程序员要开发出更大更好、傻瓜都会用到软件。而上帝在努力创造出更大更傻的傻瓜。目前为止,上帝是赢的。个人网站:。个人QQ群:、
个人大数据技术博客:
Nginx + Shiro + Ehcache 实现负载均衡集群(成绩报告查询系统)shiro在springmvc里面的集成使用 - 程序员记事本 - ITeye博客
博客分类:
需要在项目里面引入的maven依赖:
&dependency&
&groupId&commons-collections&/groupId&
&artifactId&commons-collections&/artifactId&
&version&3.2.1&/version&
&/dependency&
&dependency&
&groupId&net.sf.ehcache&/groupId&
&artifactId&ehcache-core&/artifactId&
&version&2.6.9&/version&
&/dependency&
&dependency&
&groupId&org.apache.shiro&/groupId&
&artifactId&shiro-spring&/artifactId&
&version&1.2.3&/version&
&/dependency&
&dependency&
&groupId&org.apache.shiro&/groupId&
&artifactId&shiro-ehcache&/artifactId&
&version&1.2.3&/version&
&/dependency&
&dependency&
&groupId&org.apache.shiro&/groupId&
&artifactId&shiro-quartz&/artifactId&
&version&1.2.3&/version&
&/dependency&
如果项目是hibernate的,以前的时候ehcache可能不是单例的,因为shiro里面也使用到了ehcache做缓存,和hibernate的ehcache缓存配置有冲突,所以需要对hibernate的ehcache部分做些调整,调整如下:
&bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"&
&property name="dataSource" ref="dataSource"&&/property&
&property name="hibernateProperties"&
&prop key="hibernate.dialect"&org.hibernate.dialect.MySQLDialect&/prop&
&prop key="hibernate.show_sql"&true&/prop&
&prop key="hibernate.hbm2ddl.auto"&update&/prop&
&prop key="hibernate.cache.region.factory_class"&org.hibernate.cache.EhCacheRegionFactory&/prop&
&prop key="hibernate.cache.region.factory_class"&
org.hibernate.cache.SingletonEhCacheRegionFactory
&prop key="hibernate.cache.provider_class"&net.sf.ehcache.hibernate.SingletonEhCacheProvider&/prop&
&prop key="hibernate.cache.use_second_level_cache"&true&/prop&
&prop key="hibernate.cache.use_query_cache"&true&/prop&
&prop key="hibernate.cache.use_structured_entries"&true&/prop&
&prop key="hibernate.cache.provider_configuration_file_resource_path"&WEB-INF/classes/ehcache.xml&/prop&
&prop key="hibernate.current_session_context_class"&org.springframework.orm.hibernate4.SpringSessionContext&/prop&
&/property&
&property name="packagesToScan"&
&value&com.xxx.entity&/value&
&/property&
上面红色的文字部分是需要调整的内容。
既然用到了ehcache,ehcahce.xml文件里面的配置内容如下:
&?xml version="1.0" encoding="UTF-8"?&
&diskStore path="java.io.tmpdir" /&
&defaultCache maxElementsInMemory="10000" eternal="false"
timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" /&
&cache name="org.hibernate.cache.UpdateTimestampsCache"
maxElementsInMemory="5000" eternal="true" overflowToDisk="true" /&
&cache name="org.hibernate.cache.StandardQueryCache"
maxElementsInMemory="10000" eternal="false" timeToLiveSeconds="120"
overflowToDisk="true" /&
&!-- 登录记录缓存 锁定10分钟 --&
&cache name="passwordRetryCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="0"
overflowToDisk="false"
statistics="true"&
&cache name="authorizationCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="0"
overflowToDisk="false"
statistics="true"&
&cache name="authenticationCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="0"
overflowToDisk="false"
statistics="true"&
&cache name="shiro-activeSessionCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="0"
overflowToDisk="false"
statistics="true"&
&/ehcache&
然后是web.xml文件里面加过滤器,注意要写在springmvc的filter前面
&!-- shiro 安全过滤器 --&
&!-- The filter-name matches name of a 'shiroFilter' bean inside applicationContext.xml --&
&filter-name&shiroFilter&/filter-name&
&filter-class&org.springframework.web.filter.DelegatingFilterProxy&/filter-class&
&async-supported&true&/async-supported&
&init-param&
&param-name&targetFilterLifecycle&/param-name&
&param-value&true&/param-value&
&/init-param&
&!-- Make sure any request you want accessible to Shiro is filtered. /* catches all --&
&!-- requests.
Usually this filter mapping is defined first (before all others) to --&
&!-- ensure that Shiro works in subsequent filters in the filter chain:
&filter-mapping&
&filter-name&shiroFilter&/filter-name&
&url-pattern&/*&/url-pattern&
&/filter-mapping&
然后就是shiro相关的spring配置参数文件了
&?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"&
&!-- 缓存管理器 使用Ehcache实现--&
&bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"&
&property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/&
&bean id="passwordHelper" class="com.shinowit.framework.security.PasswordHelper"&
&!-- 凭证匹配器 --&
&bean id="credentialsMatcher"
class="com.shinowit.framework.security.credentials.RetryLimitSimpleCredentialsMatcher"&
&constructor-arg ref="cacheManager"/&
&property name="passwordHelper" ref="passwordHelper"/&
&bean id="shiro_user_dao" class="com.shinowit.framework.security.dao.UserDAO"&
&property name="jt" ref="jdbcTemplate"/&
&!-- Realm实现 --&
&bean id="userRealm" class="com.shinowit.framework.security.realm.UserRealm"&
&property name="userDAO" ref="shiro_user_dao"/&
&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"/&
&!-- 会话ID生成器 --&
&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 id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie"&
&constructor-arg value="rememberMe"/&
&property name="httpOnly" value="true"/&
&property name="maxAge" value="2592000"/&
&!-- 30天 --&
&!-- rememberMe管理器 --&
&bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager"&
&property name="cipherKey"
value="#{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}"/&
&property name="cookie" ref="rememberMeCookie"/&
&!-- 会话DAO --&
&bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"&
&property name="activeSessionsCacheName" value="shiro-activeSessionCache"/&
&property name="sessionIdGenerator" ref="sessionIdGenerator"/&
&!-- 会话验证调度器 --&
&bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.quartz.QuartzSessionValidationScheduler"&
&property name="sessionValidationInterval" value="1800000"/&
&property name="sessionManager" ref="sessionManager"/&
&!-- 会话管理器 --&
&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"/&
&property name="sessionIdCookie" ref="sessionIdCookie"/&
&!-- 安全管理器 --&
&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"/&
&property name="rememberMeManager" ref="rememberMeManager"/&
&!-- 相当于调用SecurityUtils.setSecurityManager(securityManager) --&
&bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean"&
&property name="staticMethod" value="org.apache.shiro.SecurityUtils.setSecurityManager"/&
&property name="arguments" ref="securityManager"/&
&!--下面的loginUrl有两个必要条件,一个登陆校验失败以后会强制客户端redirect到这个url,
另外一个是登陆的表单(含有用户名及密码)必须action到这个url--&
&!-- 自定义的能够接收校验码的身份验证过滤器
跳转问题太他妈诡异了,不用了,自己写代码控制如何跳转了
&bean id="formAuthenticationFilter" class="com.shinowit.framework.security.filter.ValidFormAuthenticationFilter"&
&property name="usernameParam" value="loginName"/&
&property name="passwordParam" value="loginPass"/&
&property name="loginUrl" value="/login/"/&
&!-- Shiro的Web过滤器 --&
&bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"&
&property name="securityManager" ref="securityManager"/&
&property name="loginUrl" value="/login/"/&
&property name="unauthorizedUrl" value="/unauthorized.jsp"/&
&property name="filters"&
&entry key="authc"&
&bean class="org.apache.shiro.web.filter.authc.PassThruAuthenticationFilter"/&
&util:map&
&entry key="authc" value-ref="formAuthenticationFilter"/&
&/util:map&
&/property&
&property name="filterChainDefinitions"&
/index.jsp = anon
/validcode.jsp = anon
/login/ = anon
/static/** = anon
/js/** = anon
/img/** = anon
/unauthorized.jsp = anon
#/login/checklogin = authc
/login/checklogin = anon
/login/logout = logout
/** = user
&/property&
&!-- Shiro生命周期处理器--&
&bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/&
下面就是各种自己封装的java代码了
自定义的可以保存校验码的token类
package com.xxx.framework.security.
import org.apache.shiro.authc.UsernamePasswordT
* Created on .
public class CustomUsernamePasswordToken extends UsernamePasswordToken {
//用于存储用户输入的校验码
private String validC
public CustomUsernamePasswordToken(String username, char[] password,boolean rememberMe, String host, String validCode) {
//调用父类的构造函数
super(username,password,rememberMe,host);
this.validCode=validC
public String getValidCode() {
return validC
public void setValidCode(String validCode) {
this.validCode = validC
提供正确的登录用户信息的基于jdbc的realm
package com.xxx.framework.security.
import com.xxx.entity.SysUserE
import com.xxx.framework.security.dao.UserDAO;
import com.xxx.framework.security.exception.ValidCodeE
import com.xxx.framework.security.token.CustomUsernamePasswordT
import org.apache.log4j.L
import org.apache.shiro.SecurityU
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationI
import org.apache.shiro.authz.SimpleAuthorizationI
import org.apache.shiro.realm.AuthorizingR
import org.apache.shiro.subject.PrincipalC
public class UserRealm extends AuthorizingRealm {
private static Logger logger = Logger.getLogger(UserRealm.class);
private UserDAO userDAO;
public void setUserDAO(UserDAO userDAO) {
this.userDAO = userDAO;
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setRoles(userDAO.getUserRoles(username));
authorizationInfo.setStringPermissions(userDAO.findPermissions(username));
return authorizationI
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
CustomUsernamePasswordToken login_token = (CustomUsernamePasswordToken)
//校验码判断逻辑
//取得用户输入的校验码
String userInputValidCode = login_token.getValidCode();
//取得真实的正确校验码
String realRightValidCode = (String) SecurityUtils.getSubject().getSession().getAttribute("rand");
if (null == userInputValidCode || !userInputValidCode.equalsIgnoreCase(realRightValidCode)) {
logger.debug("验证码输入错误");
throw new ValidCodeException("验证码输入不正确");
//以上校验码验证通过以后,查数据库
String username = (String) token.getPrincipal();
SysUserEntity user = userDAO.findByUsername(username);
if (user == null) {
throw new UnknownAccountException();//没找到帐号
if (Boolean.FALSE.equals(user.getValid())) {
throw new LockedAccountException(); //帐号锁定
//交给AuthenticatingRealm使用CredentialsMatcher进行密码匹配,如果觉得人家的不好可以自定义实现
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
user.getLoginName(), //用户名
user.getLoginPass(), //密码
//realm name
return authenticationI
public void clearCachedAuthorizationInfo(PrincipalCollection principals) {
super.clearCachedAuthorizationInfo(principals);
public void clearCachedAuthenticationInfo(PrincipalCollection principals) {
super.clearCachedAuthenticationInfo(principals);
public void clearCache(PrincipalCollection principals) {
super.clearCache(principals);
public void clearAllCachedAuthorizationInfo() {
getAuthorizationCache().clear();
public void clearAllCachedAuthenticationInfo() {
getAuthenticationCache().clear();
public void clearAllCache() {
clearAllCachedAuthenticationInfo();
clearAllCachedAuthorizationInfo();
一个简单的自定义的处理校验码异常的类
package com.xxx.framework.security.
import org.apache.shiro.authc.AuthenticationE
* Created on .
public class ValidCodeException extends AuthenticationException {
public ValidCodeException(String msg){
super(msg);
查询用户信息及权限信息的dao
package com.xxx.framework.security.
import com.xxx.entity.SysUserE
import org.springframework.jdbc.core.BeanPropertyRowM
import org.springframework.jdbc.core.JdbcT
import java.util.HashS
import java.util.L
import java.util.S
* Created on .
public class UserDAO {
private JdbcT
public void setJt(JdbcTemplate jt) {
public Set&String& getUserRoles(String loginName) {
String sql = "select role from sys_user u, sys_role r,sys_user_to_role ur where u.login_name=? and u.user_code=ur.user_code and r.role_code=ur.role_code";
return new HashSet(jt.queryForList(sql, String.class, loginName));
public Set&String& findPermissions(String loginName) {
String sql = "select permission from sys_user u, sys_role r, sys_menu p, sys_user_to_role ur, sys_role_to_menu rp where u.login_name=? and u.user_code=ur.user_code and r.role_code=ur.role_code and r.role_code=rp.role_code and p.menu_id=rp.menu_id";
return new HashSet(jt.queryForList(sql, String.class, loginName));
public SysUserEntity findByUsername(String loginName) {
String sql = "select id, user_code,login_name, login_pass, valid from sys_user where login_name=?";
List&SysUserEntity& userList = jt.query(sql, new BeanPropertyRowMapper(SysUserEntity.class), loginName);
if (userList.size() == 0) {
return userList.get(0);
这个翻译过来叫啥合适呢?反正就是根据自定义的加密规则去进行密码匹配验证的类,爱JB叫啥叫啥吧
package com.xxx.framework.security.
import com.xxx.framework.security.PasswordH
import com.xxx.framework.security.token.CustomUsernamePasswordT
import org.apache.shiro.authc.AuthenticationI
import org.apache.shiro.authc.AuthenticationT
import org.apache.shiro.authc.ExcessiveAttemptsE
import org.apache.shiro.authc.credential.SimpleCredentialsM
import org.apache.shiro.cache.C
import org.apache.shiro.cache.CacheM
import java.util.concurrent.atomic.AtomicI
public class RetryLimitSimpleCredentialsMatcher extends SimpleCredentialsMatcher {
private Cache&String, AtomicInteger& passwordRetryC
private PasswordHelper passwordH
public RetryLimitSimpleCredentialsMatcher(CacheManager cacheManager) {
passwordRetryCache = cacheManager.getCache("passwordRetryCache");
public void setPasswordHelper(PasswordHelper passwordHelper) {
this.passwordHelper = passwordH
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
CustomUsernamePasswordToken login_token = (CustomUsernamePasswordToken)
String username = (String) token.getPrincipal();
//retry count + 1
AtomicInteger retryCount = passwordRetryCache.get(username);
if (retryCount == null) {
retryCount = new AtomicInteger(0);
passwordRetryCache.put(username, retryCount);
if (retryCount.incrementAndGet() & 5) {
//if retry count & 5 throw
throw new ExcessiveAttemptsException();
String user_input_login_pass = passwordHelper.encryptPassword(login_token.getUsername(), String.valueOf(login_token.getPassword()));
Object db_login_password = getCredentials(info);
//将密码加密与系统加密后的密码校验,内容一致就返回true,不一致就返回false
boolean matches = super.equals(user_input_login_pass, db_login_password);
if (matches) {
//clear retry count
passwordRetryCache.remove(username);
用户信息实体类
package com.xxx.
import javax.persistence.*;
import java.util.L
* Created on .
* 系统用户信息
@Table(name = "sys_user")
public class SysUserEntity {
@GeneratedValue(strategy =GenerationType.IDENTITY)
@Column(name = "id",insertable = false,updatable = false)
@Column(name = "user_code",length = 6)
private String userC
@Column(name = "login_name",length = 40,nullable = false,unique = true)
private String loginN
@Column(name = "login_pass",length = 50)
private String loginP
@Column(name = "address",length = 200)
@Column(name = "telphone",length = 30)
private String telP
@Column(name = "qq",length = 15)
@Column(name = "email",length = 40)
@Column(name = "mobile",length = 30)
@Column(name = "sort_id")
private Short sortId;
@Column(name = "valid")
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name="sys_user_to_role",joinColumns = { @JoinColumn(name = "user_code") }, inverseJoinColumns = { @JoinColumn(name = "role_code")})
private List&SysRoleEntity& roleL
public Integer getId() {
public void setId(Integer id) {
public String getUserCode() {
return userC
public void setUserCode(String userCode) {
this.userCode = userC
public String getLoginName() {
return loginN
public void setLoginName(String loginName) {
this.loginName = loginN
public String getLoginPass() {
return loginP
public void setLoginPass(String loginPass) {
this.loginPass = loginP
public String getAddress() {
public void setAddress(String address) {
this.address =
public String getTelPhone() {
return telP
public void setTelPhone(String telPhone) {
this.telPhone = telP
public String getQq() {
public void setQq(String qq) {
public String getEmail() {
public void setEmail(String email) {
this.email =
public String getMobile() {
public void setMobile(String mobile) {
this.mobile =
public Short getSortId() {
return sortId;
public void setSortId(Short sortId) {
this.sortId = sortId;
public Boolean getValid() {
public void setValid(Boolean valid) {
this.valid =
public List&SysRoleEntity& getRoleList() {
return roleL
public void setRoleList(List&SysRoleEntity& roleList) {
this.roleList = roleL
还有一个md5工具类
package com.xxx.framework.
import java.security.MessageD
public class PasswordHelper {
* 根据用户名与密码做md5单向hash加密
* @param username 用户名
* @param password 用户密码明文
* @return md5(username+password)
public String encryptPassword(String username, String password) {
String inStr = username +
MessageDigest md5 =
md5 = MessageDigest.getInstance("MD5");
} catch (Exception e) {
System.out.println(e.toString());
e.printStackTrace();
return "";
char[] charArray = inStr.toCharArray();
byte[] byteArray = new byte[charArray.length];
for (int i = 0; i & charArray. i++)
byteArray[i] = (byte) charArray[i];
byte[] md5Bytes = md5.digest(byteArray);
StringBuffer hexValue = new StringBuffer();
for (int i = 0; i & md5Bytes. i++) {
int val = ((int) md5Bytes[i]) & 0
if (val & 16)
hexValue.append("0");
hexValue.append(Integer.toHexString(val));
return hexValue.toString();
好了,我们的springmvc controller类是这么写的
package com.xxx.web.
import com.xxx.entity.SysUserE
import com.xxx.framework.dao.BaseDAO;
import com.xxx.framework.security.PasswordH
import com.xxx.framework.security.exception.ValidCodeE
import com.xxx.framework.security.token.CustomUsernamePasswordT
import org.apache.log4j.L
import org.apache.shiro.SecurityU
import org.apache.shiro.authc.ExcessiveAttemptsE
import org.apache.shiro.authc.IncorrectCredentialsE
import org.apache.shiro.authc.UnknownAccountE
import org.apache.shiro.authz.annotation.RequiresU
import org.apache.shiro.subject.S
import org.apache.shiro.web.filter.authc.FormAuthenticationF
import org.apache.shiro.web.util.WebU
import org.springframework.stereotype.C
import org.springframework.web.bind.annotation.RequestM
import org.springframework.web.bind.annotation.RequestM
import org.springframework.web.bind.annotation.RequestP
import org.springframework.web.bind.annotation.ResponseB
import javax.annotation.R
import javax.servlet.http.HttpServletR
import javax.servlet.http.HttpS
import java.util.HashM
import java.util.M
@Controller
@RequestMapping(value = "/login")
public class LoginController {
private static final Logger logger = Logger.getLogger(LoginController.class);
private BaseDAO&SysUserEntity& sys_user_
@RequestMapping(value = "/", method = RequestMethod.GET)
public String login() {
return "/login/login";
@RequestMapping(value = "/checklogin", method = RequestMethod.POST)
@ResponseBody
public Map&String, Object& checkLogin(SysUserEntity login_user,HttpServletRequest request,@RequestParam("validCode")String validCode) {
Map&String, Object& result = new HashMap&String, Object&();
result.put("msg", "用户名或者密码错误!");
result.put("success", "true");
result.put("status", false);
boolean rememberMe = WebUtils.isTrue(request, FormAuthenticationFilter.DEFAULT_REMEMBER_ME_PARAM);
String host = request.getRemoteHost();
//构造登陆令牌环
CustomUsernamePasswordToken token = new CustomUsernamePasswordToken(login_user.getLoginName(), login_user.getLoginPass().toCharArray(), rememberMe,host,validCode);
//发出登陆请求
SecurityUtils.getSubject().login(token);
//登陆成功
HttpSession session = request.getSession(true);
SysUserEntity user = sys_user_dao.findOneEntityByHql("from SysUserEntity where loginName=?", login_user.getLoginName());
if (null != user) {
//根据输入的用户名和密码确实查到了用户信息
session.removeAttribute("rand");
session.setAttribute("current_login_user", user);
result.put("msg", "登录成功!");
result.put("status", true);
result.put("main_url", "http://" + request.getServerName() + ":" + request.getServerPort() + request.getContextPath() + "/main");
} catch (Exception e) {
logger.error(e.getMessage(), e);
}catch (UnknownAccountException e){
result.put("msg", "账号不存在!");
}catch (IncorrectCredentialsException e){
result.put("msg", "用户名/密码错误!");
}catch (ExcessiveAttemptsException e) {
result.put("msg", "账户错误次数过多,暂时禁止登录!");
}catch (ValidCodeException e){
result.put("msg", "验证码输入错误!");
}catch (Exception e){
result.put("msg", "未知错误!");
@RequestMapping(value="/logout")
public String logout(){
Subject currentUser = SecurityUtils.getSubject();
if (SecurityUtils.getSubject().getSession() != null)
currentUser.logout();
return "redirect:/login/";
private PasswordHelper passwordH
@RequestMapping(value = "/fuck")
@ResponseBody
public Map&String, Object& fuck() {
Map&String, Object& result = new HashMap&String, Object&();
result.put("msg", "用户名或者密码错误!");
result.put("success", "true");
result.put("status", false);
SysUserEntity user = sys_user_dao.findById(SysUserEntity.class, "0001");
user.setLoginPass("a");
String new_pass = passwordHelper.encryptPassword(user.getLoginName(), user.getLoginPass());
user.setLoginPass(new_pass);
sys_user_dao.update(user);
哦,对了,里面那个fuck那个url是用来改密码的,因为数据库里面的密码是加密的,不这么整总也不可能知道对的md5值是多少。
但愿没有忘记什么内容,挺墨迹的,不过能跑起来以后后边关于权限和安全的处理就简单多了,写写注解或者标签就搞定了,很爽。
(641.7 KB)
下载次数: 626
浏览 24069
总结的很好,推荐一个框架整合:
浏览: 274421 次
来自: 北京
楼主这个怎么弄啊,里面的cabs有什么用吗
怎么用的啊,运行后 只 显示上传结果
未签名 XActive ...
怎么用的啊??好难用的,能不能附加个完整解释呢,打开浏览器要求 ...
请问,这样自己写的/login,在人直接请求/checklog ...

我要回帖

更多关于 ehcache shiro.xml 的文章

 

随机推荐