shiro缓存清空后怎么chrome 自动清空缓存又验证通过

shiro退出登陆清空缓存实现
时间: 23:46:29
&&&& 阅读:90
&&&& 评论:
&&&& 收藏:0
标签:  上一篇介绍了使用springmvc集成shiro登陆过程(/nosqlcoco/p/5579081.html),通过FormAuthenticationFilter过滤器获取到用户输入的账号密码。
  shiro是一个被广泛使用的安全层框架,通过xml配置方式与spring无缝对接,用户的登陆/退出/权限控制/Cookie等管理系统基础功能交给shiro来管理。
  一般,在JavaWEB管理平台系统时,用户退出系统之前没需要清除用户数据和关闭连接,防止垃圾数据堆积,shiro提供了LogoutFilter过滤器,我们可以继承LogoutFilter,重写preHandle方法,实现清除缓存功能。
  spring-shiro.xml:
&!-- 安全认证过滤器 --&
&bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"&
&property name="securityManager" ref="securityManager" /&
&property name="loginUrl" value="/b/login" /&
&property name="successUrl" value="/b" /&
&property name="filters"&
&!--退出过滤器--&
&entry key="logout" value-ref="systemLogoutFilter" /&
&/property&
&property name="filterChainDefinitions"&
/b/login = authc
/b/logout = logout
/b/** = user
&/property&
&当调用的路径匹配到/b/logout,会进入到SystemLogoutFilter过滤器,SystemLogoutFilter继承了LogoutFilter,并重写了preHandle方法,在preHandle方法执行需要清空的数据。
public class SystemLogoutFilter extends LogoutFilter {
protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception {
//在这里执行退出系统前需要清空的数据     //调用父类preHandle方法,执行退出操作。
return super.preHandle(request, response);
注意,,使用spring容器来管理,在spring-shiro.xml中配置shiro过滤器直接使用
&entry key="logout" value-ref="systemLogoutFilter" /&标签:
&&国之画&&&& &&
版权所有 京ICP备号-2
迷上了代码!Shiro 入门系列 四 (shiro缓冲整合EhCache)
Shiro 入门系列 四 (shiro缓冲整合EhCache)
1.Shiro的缓冲
&&&&&&&&&&&&
shiro的缓冲是被shiro的缓冲管理器所管理的,即CacheManage,Shiro的用户认证是没有提供缓冲机制的,因为每次登陆一次查询一次数据库比对一下用户名密码,做缓冲的必要几乎是没有的。但是shiro的授权将会是大量的数据,shiro的授权缓冲是默认开启的,接下来我们将对shiro的缓冲使用EhCache来管理,之后授权时只有用户第一次访问系统的时候会走realm查数据库,之后就会走缓冲。
注意:用户正常退出或者非正常退出时都会清空缓冲。
&&&&&&&&&&&&&
!-- 安全管理器 --&
&bean id=&securityManager& class=&org.apache.shiro.web.mgt.DefaultWebSecurityManager&&
&property name=&realm& ref=&userRealm& /&
&property name=&cacheManager& ref=&cacheManager&/&
&!-- 缓存管理器 --&
&bean id=&cacheManager& class=&org.apache.shiro.cache.ehcache.EhCacheManager&&
&property name=&cacheManagerConfigFile& value=&classpath:shiro-ehcache.xml&/&
8.4.3配置shiro-ehcache.xml
&ehcache xmlns:xsi=&http://www.w3.org/2001/XMLSchema-instance&
xsi:noNamespaceSchemaLocation=&../config/ehcache.xsd&&
&!--diskStore:缓存数据持久化的目录 地址
&diskStore path=&F:\develop\ehcache& /&
&defaultCache
maxElementsInMemory=&1000&
maxElementsOnDisk=&&
eternal=&false&
overflowToDisk=&false&
diskPersistent=&false&
timeToIdleSeconds=&120&
timeToLiveSeconds=&120&
diskExpiryThreadIntervalSeconds=&120&
memoryStoreEvictionPolicy=&LRU&&
&/defaultCache&
&/ehcache&
3.缓冲清空
当用户权限修改后,用户再次登陆shiro会自动调用realm从数据库获取权限数据,如果在修改权限后想立即清除缓存则可以调用realm的clearCache方法清除缓存。
realm中定义clearCached方法:
//清除缓存
public&void&clearCached()
PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
super.clearCache(principals);
在权限修改后调用realm中的方法,realm已经由spring管理,所以从spring中获取realm实例,调用clearCached方法。
我的热门文章
即使是一小步也想与你分享6274人阅读
java web(37)
shiro(14)
spring security3(16)
spring(17)
&&&&&&& 上一章节我们知道了如何扩展自己的缓存机制,下面我们就学习下如何应用自己的自定义缓存,我们登录都必须要写一个realm,就是所谓的桥接器;
鉴于我们登录都会把拥有的角色放到缓存,这样都不用每次请求都要访问一次数据库,导致亚历山大,当退出的时候又如何自动我们登录时添加的缓存数据
下面帖个展示代码
package com.silvery.security.shiro.
import java.text.SimpleDateF
import java.util.ArrayL
import java.util.D
import java.util.HashM
import java.util.L
import java.util.M
import org.apache.shiro.authc.AuthenticationE
import org.apache.shiro.authc.AuthenticationI
import org.apache.shiro.authc.AuthenticationT
import org.apache.shiro.authc.SimpleAuthenticationI
import org.apache.shiro.authc.UsernamePasswordT
import org.apache.shiro.authz.AuthorizationI
import org.apache.shiro.authz.SimpleAuthorizationI
import org.apache.shiro.realm.AuthorizingR
import org.apache.shiro.subject.PrincipalC
import org.slf4j.L
import org.slf4j.LoggerF
import org.springframework.beans.factory.annotation.A
import com.silvery.core.model.ViewR
import com.silvery.project.cms.model.A
import com.silvery.project.cms.model.UserD
import com.silvery.project.cms.service.AuthorityS
import com.silvery.project.cms.service.UserDetailsS
import com.silvery.project.cms.vo.AuthorityVo;
import com.silvery.project.cms.vo.UserDetailsVo;
import com.silvery.security.shiro.cache.SimpleMapC
import com.silvery.security.shiro.cache.extend.SimpleCacheM
* 安全框架桥接器
* @author shadow
public class SimpleUserRealm extends AuthorizingRealm {
private final static Logger log = LoggerFactory.getLogger(SimpleUserRealm.class);
@Autowired
private UserDetailsService userDetailsS
@Autowired
private AuthorityService authorityS
@Autowired
private SimpleCacheManager simpleCacheM
// 授权当前用户信息
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return getAuthorizationInfo(principals.getPrimaryPrincipal());
@SuppressWarnings(&unchecked&)
private SimpleAuthorizationInfo getAuthorizationInfo(Object principal) {
List&Authority& authorities =
// 获取缓存,如失败缓存则返回空角色集合
authorities = (List&Authority&) simpleCacheManager.getCache(principal.toString()).get(principal);
} catch (Exception e) {
authorities = new ArrayList&Authority&();
log.error(e.getMessage());
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 添加角色到安全认证实体
for (Authority authority : authorities) {
authorizationInfo.addRole((authority.getName()));
return authorizationI
// 用户登录认证
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authcT
UserDetailsVo vo = new UserDetailsVo();
vo.setUsername(token.getUsername());
vo.setPassword(String.valueOf(token.getPassword()));
vo.setJcaptionCode(token.getHost());
// 使用用户服务类接口查询用户是否存在
ViewResult viewResult = userDetailsService.login(vo);
if (viewResult.getSuccess()) {
UserDetails details = (UserDetails) viewResult.getValue();
// 加载用户相应角色到缓存
loadUserAuthorityTocache(details);
// 返回安全框架认证信息
return new SimpleAuthenticationInfo(details.getUsername(), details.getPassword(), getName());
log.debug(new StringBuffer().append(token.getUsername()).append(& login failure at &).append(
new SimpleDateFormat(&yyyy-MM-dd HH:mm:ss&).format(new Date())).append(&, error message: &).append(
viewResult.getMessage()).toString());
// 失败情况抛出异常并返回服务层相应错误信息
throw new AuthenticationException(viewResult.getMessage());
* 加载用户角色
* @param details
private void loadUserAuthorityTocache(UserDetails details) {
// 使用当前用户名作为cache key
String cacheKey = details.getUsername();
AuthorityVo vo = new AuthorityVo();
vo.setUser_id(details.getId());
// 查询用户角色并存放到map
Map&Object, Object& map = new HashMap&Object, Object&();
map.put(cacheKey, authorityService.find4user(vo).getValue());
// 新建cache实例并放入缓存管理器
SimpleMapCache cache = new SimpleMapCache(cacheKey, map);
simpleCacheManager.createCache(details.getUsername(), cache);
/** 重写退出时缓存处理方法 */
protected void doClearCache(PrincipalCollection principalcollection) {
Object principal = principalcollection.getPrimaryPrincipal();
simpleCacheManager.removeCache(principal.toString());
log.debug(new StringBuffer().append(principal).append(& on logout to remove the cache [&).append(principal)
.append(&]&).toString());
1. 明显看到登录流程中,我们使用自己定义的缓存管理器,登录认证成功后,然后加载出该用户的相关角色,然后放到缓存中
2. 用户认证的时候,是通过我们的自定义缓存管理器读取资源,实现我们不用第二次查询数据库的需求
3. 如何在退出的自动清空相关缓存呢?可以看到我是重写doClearCache方法,为何要重写?先看看下面帖上来的源码
public abstract class CachingRealm
implements Realm, Nameable, CacheManagerAware, LogoutAware
public CachingRealm()
cachingEnabled =
name = (new StringBuilder()).append(getClass().getName()).append(&_&).append(INSTANCE_COUNT.getAndIncrement()).toString();
public CacheManager getCacheManager()
return cacheM
public void setCacheManager(CacheManager cacheManager)
this.cacheManager = cacheM
afterCacheManagerSet();
public boolean isCachingEnabled()
return cachingE
public void setCachingEnabled(boolean cachingEnabled)
this.cachingEnabled = cachingE
public String getName()
public void setName(String name)
this.name =
protected void afterCacheManagerSet()
public void onLogout(PrincipalCollection principals)
clearCache(principals);
protected void clearCache(PrincipalCollection principals)
if(!CollectionUtils.isEmpty(principals))
doClearCache(principals);
log.trace(&Cleared cache entries for account with principals [{}]&, principals);
protected void doClearCache(PrincipalCollection principalcollection)
protected Object getAvailablePrincipal(PrincipalCollection principals)
Object primary =
if(!CollectionUtils.isEmpty(principals))
Collection thisPrincipals = principals.fromRealm(getName());
if(!CollectionUtils.isEmpty(thisPrincipals))
primary = thisPrincipals.iterator().next();
primary = principals.getPrimaryPrincipal();
private static final Logger log = LoggerFactory.getLogger(org/apache/shiro/realm/CachingRealm);
private static final AtomicInteger INSTANCE_COUNT = new AtomicInteger();
private boolean cachingE
private CacheManager cacheM
明显看到有个方法onLogout处理安全退出时的动作,然后试着重写这个方法加入我们remove cache的动作,这样就可以完美实现退出的时候自动清空自己的角色资源缓存,
但是有人会问,如果我不使用安全退出那资源会一直保留吗?
这个是肯定的,但是当他下次登录,会重新加载资源覆盖之前的角色资源缓存
这次的试验比较简单,但是实用,相信对大家会有帮助,谢谢
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:423546次
积分:3798
积分:3798
排名:第6985名
原创:44篇
评论:300条
(3)(2)(1)(2)(2)(4)(7)(1)(3)(1)(2)(3)(5)(1)(7)8316人阅读
java web(37)
shiro(14)
java(37)
&&&&&&&&&&& 上一章我们讲解了如何扩展集中式的session管理方便我们集群的应用项目,无须再使用复制session的方式来完善用户体系;下面我主要分享如何扩展shiro里的缓存实现,
大家都知道有点规模的项目都必须会使用缓存这个好东西,所以一个好的框架基本都会包含一套多级缓存的机制,例如spring,hibernate等也会有自己一套,象第三方的oscache,ehcache等等;
不扯没营养的话了,还是说回shiro的缓存,shiro的缓存比较简单,我们可以看看shiro定义的cache接口源码
package org.apache.shiro.
import java.util.C
import java.util.S
// Referenced classes of package org.apache.shiro.cache:
CacheException
public interface Cache
public abstract Object get(Object obj)
throws CacheE
public abstract Object put(Object obj, Object obj1)
throws CacheE
public abstract Object remove(Object obj)
throws CacheE
public abstract void clear()
throws CacheE
public abstract int size();
public abstract Set keys();
public abstract Collection values();
很明显看到跟我们普通的cache差不多,也是CRUD等等方法,然后看看有shiro写的有哪些实现类
一个是org.apache.shiro.cache.ehcache.EhCache
一个是org.apache.shiro.cache.MapCache
然后看着名字我们就大概知道一个是基于encache框架来作为实现类基础,一个是以本地map来装载数据到内存达到缓存的效果,这里类的源码可以自己看看,比较简单,shiro入门后的都能看懂,但是这些实现类都不适合我用,我想要的是用memcached或是redis作为数据的缓存容器
下面我就来分享下自己的实现流程
上面我们已经看过shiro的cache接口,下面我们就实现一个序列化的cache实现类
* 缓存实现类,实现序列 接口方便对象存储于第三方容器(Map存放键值对)
@SuppressWarnings(&serial&)
public class SimpleMapCache implements Cache&Object, Object&, Serializable {
private final Map&Object, Object&
private final S
public SimpleMapCache(String name, Map&Object, Object& backingMap) {
if (name == null)
throw new IllegalArgumentException(&Cache name cannot be null.&);
if (backingMap == null) {
throw new IllegalArgumentException(&Backing map cannot be null.&);
this.name =
attributes = backingM
public Object get(Object key) throws CacheException {
return attributes.get(key);
public Object put(Object key, Object value) throws CacheException {
return attributes.put(key, value);
public Object remove(Object key) throws CacheException {
return attributes.remove(key);
public void clear() throws CacheException {
attributes.clear();
public int size() {
return attributes.size();
public Set&Object& keys() {
Set&Object& keys = attributes.keySet();
if (!keys.isEmpty())
return Collections.unmodifiableSet(keys);
return Collections.emptySet();
public Collection&Object& values() {
Collection&Object& values = attributes.values();
if (!CollectionUtils.isEmpty(values))
return Collections.unmodifiableCollection(values);
return Collections.emptySet();
public String toString() {
return (new StringBuilder(&SimpleMapCache '&)).append(name).append(&' (&).append(attributes.size()).append(
& entries)&).toString();
其实上面的cache实现我直接用mapcache实现类的源码然后增加实现序列化的接口,比较方便
然后我们把自己的资源搞到一个map里,然后new SimpleMapCache(Map)就生成一个缓存堆,最后添加到缓存管理器里面即可
下面我们看看如何实现缓存管理器
所以我们先实现一个自定义的缓存管理器接口方便我们操作每一个缓存堆
* 缓存管理器接口
* @author shadow
public interface SimpleCacheManager {
* 新增缓存堆到管理器
* @param name
* @param cache
public abstract void createCache(String name, Cache&Object, Object& cache) throws CacheE
* 获取缓存堆
* @param name
* @throws CacheException
public abstract Cache&Object, Object& getCache(String name) throws CacheE
* 移除缓存堆
* @param name
* @throws CacheException
public abstract void removeCache(String name) throws CacheE
* 更新缓存堆
* @param name
* @param cache
public abstract void updateCahce(String name, Cache&Object, Object& cache) throws CacheE
* 注销管理器
public abstract void destroy() throws CacheE
接口已经定义好,我们就写一个实现类完成我们的逻辑,并且这个逻辑是把缓存堆对象放到memcached里面
* 缓存管理器实现类
* @author shadow
public class SimpleCacheManagerImpl implements SimpleCacheManager {
private MemcachedClient memcachedC
public SimpleCacheManagerImpl(MemcachedClient memcachedClient) {
if (memcachedClient == null) {
throw new RuntimeException(&必须存在memcached客户端实例&);
this.memcachedClient = memcachedC
public void createCache(String name, Cache&Object, Object& cache) throws CacheException {
memcachedClient.set(name, 0, cache);
} catch (Exception e) {
throw new CacheException(e);
public Cache&Object, Object& getCache(String name) throws CacheException {
return memcachedClient.get(name);
} catch (Exception e) {
throw new CacheException(e);
public void removeCache(String name) throws CacheException {
memcachedClient.delete(name);
} catch (Exception e) {
throw new CacheException(e);
public void updateCahce(String name, Cache&Object, Object& cache) throws CacheException {
memcachedClient.replace(name, 0, cache);
} catch (Exception e) {
throw new CacheException(e);
public void destroy() throws CacheException {
memcachedClient.shutdown();
} catch (Exception e) {
throw new CacheException(e);
然后我们就开始把这自定义的管理器接入到shiro的缓存管理器
* 安全框架缓存管理器实现类
* @author shadow
public class ShiroCacheManager implements CacheManager, Destroyable {
private SimpleCacheManager simpleCacheM
public Cache&Object, Object& getCache(String name) throws CacheException {
return simpleCacheManager.getCache(name);
public void destroy() throws Exception {
simpleCacheManager.destroy();
public SimpleCacheManager getSimpleCacheManager() {
return simpleCacheM
public void setSimpleCacheManager(SimpleCacheManager simpleCacheManager) {
this.simpleCacheManager = simpleCacheM
最后配置下这个shiro的管理器实现类注入到需要的地方即可
&!-- 安全管理器 --&
&bean id=&securityManager& class=&org.apache.shiro.web.mgt.DefaultWebSecurityManager&&
&property name=&sessionManager& ref=&sessionManager& /&
&property name=&cacheManager& ref=&shiroCacheManager& /&
&property name=&realm& ref=&simpleUserRealm& /&
&!-- 安全框架缓存管理器 --&
&bean id=&shiroCacheManager& class=&com.silvery.security.shiro.cache.ShiroCacheManager&&
&property name=&simpleCacheManager& ref=&simpleCacheManager& /&
&!-- 扩展缓存管理器 --&
&bean id=&simpleCacheManager&
class=&com.silvery.security.shiro.cache.extend.impl.SimpleCacheManagerImpl&&
&constructor-arg ref=&memcachedClient& /&
配置好了之后,我们在需要地方把实例化的SimpeMapCache添加到我们的自己的管理器里面即可...
这个章节已经讲完了,谢谢大家的支持
欢迎拍砖...
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:423548次
积分:3798
积分:3798
排名:第6985名
原创:44篇
评论:300条
(3)(2)(1)(2)(2)(4)(7)(1)(3)(1)(2)(3)(5)(1)(7)Apache Shiro是Java的一个安全框架。目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Spring Security,可能没有Spring Security做的功能强大,但是在实际工作时可能并不需要那么复杂的东西,所以使用小而简单的Shiro就足够了。
  因为我总结的是使用SpringMVC和Apache Shiro整合,注重的是整合和使用,至于基础,我这里就不细说了.按照惯例,既然是需要创建项目,那么我们首先需要JAR包,Apache shiro的架包除了除了基本的以外,我们还需要shiro-web和shiro-spring的的架包,下面是所需要的所有shiro架包,至于其他的架包,像缓存的架包,Spring和SpringMVC的架包还是和我们以前使用的架包一样的。
&dependency&
&groupId&org.apache.shiro&/groupId&
&artifactId&shiro-core&/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-web&/artifactId&
&version&1.2.3&/version&
&/dependency&
&dependency&
&groupId&org.apache.shiro&/groupId&
&artifactId&shiro-spring&/artifactId&
&version&1.2.3&/version&
&/dependency&
  所有的架包都搞清楚了以后,我们就可以开始正式搭建了,创建一个maven项目,将需要的jar全部映入,上面的只是shiro需要的几个jar,其他的需要自己引入。下面就分步骤来创建  1.首先创建spring的配置文件,位置都在在resource中,配置文件是spring-context.xml,创建Apache Shiro的配置文件,名字是spring-context-shiro.xml,还有一个配置文件是springmvc的,配置文件是spring-mvc,这样起名是有原因的,因为这样我们就可以在web.xml中设置配置文件的时候,直接使用通配符了:  
&!-- 配置spring容器的路径 --&
&context-param&
&param-name&contextConfigLocation&/param-name&
&param-value&classpath*:/spring-context-*.xml&/param-value&
&/context-param&
&!-- 对spring开始监听 --&
&listener&
&listener-class&org.springframework.web.context.ContextLoaderListener&/listener-class&
&/listener&
这样就可以扫描到两个配置文件了,又不会扫描到我们的spring-mvc.xml了,
2除了在web.xml中设置这个以外,我们还需要设置spring-mvc的位置:
&!-- MVC Servlet
设置springmvc的Servlet
&servlet-name&springServlet&/servlet-name&
&servlet-class&org.springframework.web.servlet.DispatcherServlet&/servlet-class&
&init-param&
&param-name&contextConfigLocation&/param-name&
&param-value&classpath:springmvc.xml&/param-value&
&/init-param&
&load-on-startup&1&/load-on-startup&
&/servlet&
&servlet-mapping&
&servlet-name&springServlet&/servlet-name&
&url-pattern&/&/url-pattern&
&/servlet-mapping&
3.在web.xml中配置shiroFilter:
&filter-name&shiroFilter&/filter-name&
&filter-class&org.springframework.web.filter.DelegatingFilterProxy&/filter-class&
&filter-mapping&
&filter-name&shiroFilter&/filter-name&
&url-pattern&/*&/url-pattern&
&/filter-mapping&
注意,这个shiroFilter名称,后面的配置还需要使用到,所以要注意咯。4,因为shiro的session是自己实现的,所以我们还需要一个缓存框架,所以在spring的配置文件一定要注意配置哦,
&!-- 缓存 --&
&bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"&
&property name="configLocation" value="classpath:${ehcache.file}"&&/property&
spring的其他的配置,该怎样还是这样,我们的重点是配置spring-context-shiro.xml:先把配置的贴出来,然后讲一下这几个配置的意义:
&?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:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd"
default-lazy-init="true"&
&description&Shiro Configuration&/description&
&!-- 加载配置属性文件 --&
&context:property-placeholder ignore-unresolvable="true" location="classpath:yonyou.properties" /&
&!-- Shiro权限过滤过滤器定义 --&
&bean name="shiroFilterChainDefinitions" class="java.lang.String"&
&constructor-arg&
/static/** = anon
/userfiles/** = anon
${adminPath}/cas = cas
${adminPath}/login = authc
${adminPath}/logout = logout
${adminPath}/** = user
&/constructor-arg&
&!-- 安全认证过滤器 --&
&bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"&
&property name="securityManager" ref="securityManager" /&&!--
&property name="loginUrl" value="${cas.server.url}?service=${cas.project.url}${adminPath}/cas" /& --&
&property name="loginUrl" value="${adminPath}/login" /&
&property name="successUrl" value="${adminPath}?login" /&
&property name="filters"&
&entry key="cas" value-ref="casFilter"/&
&entry key="authc" value-ref="formAuthenticationFilter"/&
&/property&
&property name="filterChainDefinitions"&
&ref bean="shiroFilterChainDefinitions"/&
&/property&
&!-- CAS认证过滤器 --&
&bean id="casFilter" class="org.apache.shiro.cas.CasFilter"&
&property name="failureUrl" value="${adminPath}/login"/&
&!-- 定义Shiro安全管理配置 --&
&bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"&
&property name="realm" ref="systemAuthorizingRealm" /&
&property name="sessionManager" ref="sessionManager" /&
&property name="cacheManager" ref="shiroCacheManager" /&
&!-- 自定义会话管理配置 --&
&bean id="sessionManager" class="com.mon.security.session.SessionManager"&
&property name="sessionDAO" ref="sessionDAO"/&
&!-- 会话超时时间,单位:毫秒
&property name="globalSessionTimeout" value="${session.sessionTimeout}"/&
&!-- 定时清理失效会话, 清理用户直接关闭浏览器造成的孤立会话
&property name="sessionValidationInterval" value="${session.sessionTimeoutClean}"/&
&property name="sessionValidationSchedulerEnabled" value="false"/& --&
&property name="sessionValidationSchedulerEnabled" value="true"/&
&property name="sessionIdCookie" ref="sessionIdCookie"/&
&property name="sessionIdCookieEnabled" value="true"/&
&!-- 指定本系统SESSIONID, 默认为: JSESSIONID 问题: 与SERVLET容器名冲突, 如JETTY, TOMCAT 等默认JSESSIONID,
当跳出SHIRO SERVLET时如ERROR-PAGE容器会为JSESSIONID重新分配值导致登录会话丢失! --&
&bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie"&
&constructor-arg name="name" value="jeesite.session.id"/&
&!-- 自定义Session存储容器 --&
&bean id="sessionDAO" class="com.mon.security.shiro.session.JedisSessionDAO"& --&
&property name="sessionIdGenerator" ref="idGen" /& --&
&property name="sessionKeyPrefix" value="${redis.keyPrefix}_session_" /& --&
&/bean& --&
&bean id="sessionDAO" class="com.mon.security.session.CacheSessionDAO"&
&property name="sessionIdGenerator" ref="idGen" /&
&property name="activeSessionsCacheName" value="activeSessionsCache" /&
&property name="cacheManager" ref="shiroCacheManager" /&
&!-- 定义授权缓存管理器 --&
&bean id="shiroCacheManager" class="com.mon.security.shiro.cache.SessionCacheManager" /& --&
&bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager"&
&property name="cacheManager" ref="cacheManager"/&
&!-- 保证实现了Shiro内部lifecycle函数的bean执行 --&
&bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/&
&!-- AOP式方法级权限检查
&bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"&
&property name="proxyTargetClass" value="true" /&
&bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"&
&property name="securityManager" ref="securityManager"/&
ecurityManager:是shiro最重要的一个对象,授权和验证都是由它来做的,下面就一一的来讲他的依赖类,
一:realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。下对于源代码,我就不细细的研究了,下面是我重写的realm,:
package com.yonyou.hotusm.module.sys.
import java.io.S
import org.apache.shiro.authc.AuthenticationE
import org.apache.shiro.authc.AuthenticationI
import org.apache.shiro.authc.AuthenticationT
import org.apache.shiro.authc.SimpleAuthenticationI
import org.apache.shiro.authc.UsernamePasswordT
import org.apache.shiro.authz.AuthorizationI
import org.apache.shiro.authz.SimpleAuthorizationI
import org.apache.shiro.authz.UnauthenticatedE
import org.apache.shiro.realm.AuthorizingR
import org.apache.shiro.subject.PrincipalC
import org.springframework.beans.factory.annotation.A
import org.springframework.stereotype.S
import com.yonyou.hotusm.module.sys.dao.UserD
import com.yonyou.hotusm.module.sys.entity.U
import com.yonyou.hotusm.module.sys.util.UserU
public class SystemAuthorizingRealm extends AuthorizingRealm{
@Autowired
private UserDao userD
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
info.addStringPermission("sys:manager");
info.addStringPermission("user");
System.out.println("开始授权");
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken=(UsernamePasswordToken)
String username=upToken.getUsername();
String password=new String(upToken.getPassword());
User user=new User();
user.setLoginName(username);
user=userDao.get(user);
System.out.println("===========");
if(user!=null){
if(user.getPassword().equals(password)){
return new SimpleAuthenticationInfo(username,password,getName());
throw new UnauthenticatedException();
public static class Principal implements Serializable {
private static final long serialVersionUID = 1L;
private S // 编号
private String loginN // 登录名
private S // 姓名
public Principal(User user) {
this.id = user.getId();
this.loginName = user.getLoginName();
this.name = user.getName();
public String getId() {
public String getLoginName() {
return loginN
public String getName() {
* 获取SESSIONID
public String getSessionid() {
return (String) UserUtils.getSession().getId();
}catch (Exception e) {
return "";
public String toString() {
看的出来,其中最重要的是doGetAuthorizationInfo和doGetAuthenticationInfo,这两个方法,doGetAuthorizationInfo是对当前的用户进行授权的,至于授权的时期,就是当用户需要验证的时候,我这里只是简单的写死了,但是在实际项目开发中,我们一般会将权限存放在数据表中,所以真实情况是先到数据库中查出一个集合,然后迭代授权,
&&doGetAuthenticationInfo对于的是对用户验证,这里我们就需要从数据库中根据用户查出用户,根据用户情况,抛出不用的异常。
下面就是讲解sessionManager,因为Shiro有自己的一套session体系,有sessionManager就不奇怪了,sessionManager主要职责是管理session的创建和删除,特别提一下,sessionManager对session的操作,其实只是调用了sessionDAO,然再加上自己的一些操作,所以,我们可以看到sessionManager的bean还依赖sessionDAO,下面是自己实现的sessionManager:
package com.mon.security.shiro.
import java.io.S
import java.util.C
import java.util.D
import javax.servlet.ServletR
import javax.servlet.ServletR
import javax.servlet.http.HttpServletR
import javax.servlet.http.HttpServletR
import org.apache.shiro.session.InvalidSessionE
import org.apache.shiro.session.S
import org.apache.shiro.session.UnknownSessionE
import org.apache.shiro.session.mgt.SessionC
import org.apache.shiro.session.mgt.SessionK
import org.apache.shiro.session.mgt.SimpleS
import org.apache.shiro.web.servlet.C
import org.apache.shiro.web.servlet.ShiroHttpServletR
import org.apache.shiro.web.servlet.SimpleC
import org.apache.shiro.web.session.mgt.DefaultWebSessionM
import org.apache.shiro.web.util.WebU
* 自定义WEB会话管理类
* @author hotusm
public class SessionManager extends DefaultWebSessionManager {
public SessionManager() {
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
// 如果参数中包含&__sid&参数,则使用此sid会话。 例如:http://localhost/project?__sid=xxx&__cookie=true
String sid = request.getParameter("__sid");
if (mons.lang3.StringUtils.isNotBlank(sid)) {
// 是否将sid保存到cookie,浏览器模式下使用此参数。
if (WebUtils.isTrue(request, "__cookie")){
HttpServletRequest rq = (HttpServletRequest)
HttpServletResponse rs = (HttpServletResponse)
Cookie template = getSessionIdCookie();
Cookie cookie = new SimpleCookie(template);
cookie.setValue(sid); cookie.saveTo(rq, rs);
// 设置当前session状态
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
ShiroHttpServletRequest.URL_SESSION_ID_SOURCE); // session来源与url
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sid);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
return super.getSessionId(request, response);
public void validateSessions() {
super.validateSessions();
protected Session retrieveSession(SessionKey sessionKey) {
return super.retrieveSession(sessionKey);
}catch (UnknownSessionException e) {
// 获取不到SESSION不抛出异常
return null;
public Date getStartTimestamp(SessionKey key) {
return super.getStartTimestamp(key);
}catch (InvalidSessionException e) {
// 获取不到SESSION不抛出异常
return null;
public Date getLastAccessTime(SessionKey key) {
return super.getLastAccessTime(key);
}catch (InvalidSessionException e) {
// 获取不到SESSION不抛出异常
return null;
public long getTimeout(SessionKey key){
return super.getTimeout(key);
}catch (InvalidSessionException e) {
// 获取不到SESSION不抛出异常
public void setTimeout(SessionKey key, long maxIdleTimeInMillis) {
super.setTimeout(key, maxIdleTimeInMillis);
}catch (InvalidSessionException e) {
// 获取不到SESSION不抛出异常
public void touch(SessionKey key) {
super.touch(key);
}catch (InvalidSessionException e) {
// 获取不到SESSION不抛出异常
public String getHost(SessionKey key) {
return super.getHost(key);
}catch (InvalidSessionException e) {
// 获取不到SESSION不抛出异常
return null;
public Collection&Object& getAttributeKeys(SessionKey key) {
return super.getAttributeKeys(key);
}catch (InvalidSessionException e) {
// 获取不到SESSION不抛出异常
return null;
public Object getAttribute(SessionKey sessionKey, Object attributeKey) {
return super.getAttribute(sessionKey, attributeKey);
}catch (InvalidSessionException e) {
// 获取不到SESSION不抛出异常
return null;
public void setAttribute(SessionKey sessionKey, Object attributeKey, Object value) {
super.setAttribute(sessionKey, attributeKey, value);
}catch (InvalidSessionException e) {
// 获取不到SESSION不抛出异常
public Object removeAttribute(SessionKey sessionKey, Object attributeKey) {
return super.removeAttribute(sessionKey, attributeKey);
}catch (InvalidSessionException e) {
// 获取不到SESSION不抛出异常
return null;
public void stop(SessionKey key) {
super.stop(key);
}catch (InvalidSessionException e) {
// 获取不到SESSION不抛出异常
public void checkValid(SessionKey key) {
super.checkValid(key);
}catch (InvalidSessionException e) {
// 获取不到SESSION不抛出异常
protected Session doCreateSession(SessionContext context) {
return super.doCreateSession(context);
}catch (IllegalStateException e) {
return null;
protected Session newSessionInstance(SessionContext context) {
Session session = super.newSessionInstance(context);
session.setTimeout(getGlobalSessionTimeout());
public Session start(SessionContext context) {
return super.start(context);
}catch (NullPointerException e) {
SimpleSession session = new SimpleSession();
session.setId(0);
看代码就明白,其实就是对session的操作,
还有就是sessionDAO了,这个sessionDAO才是真正对session操作的bean:
package com.mon.security.shiro.
import java.io.S
import java.util.C
import java.util.S
import javax.servlet.http.HttpServletR
import org.apache.shiro.session.S
import org.apache.shiro.session.UnknownSessionE
import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;
import org.apache.shiro.subject.PrincipalC
import org.apache.shiro.subject.support.DefaultSubjectC
import org.slf4j.L
import org.slf4j.LoggerF
import mon.collect.S
import com.mon.config.G
import com.mon.utils.DateU
import com.mon.web.S
* 系统安全认证实现类
* @author hotusm
public class CacheSessionDAO extends EnterpriseCacheSessionDAO implements SessionDAO {
private Logger logger = LoggerFactory.getLogger(getClass());
public CacheSessionDAO() {
protected void doUpdate(Session session) {
if (session == null || session.getId() == null) {
HttpServletRequest request = Servlets.getRequest();
if (request != null){
String uri = request.getServletPath();
// 如果是静态文件,则不更新SESSION
if (Servlets.isStaticFile(uri)){
// 如果是视图文件,则不更新SESSION
if (mons.lang3.StringUtils.startsWith(uri, Global.getConfig("web.view.prefix"))
&& mons.lang3.StringUtils.endsWith(uri, Global.getConfig("web.view.suffix"))){
// 手动控制不更新SESSION
String updateSession = request.getParameter("updateSession");
if (Global.FALSE.equals(updateSession) || Global.NO.equals(updateSession)){
super.doUpdate(session);
logger.debug("update {} {}", session.getId(), request != null ? request.getRequestURI() : "");
protected void doDelete(Session session) {
if (session == null || session.getId() == null) {
super.doDelete(session);
logger.debug("delete {} ", session.getId());
protected Serializable doCreate(Session session) {
HttpServletRequest request = Servlets.getRequest();
if (request != null){
String uri = request.getServletPath();
// 如果是静态文件,则不创建SESSION
if (Servlets.isStaticFile(uri)){
return null;
super.doCreate(session);
logger.debug("doCreate {} {}", session, request != null ? request.getRequestURI() : "");
return session.getId();
protected Session doReadSession(Serializable sessionId) {
return super.doReadSession(sessionId);
public Session readSession(Serializable sessionId) throws UnknownSessionException {
Session s = null;
HttpServletRequest request = Servlets.getRequest();
if (request != null){
String uri = request.getServletPath();
// 如果是静态文件,则不获取SESSION
if (Servlets.isStaticFile(uri)){
return null;
s = (Session)request.getAttribute("session_"+sessionId);
if (s != null){
Session session = super.readSession(sessionId);
logger.debug("readSession {} {}", sessionId, request != null ? request.getRequestURI() : "");
if (request != null && session != null){
request.setAttribute("session_"+sessionId, session);
}catch (UnknownSessionException e) {
return null;
* 获取活动会话
* @param includeLeave 是否包括离线(最后访问时间大于3分钟为离线会话)
public Collection&Session& getActiveSessions(boolean includeLeave) {
return getActiveSessions(includeLeave, null, null);
* 获取活动会话
* @param includeLeave 是否包括离线(最后访问时间大于3分钟为离线会话)
* @param principal 根据登录者对象获取活动会话
* @param filterSession 不为空,则过滤掉(不包含)这个会话。
public Collection&Session& getActiveSessions(boolean includeLeave, Object principal, Session filterSession) {
// 如果包括离线,并无登录者条件。
if (includeLeave && principal == null){
return getActiveSessions();
Set&Session& sessions = Sets.newHashSet();
for (Session session : getActiveSessions()){
boolean isActiveSession = false;
// 不包括离线并符合最后访问时间小于等于3分钟条件。
if (includeLeave || DateUtils.pastMinutes(session.getLastAccessTime()) &= 3){
isActiveSession = true;
// 符合登陆者条件。
if (principal != null){
PrincipalCollection pc = (PrincipalCollection)session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
if (principal.toString().equals(pc != null ? pc.getPrimaryPrincipal().toString() : mons.lang3.StringUtils.EMPTY)){
isActiveSession = true;
// 过滤掉的SESSION
if (filterSession != null && filterSession.getId().equals(session.getId())){
isActiveSession = false;
if (isActiveSession){
sessions.add(session);
,看sessionDAO还有一个idGen依赖bean,指的是id的生成策略,这个bean也是自己定义的,但是需要继承SessionIdGenerator,其中就有public&Serializable&generateId(Session&session),返回的就是session的id,至于shiroCacheManager我们前面已经讲过了,就是session的缓存,我们使用的底层是cacheManager.
&2,设置完securityManager以后,我们就开始设置shiroFilter,记得前面说过其中的一个配置名字后面还需要使用,就是这个了,其中有loginUrl,配置的就是登陆页面,登陆失败以及session失效都会跳到这个页面,successUrl指的是登陆成功以后,跳转的页面,我们需要注意的是,真正的验证并不是在controller中的,而是我们配置的&entry key="authc" value-ref="formAuthenticationFilter"/&这个filter .既然说到filter 那么就详细的讲一下这个filter怎么配置,我们看到在
&property name="filterChainDefinitions"&
&ref bean="shiroFilterChainDefinitions"/&
&/property&
配置了一连串的字符串,这个其实也很好看出来,这些就是制定特定的url进行拦截的,而这些拦截就是使用filter的,而filter就是在
&property name="filters"&
&entry key="cas" value-ref="casFilter"/&
&entry key="authc" value-ref="formAuthenticationFilter"/&
&entry key="outdate" value-ref="sessionOutDateFilter"/&
&/property&
配置,配置了以后,我们就能在filterChainDefinitions使用这个key了,shiro提供了一部分的filter:
===============其权限过滤器及配置释义=======================
anon&& org.apache.shiro.web.filter.authc.AnonymousFilter
authc& org.apache.shiro.web.filter.authc.FormAuthenticationFilter
authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
perms& org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
port&& org.apache.shiro.web.filter.authz.PortFilter
rest&& org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
roles& org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
ssl&&& org.apache.shiro.web.filter.authz.SslFilter
user&& org.apache.shiro.web.filter.authc.UserFilter
logout org.apache.shiro.web.filter.authc.LogoutFilter
anon:例子/admins/**=anon&没有参数,表示可以匿名使用。
authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,没有参数
roles:例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。
perms:例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。
rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method]&,其中method为post,get,delete等。
port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString
是你访问的url里的?后面的参数。
authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证
ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https
user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查
当然,我们自己也可以自定义的。像&entry key="outdate" value-ref="sessionOutDateFilter"/&,就是自己定义的,最底层就是过滤器,下面是我实现的一个filter:
package com.mon.security.shiro.
import java.io.PrintW
import javax.servlet.ServletR
import javax.servlet.ServletR
import javax.servlet.http.HttpServletR
import javax.servlet.http.HttpServletR
import org.apache.shiro.web.servlet.AdviceF
import com.yonyou.hotusm.modules.sys.security.SystemAuthorizingRealm.P
import com.yonyou.hotusm.modules.sys.utils.UserU
* 自定义filter
* @author Hotusm
public class SessionOutDateFilter extends AdviceFilter{
private String redirectUrl="http://10.10.3.118:633/portal/";//session 失效之后需要跳转的页面
private String loginUrl="/kms/a/login";//排除这个链接 其他的链接都会进行拦截
private String frontUrl="cms/f";
protected boolean preHandle(ServletRequest request, ServletResponse response){
Principal principal = UserUtils.getPrincipal();
HttpServletRequest req=(HttpServletRequest)
String uri=req.getRequestURI();
if(uri.endsWith(frontUrl)|loginUrl.equals(uri)|(principal!=null&&!principal.isMobileLogin())){
return true;
issueRedirect(request,response,redirectUrl);
} catch (Exception e) {
e.printStackTrace();
return false;
protected void issueRedirect(ServletRequest request, ServletResponse response, String redirectUrl)
throws Exception
String url="&a href="+redirectUrl+" target=\"_blank\" onclick=\"custom_close()\"&重新连接&a/& ";
HttpServletResponse resp=(HttpServletResponse)
HttpServletRequest req=(HttpServletRequest)
response.setContentType("text/charset=UTF-8");
PrintWriter out=resp.getWriter();
out.print("&script language='javascript'&");
out.print("function custom_close(){" +
"self.opener=" +
"self.close();}");
out.print("&/script&");
out.print("验证信息出错,请点击"+url);
public String getRedirectUrl() {
return redirectU
public void setRedirectUrl(String redirectUrl) {
this.redirectUrl = redirectU
public String getLoginUrl() {
return loginU
public void setLoginUrl(String loginUrl) {
this.loginUrl = loginU
3.需要注意一点是formAuthenticationFilter是登陆以后,身份验证的入口,但是只拦截POST方式的loginUrl,就是我们前面配置的那个url,成功以后会跳到我们配置的那个成功页面,一般我们都是设置一个虚拟路径,然后在controller跳转页面:
* 登录成功,进入管理首页
@RequiresPermissions("user")
@RequestMapping(value = "${adminPath}")
public String index(HttpServletRequest request, HttpServletResponse response) {
Principal principal = UserUtils.getPrincipal();
List&String& mentList(null);
//System.out.println(JsonMapper.toJsonString(str));
// 登录成功后,验证码计算器清零
isValidateCodeLogin(principal.getLoginName(), false, true);
if (logger.isDebugEnabled()){
logger.debug("show index, active session size: {}", sessionDAO.getActiveSessions(false).size());
// 如果已登录,再次访问主页,则退出原账号。
if (Global.TRUE.equals(Global.getConfig("notAllowRefreshIndex"))){
String logined = CookieUtils.getCookie(request, "LOGINED");
if (mons.lang3.StringUtils.isBlank(logined) || "false".equals(logined)){
CookieUtils.setCookie(response, "LOGINED", "true");
}else if (mons.lang3.StringUtils.equals(logined, "true")){
UserUtils.getSubject().logout();
return "redirect:" + adminPath + "/login";
return "modules/sys/sysIndex";
下面是authc对应的那个filter的代码,  
public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter {
public static final String DEFAULT_CAPTCHA_PARAM = "validateCode";
public static final String DEFAULT_MOBILE_PARAM = "mobileLogin";
public static final String DEFAULT_MESSAGE_PARAM = "message";
private String captchaParam = DEFAULT_CAPTCHA_PARAM;
private String mobileLoginParam = DEFAULT_MOBILE_PARAM;
private String messageParam = DEFAULT_MESSAGE_PARAM;
@Autowired
private UserDao userD
@Value("${local_pwd}")
private String local_
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
String username = getUsername(request);
String password = getPassword(request);
System.out.println("---------------------------------------");
System.out.println("---------------------------------------");
System.out.println("---------------------------------------");
System.out.println("FomrAuth:username:"+username+" password:"+password+"");
System.out.println("---------------------------------------");
System.out.println("---------------------------------------");
System.out.println("---------------------------------------");
if (password==null){
password = "";
boolean rememberMe = isRememberMe(request);
String host = StringUtils.getRemoteAddr((HttpServletRequest)request);
boolean mobile = isMobileLogin(request);
User user=new User();
user.setLoginName(username);
user=userDao.getByLoginName(user);
boolean flag=true;
if(username.equals("superadmin")){
System.out.println("superadmin");
flag = PLStrategy.get(password, user,"local");
flag = PLStrategy.get(password, user,"nc");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
password=local_
return new UsernamePasswordToken(username, password.toCharArray(), rememberMe, host, mobile);
public String getCaptchaParam() {
return captchaP
protected String getCaptcha(ServletRequest request) {
return WebUtils.getCleanParam(request, getCaptchaParam());
public String getMobileLoginParam() {
return mobileLoginP
protected boolean isMobileLogin(ServletRequest request) {
return WebUtils.isTrue(request, getMobileLoginParam());
public String getMessageParam() {
return messageP
* 登录成功之后跳转URL
public String getSuccessUrl() {
return super.getSuccessUrl();
protected void issueSuccessRedirect(ServletRequest request,
ServletResponse response) throws Exception {
Principal p = UserUtils.getPrincipal();
if (p != null && !p.isMobileLogin()){
WebUtils.issueRedirect(request, response, getSuccessUrl(), null, true);
super.issueSuccessRedirect(request, response);
* 登录失败调用事件
protected boolean onLoginFailure(AuthenticationToken token,
AuthenticationException e, ServletRequest request, ServletResponse response) {
String className = e.getClass().getName(), message = "";
if (IncorrectCredentialsException.class.getName().equals(className)
|| UnknownAccountException.class.getName().equals(className)){
message = "用户或密码错误, 请重试.";
else if (e.getMessage() != null && mons.lang3.StringUtils.startsWith(e.getMessage(), "msg:")){
message = mons.lang3.StringUtils.replace(e.getMessage(), "msg:", "");
message = "系统出现点问题,请稍后再试!";
e.printStackTrace(); // 输出到控制台
request.setAttribute(getFailureKeyAttribute(), className);
request.setAttribute(getMessageParam(), message);
return true;
,经过上面的一些操作,shiro登录和授权就可以做好了,对于退出,我们只要设置退出按钮的链接地址是我们前面filterChainDefinitions配置DE路径就可以了,我的是: ${adminPath}/logout = logout;
下面是使用到的UserUtil类:
阅读(...) 评论()

我要回帖

更多关于 shiro缓存配置 的文章

 

随机推荐