shiro与springmvc整合 + shiro 整合,shiro注解无效什么鬼

这是因为没有开启spring拦截器,在spring-mvc.xml中加入以下代码就可以了(一定要写在最先加载的xml中,写在后面加载的xml中也不起作用)
&bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor" /&
&bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"&
&property name="securityManager" ref="securityManager" /&
lifecycleBeanPostProcessor和securityManager是在shiro配置文件中定义好的:
&bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"&&/bean&
&!-- Shiro安全管理器 --&
&bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"&
&property name="realm" ref="jdbcRealm"&&/property&
&property name="cacheManager" ref="cacheManager"&&/property&
阅读(...) 评论()shiro为了支持注解. 在spring-shiro.xml中加上
&aop:config proxy-target-class="true"/&
&bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor"&
&property name="securityManager" ref="securityManager"/&
如果继续按照javamelody的文档. 导入monitoring-spring.xml, 会发现注解在controller层, springmvc扫描的controller被代理了2次. 一次是aspectj, 一次是jdk自带的代理
这个时候: 需要将导入文件修改为monitoring-spring-aspectj.xml. 这样使用统一的aspectj方式代理.
更多类似文章博客分类:
摘要 SpringMVC整合Shiro, Shiro是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理等功能。
第一步:配置web.xml
&filter-name&shiroFilter&/filter-name&
&filter-class&org.springframework.web.filter.DelegatingFilterProxy&/filter-class&
&init-param&
&param-name&targetFilterLifecycle&/param-name&
&param-value&true&/param-value&
&/init-param&
&filter-mapping&
&filter-name&shiroFilter&/filter-name&
&url-pattern&/*&/url-pattern&
&/filter-mapping&
第二步:配置applicationContext.xml
&bean id="myRealm" class="com.jadyer.realm.MyRealm"/&
&bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"&
&property name="realm" ref="myRealm"/&
&bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"&
&property name="securityManager" ref="securityManager"/&
&property name="loginUrl" value="/"/&
&property name="unauthorizedUrl" value="/"/&
&property name="filterChainDefinitions"&
/mydemo/login=anon
/mydemo/getVerifyCodeImage=anon
/main**=authc
/user/info**=authc
/admin/listUser**=authc,perms[admin:manage]
&/property&
&bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/&
第三步:自定义的Realm类
public class MyRealm extends AuthorizingRealm {
* 为当前登录的Subject授予角色和权限
经测试:本例中该方法的调用时机为需授权资源被访问时
经测试:并且每次访问需授权资源时都会执行该方法中的逻辑,这表明本例中默认并未启用AuthorizationCache
个人感觉若使用了Spring3.1开始提供的ConcurrentMapCache支持,则可灵活决定是否启用AuthorizationCache
比如说这里从数据库获取权限信息时,先去访问Spring3.1提供的缓存,而不使用Shior提供的AuthorizationCache
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals){
String currentUsername = (String)super.getAvailablePrincipal(principals);
SimpleAuthorizationInfo simpleAuthorInfo = new SimpleAuthorizationInfo();
if(null!=currentUsername && "mike".equals(currentUsername)){
simpleAuthorInfo.addRole("admin");
simpleAuthorInfo.addStringPermission("admin:manage");
System.out.println("已为用户[mike]赋予了[admin]角色和[admin:manage]权限");
return simpleAuthorI
return null;
* 验证当前登录的Subject
经测试:本例中该方法的调用时机为LoginController.login()方法中执行Subject.login()时
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken)authcT
System.out.println("验证当前Subject时获取到token为" + ReflectionToStringBuilder.toString(token, ToStringStyle.MULTI_LINE_STYLE));
if("mike".equals(token.getUsername())){
AuthenticationInfo authcInfo = new SimpleAuthenticationInfo("mike", "mike", this.getName());
this.setSession("currentUser", "mike");
return authcI
return null;
* 将一些数据放到ShiroSession中,以便于其它地方使用
比如Controller,使用时直接用HttpSession.getAttribute(key)就可以取到
private void setSession(Object key, Object value){
Subject currentUser = SecurityUtils.getSubject();
if(null != currentUser){
Session session = currentUser.getSession();
System.out.println("Session默认超时时间为[" + session.getTimeout() + "]毫秒");
if(null != session){
session.setAttribute(key, value);
浏览: 7765 次
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'Shiro整合SpringMVC并且实现权限管理,登录和注销_Java教程_动态网站制作指南
Shiro整合SpringMVC并且实现权限管理,登录和注销
来源:人气:26491
Apache Shiro是的一个安全框架。目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Sing 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&
  所有的架包都搞清楚了以后,我们就可以开始正式搭建了,在myeclise中创建一个maven项目,将需要的架包信息依赖全部放入。下面就分步骤来创建  1.首先创建spring的配置文件,位置都在在resource中,配置文件是spring-context.,创建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的是自己实现的,所以我们还需要一个缓存框架,所以在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"&
&descrtion&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.UsernamePassT
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 getLastTime(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.thinkgem.jeesite.modules.sys.security.SystemAuthorizingRealm.P
import com.thinkgem.jeesite.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=''&");
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;
优质网站模板}

我要回帖

更多关于 shiro结合springmvc 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信