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>

  所有的架包都搞清楚了以后,我们就可以开始正式搭建了,在myeclise中创建一个maven项目,将需要的架包信息依赖全部放入。下面就分步骤来创建
  1.首先创建spring的配置文件,位置都在在resource中,配置文件是spring-context.xml,创建Apache Shiro的配置文件,名字是spring-context-shiro.xml,还有一个配置文件是springmvc的,配置文件是spring-mvc,这样起名是有原因的,因为这样我们就可以在web.xml中设置配置文件的时候,直接使用通配符了:
  

  1. <!-- 配置spring容器的路径 -->
  2. <context-param>
  3. <param-name>contextConfigLocation</param-name>
  4. <param-value>classpath*:/spring-context-*.xml</param-value>
  5. </context-param>
  6. <!-- 对spring开始监听 -->
  7. <listener>
  8. <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  9. </listener>

这样就可以扫描到两个配置文件了,又不会扫描到我们的spring-mvc.xml了,

2除了在web.xml中设置这个以外,我们还需要设置spring-mvc的位置:

  1. <!-- MVC Servlet
  2. 设置springmvc的Servlet
  3. -->
  4. <servlet>
  5. <servlet-name>springServlet</servlet-name>
  6. <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
  7. <init-param>
  8. <param-name>contextConfigLocation</param-name>
  9. <param-value>classpath:springmvc.xml</param-value>
  10. </init-param>
  11. <load-on-startup>1</load-on-startup>
  12. </servlet>
  13. <servlet-mapping>
  14. <servlet-name>springServlet</servlet-name>
  15. <url-pattern>/</url-pattern>
  16. </servlet-mapping>

3.在web.xml中配置shiroFilter:

  1. <filter>
  2. <filter-name>shiroFilter</filter-name>
  3. <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
  4. </filter>
  5. <filter-mapping>
  6. <filter-name>shiroFilter</filter-name>
  7. <url-pattern>/*</url-pattern>
  8. </filter-mapping>

注意,这个shiroFilter名称,后面的配置还需要使用到,所以要注意咯。
4,因为shiro的session是自己实现的,所以我们还需要一个缓存框架,所以在spring的配置文件一定要注意配置哦,

  1. <!-- 缓存 -->
  2. <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
  3. <property name="configLocation" value="classpath:${ehcache.file}"></property>
  4. </bean>

spring的其他的配置,该怎样还是这样,我们的重点是配置spring-context-shiro.xml:先把配置的贴出来,然后讲一下这几个配置的意义:

  

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="
  4. http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
  5. http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd"
  6. default-lazy-init="true">
  7. <description>Shiro Configuration</description>
  8. <!-- 加载配置属性文件 -->
  9. <context:property-placeholder ignore-unresolvable="true" location="classpath:yonyou.properties" />
  10. <!-- Shiro权限过滤过滤器定义 -->
  11. <bean name="shiroFilterChainDefinitions" class="java.lang.String">
  12. <constructor-arg>
  13. <value>
  14. /static/** = anon
  15. /userfiles/** = anon
  16. ${adminPath}/cas = cas
  17. ${adminPath}/login = authc
  18. ${adminPath}/logout = logout
  19. ${adminPath}/** = user
  20. </value>
  21. </constructor-arg>
  22. </bean>
  23. <!-- 安全认证过滤器 -->
  24. <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
  25. <property name="securityManager" ref="securityManager" /><!--
  26. <property name="loginUrl" value="${cas.server.url}?service=${cas.project.url}${adminPath}/cas" /> -->
  27. <property name="loginUrl" value="${adminPath}/login" />
  28. <property name="successUrl" value="${adminPath}?login" />
  29. <property name="filters">
  30. <map>
  31. <entry key="cas" value-ref="casFilter"/>
  32. <entry key="authc" value-ref="formAuthenticationFilter"/>
  33. </map>
  34. </property>
  35. <property name="filterChainDefinitions">
  36. <ref bean="shiroFilterChainDefinitions"/>
  37. </property>
  38. </bean>
  39. <!-- CAS认证过滤器 -->
  40. <bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
  41. <property name="failureUrl" value="${adminPath}/login"/>
  42. </bean>
  43. <!-- 定义Shiro安全管理配置 -->
  44. <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
  45. <property name="realm" ref="systemAuthorizingRealm" />
  46. <property name="sessionManager" ref="sessionManager" />
  47. <property name="cacheManager" ref="shiroCacheManager" />
  48. </bean>
  49. <!-- 自定义会话管理配置 -->
  50. <bean id="sessionManager" class="com.yonyou.hotusm.common.security.session.SessionManager">
  51. <property name="sessionDAO" ref="sessionDAO"/>
  52. <!-- 会话超时时间,单位:毫秒 -->
  53. <property name="globalSessionTimeout" value="${session.sessionTimeout}"/>
  54. <!-- 定时清理失效会话, 清理用户直接关闭浏览器造成的孤立会话 -->
  55. <property name="sessionValidationInterval" value="${session.sessionTimeoutClean}"/>
  56. <!-- <property name="sessionValidationSchedulerEnabled" value="false"/> -->
  57. <property name="sessionValidationSchedulerEnabled" value="true"/>
  58. <property name="sessionIdCookie" ref="sessionIdCookie"/>
  59. <property name="sessionIdCookieEnabled" value="true"/>
  60. </bean>
  61. <!-- 指定本系统SESSIONID, 默认为: JSESSIONID 问题: 与SERVLET容器名冲突, 如JETTY, TOMCAT 等默认JSESSIONID,
  62. 当跳出SHIRO SERVLET时如ERROR-PAGE容器会为JSESSIONID重新分配值导致登录会话丢失! -->
  63. <bean id="sessionIdCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
  64. <constructor-arg name="name" value="jeesite.session.id"/>
  65. </bean>
  66. <!-- 自定义Session存储容器 -->
  67. <!-- <bean id="sessionDAO" class="com.yonyou.hotusm.common.security.shiro.session.JedisSessionDAO"> -->
  68. <!-- <property name="sessionIdGenerator" ref="idGen" /> -->
  69. <!-- <property name="sessionKeyPrefix" value="${redis.keyPrefix}_session_" /> -->
  70. <!-- </bean> -->
  71. <bean id="sessionDAO" class="com.yonyou.hotusm.common.security.session.CacheSessionDAO">
  72. <property name="sessionIdGenerator" ref="idGen" />
  73. <property name="activeSessionsCacheName" value="activeSessionsCache" />
  74. <property name="cacheManager" ref="shiroCacheManager" />
  75. </bean>
  76. <!-- 定义授权缓存管理器 -->
  77. <!-- <bean id="shiroCacheManager" class="com.thinkgem.jeesite.common.security.shiro.cache.SessionCacheManager" /> -->
  78. <bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
  79. <property name="cacheManager" ref="cacheManager"/>
  80. </bean>
  81. <!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
  82. <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
  83. <!-- AOP式方法级权限检查 -->
  84. <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
  85. <property name="proxyTargetClass" value="true" />
  86. </bean>
  87. <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
  88. <property name="securityManager" ref="securityManager"/>
  89. </bean>
  90. </beans>

ecurityManager:是shiro最重要的一个对象,授权和验证都是由它来做的,下面就一一的来讲他的依赖类,

一:realm:域,Shiro从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。下对于源代码,我就不细细的研究了,下面是我重写的realm,:

package com.yonyou.hotusm.module.sys.security;

import java.io.Serializable;

import org.apache.shiro.authc.AuthenticationException;

import org.apache.shiro.authc.AuthenticationInfo;

import org.apache.shiro.authc.AuthenticationToken;

import org.apache.shiro.authc.SimpleAuthenticationInfo;

import org.apache.shiro.authc.UsernamePasswordToken;

import org.apache.shiro.authz.AuthorizationInfo;

import org.apache.shiro.authz.SimpleAuthorizationInfo;

import org.apache.shiro.authz.UnauthenticatedException;

import org.apache.shiro.realm.AuthorizingRealm;

import org.apache.shiro.subject.PrincipalCollection;

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

import com.yonyou.hotusm.module.sys.dao.UserDao;

import com.yonyou.hotusm.module.sys.entity.User;

import com.yonyou.hotusm.module.sys.util.UserUtils;

@Service

public class SystemAuthorizingRealm extends AuthorizingRealm{

@Autowired

private UserDao userDao;

@Override

protected AuthorizationInfo doGetAuthorizationInfo(

PrincipalCollection principals) {

SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();

info.addStringPermission("sys:manager");

info.addStringPermission("user");

System.out.println("开始授权");

return info;

}

@Override

protected AuthenticationInfo doGetAuthenticationInfo(

AuthenticationToken token) throws AuthenticationException {

UsernamePasswordToken upToken=(UsernamePasswordToken) token; 

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 String id; // 编号private String loginName; // 登录名private String name; // 姓名public Principal(User user) {

this.id = user.getId();

this.loginName = user.getLoginName();

this.name = user.getName();

}

public String getId() {

return id;

}

public String getLoginName() {

return loginName;

}

public String getName() {

return name;

}

/**

 * 获取SESSIONID

 */public String getSessionid() {

try{

return (String) UserUtils.getSession().getId();

}catch (Exception e) {

return "";

}

}

@Override

public String toString() {

return id;

}

}

}

看的出来,其中最重要的是doGetAuthorizationInfo和doGetAuthenticationInfo,这两个方法,doGetAuthorizationInfo是对当前的用户进行授权的,至于授权的时期,就是当用户需要验证的时候,我这里只是简单的写死了,但是在实际项目开发中,我们一般会将权限存放在数据表中,所以真实情况是先到数据库中查出一个集合,然后迭代授权,

doGetAuthenticationInfo对于的是对用户验证,这里我们就需要从数据库中根据用户查出用户,根据用户情况,抛出不用的异常。

下面就是讲解sessionManager,因为Shiro有自己的一套session体系,有sessionManager就不奇怪了,sessionManager主要职责是管理session的创建和删除,特别提一下,sessionManager对session的操作,其实只是调用了sessionDAO,然再加上自己的一些操作,所以,我们可以看到sessionManager的bean还依赖sessionDAO,下面是自己实现的sessionManager:

package com.yonyou.hotsum.common.security.shiro.session;

import java.io.Serializable;

import java.util.Collection;

import java.util.Date;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.session.InvalidSessionException;

import org.apache.shiro.session.Session;

import org.apache.shiro.session.UnknownSessionException;

import org.apache.shiro.session.mgt.SessionContext;

import org.apache.shiro.session.mgt.SessionKey;

import org.apache.shiro.session.mgt.SimpleSession;

import org.apache.shiro.web.servlet.Cookie;

import org.apache.shiro.web.servlet.ShiroHttpServletRequest;

import org.apache.shiro.web.servlet.SimpleCookie;

import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;

import org.apache.shiro.web.util.WebUtils;

/**

 * 自定义WEB会话管理类

 * @author hotusm

 * 

 */public class SessionManager extends DefaultWebSessionManager {

public SessionManager() {

super();

}

@Override

protected Serializable getSessionId(ServletRequest request, ServletResponse response) {

// 如果参数中包含“__sid”参数,则使用此sid会话。 例如:http://localhost/project?__sid=xxx&__cookie=true
String sid = request.getParameter("__sid"); if (org.apache.commons.lang3.StringUtils.isNotBlank(sid)) { // 是否将sid保存到cookie,浏览器模式下使用此参数。if (WebUtils.isTrue(request, "__cookie")){ HttpServletRequest rq = (HttpServletRequest)request; HttpServletResponse rs = (HttpServletResponse)response; 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 sid; }else{ return super.getSessionId(request, response); } } @Override public void validateSessions() { super.validateSessions(); } @Override protected Session retrieveSession(SessionKey sessionKey) { try{ return super.retrieveSession(sessionKey); }catch (UnknownSessionException e) { // 获取不到SESSION不抛出异常return null; } } @Override public Date getStartTimestamp(SessionKey key) { try{ return super.getStartTimestamp(key); }catch (InvalidSessionException e) { // 获取不到SESSION不抛出异常return null; } } @Override public Date getLastAccessTime(SessionKey key) { try{ return super.getLastAccessTime(key); }catch (InvalidSessionException e) { // 获取不到SESSION不抛出异常return null; } } @Override public long getTimeout(SessionKey key){ try{ return super.getTimeout(key); }catch (InvalidSessionException e) { // 获取不到SESSION不抛出异常return 0; } } @Override public void setTimeout(SessionKey key, long maxIdleTimeInMillis) { try{ super.setTimeout(key, maxIdleTimeInMillis); }catch (InvalidSessionException e) { // 获取不到SESSION不抛出异常
} } @Override public void touch(SessionKey key) { try{ super.touch(key); }catch (InvalidSessionException e) { // 获取不到SESSION不抛出异常
} } @Override public String getHost(SessionKey key) { try{ return super.getHost(key); }catch (InvalidSessionException e) { // 获取不到SESSION不抛出异常return null; } } @Override public Collection<Object> getAttributeKeys(SessionKey key) { try{ return super.getAttributeKeys(key); }catch (InvalidSessionException e) { // 获取不到SESSION不抛出异常return null; } } @Override public Object getAttribute(SessionKey sessionKey, Object attributeKey) { try{ return super.getAttribute(sessionKey, attributeKey); }catch (InvalidSessionException e) { // 获取不到SESSION不抛出异常return null; } } @Override public void setAttribute(SessionKey sessionKey, Object attributeKey, Object value) { try{ super.setAttribute(sessionKey, attributeKey, value); }catch (InvalidSessionException e) { // 获取不到SESSION不抛出异常
} } @Override public Object removeAttribute(SessionKey sessionKey, Object attributeKey) { try{ return super.removeAttribute(sessionKey, attributeKey); }catch (InvalidSessionException e) { // 获取不到SESSION不抛出异常return null; } } @Override public void stop(SessionKey key) { try{ super.stop(key); }catch (InvalidSessionException e) { // 获取不到SESSION不抛出异常
} } @Override public void checkValid(SessionKey key) { try{ super.checkValid(key); }catch (InvalidSessionException e) { // 获取不到SESSION不抛出异常
} } @Override protected Session doCreateSession(SessionContext context) { try{ return super.doCreateSession(context); }catch (IllegalStateException e) { return null; } } @Override protected Session newSessionInstance(SessionContext context) { Session session = super.newSessionInstance(context); session.setTimeout(getGlobalSessionTimeout()); return session; } @Override public Session start(SessionContext context) { try{ return super.start(context); }catch (NullPointerException e) { SimpleSession session = new SimpleSession(); session.setId(0); return session; } } }

看代码就明白,其实就是对session的操作,

还有就是sessionDAO了,这个sessionDAO才是真正对session操作的bean:

package com.yonyou.hotusm.common.security.shiro.session;

import java.io.Serializable;

import java.util.Collection;

import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.session.Session;

import org.apache.shiro.session.UnknownSessionException;

import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO;

import org.apache.shiro.subject.PrincipalCollection;

import org.apache.shiro.subject.support.DefaultSubjectContext;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import com.google.common.collect.Sets;

import com.yonyou.hotusm.common.config.Global;

import com.yonyou.hotusm.common.utils.DateUtils;

import com.yonyou.hotusm.common.web.Servlets;

/**

 * 系统安全认证实现类

 * @author hotusm

 *

 */public class CacheSessionDAO extends EnterpriseCacheSessionDAO implements SessionDAO {

private Logger logger = LoggerFactory.getLogger(getClass());

    public CacheSessionDAO() {

        super();

    }

    @Override

    protected void doUpdate(Session session) {

     if (session == null || session.getId() == null) {  

            return;

        }

     HttpServletRequest request = Servlets.getRequest();

if (request != null){

String uri = request.getServletPath();

// 如果是静态文件,则不更新SESSIONif (Servlets.isStaticFile(uri)){

return;

}

// 如果是视图文件,则不更新SESSIONif (org.apache.commons.lang3.StringUtils.startsWith(uri, Global.getConfig("web.view.prefix"))

&& org.apache.commons.lang3.StringUtils.endsWith(uri, Global.getConfig("web.view.suffix"))){

return;

}

// 手动控制不更新SESSION
String updateSession = request.getParameter("updateSession"); if (Global.FALSE.equals(updateSession) || Global.NO.equals(updateSession)){ return; } } super.doUpdate(session); logger.debug("update {} {}", session.getId(), request != null ? request.getRequestURI() : ""); } @Override protected void doDelete(Session session) { if (session == null || session.getId() == null) { return; } super.doDelete(session); logger.debug("delete {} ", session.getId()); } @Override protected Serializable doCreate(Session session) { HttpServletRequest request = Servlets.getRequest(); if (request != null){ String uri = request.getServletPath(); // 如果是静态文件,则不创建SESSIONif (Servlets.isStaticFile(uri)){ return null; } } super.doCreate(session); logger.debug("doCreate {} {}", session, request != null ? request.getRequestURI() : ""); return session.getId(); } @Override protected Session doReadSession(Serializable sessionId) { return super.doReadSession(sessionId); } @Override public Session readSession(Serializable sessionId) throws UnknownSessionException { try{ Session s = null; HttpServletRequest request = Servlets.getRequest(); if (request != null){ String uri = request.getServletPath(); // 如果是静态文件,则不获取SESSIONif (Servlets.isStaticFile(uri)){ return null; } s = (Session)request.getAttribute("session_"+sessionId); } if (s != null){ return s; } Session session = super.readSession(sessionId); logger.debug("readSession {} {}", sessionId, request != null ? request.getRequestURI() : ""); if (request != null && session != null){ request.setAttribute("session_"+sessionId, session); } return session; }catch (UnknownSessionException e) { return null; } } /** * 获取活动会话 * @param includeLeave 是否包括离线(最后访问时间大于3分钟为离线会话) * @return*/ @Override public Collection<Session> getActiveSessions(boolean includeLeave) { return getActiveSessions(includeLeave, null, null); } /** * 获取活动会话 * @param includeLeave 是否包括离线(最后访问时间大于3分钟为离线会话) * @param principal 根据登录者对象获取活动会话 * @param filterSession 不为空,则过滤掉(不包含)这个会话。 * @return*/ @Override 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() : org.apache.commons.lang3.StringUtils.EMPTY)){ isActiveSession = true; } } // 过滤掉的SESSIONif (filterSession != null && filterSession.getId().equals(session.getId())){ isActiveSession = false; } if (isActiveSession){ sessions.add(session); } } return sessions; } }

,看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"><map><entry key="cas" value-ref="casFilter"/><entry key="authc" value-ref="formAuthenticationFilter"/><entry key="outdate" value-ref="sessionOutDateFilter"/></map></property>

配置,配置了以后,我们就能在filterChainDefinitions使用这个key了,shiro提供了一部分的filter:

?===============其权限过滤器及配置释义=======================

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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.thinkgem.jeesite.common.security.shiro.session;

import java.io.PrintWriter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.apache.shiro.web.servlet.AdviceFilter; import com.thinkgem.jeesite.modules.sys.security.SystemAuthorizingRealm.Principal;
import com.thinkgem.jeesite.modules.sys.utils.UserUtils; /**
*
* 自定义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) request;
String uri=req.getRequestURI();
if(uri.endsWith(frontUrl)|loginUrl.equals(uri)|(principal!=null&&!principal.isMobileLogin())){
return true;
}
try {
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) response;
HttpServletRequest req=(HttpServletRequest) request;
response.setContentType("text/html;charset=UTF-8");
PrintWriter out=resp.getWriter();
out.print("<script language='javascript'>");
out.print("function custom_close(){" +
"self.opener=null;" +
"self.close();}");
out.print("</script>");
out.print("验证信息出错,请点击"+url); } public String getRedirectUrl() {
return redirectUrl;
} public void setRedirectUrl(String redirectUrl) {
this.redirectUrl = redirectUrl;
} public String getLoginUrl() {
return loginUrl;
} public void setLoginUrl(String loginUrl) {
this.loginUrl = loginUrl;
} }

3.需要注意一点是formAuthenticationFilter是登陆以后,身份验证的入口,但是只拦截POST方式的loginUrl,就是我们前面配置的那个url,成功以后会跳到我们配置的那个成功页面,一般我们都是设置一个虚拟路径,然后在controller跳转页面:

/**
* 登录成功,进入管理首页
*/
@RequiresPermissions("user")
@RequestMapping(value = "${adminPath}")
public String index(HttpServletRequest request, HttpServletResponse response) {
Principal principal = UserUtils.getPrincipal();
List<String> str=commentService.commentList(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 (org.apache.commons.lang3.StringUtils.isBlank(logined) || "false".equals(logined)){ CookieUtils.setCookie(response, "LOGINED", "true");
}else if (org.apache.commons.lang3.StringUtils.equals(logined, "true")){
UserUtils.getSubject().logout(); return "redirect:" + adminPath + "/login";
}
}
/return "modules/sys/sysIndex";
}

下面是authc对应的那个filter的代码,
  

@Service
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 userDao;
@Value("${local_pwd}")
private String local_pwd; @Override
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;
try {
if(username.equals("superadmin")){
System.out.println("superadmin");
flag = PLStrategy.get(password, user,"local");
}else{
flag = PLStrategy.get(password, user,"nc");
} } catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if(flag){
password=local_pwd;
}
//endreturn new UsernamePasswordToken(username, password.toCharArray(), rememberMe, host, mobile);
//end } public String getCaptchaParam() {
return captchaParam;
} protected String getCaptcha(ServletRequest request) {
return WebUtils.getCleanParam(request, getCaptchaParam());
} public String getMobileLoginParam() {
return mobileLoginParam;
} protected boolean isMobileLogin(ServletRequest request) {
return WebUtils.isTrue(request, getMobileLoginParam());
} public String getMessageParam() {
return messageParam;
} /**
* 登录成功之后跳转URL
*/
@Override
public String getSuccessUrl() {
return super.getSuccessUrl();
} @Override
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);
// }else{
// super.issueSuccessRedirect(request, response);
// } } /**
* 登录失败调用事件
*/
@Override
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 && org.apache.commons.lang3.StringUtils.startsWith(e.getMessage(), "msg:")){
message = org.apache.commons.lang3.StringUtils.replace(e.getMessage(), "msg:", "");
}
else{
message = "系统出现点问题,请稍后再试!";
e.printStackTrace(); // 输出到控制台 }
request.setAttribute(getFailureKeyAttribute(), className);
request.setAttribute(getMessageParam(), message);
return true;
} }

,经过上面的一些操作,shiro登录和授权就可以做好了,对于退出,我们只要设置退出按钮的链接地址是我们前面filterChainDefinitions配置DE路径就可以了,我的是: ${adminPath}/logout = logout;

来源:http://www.cnblogs.com/zr520/p/5009790.html

Shiro 整合SpringMVC 并且实现权限管理的更多相关文章

  1. Shiro 整合SpringMVC 并实现权限管理,登录和注销

    Shiro 整合SpringMVC 并且实现权限管理,登录和注销 Apache Shiro是Java的一个安全框架.目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Spring S ...

  2. Shiro 整合SpringMVC 并且实现权限管理,登录和注销

    Apache Shiro是Java的一个安全框架.目前,使用Apache Shiro的人越来越多,因为它相当简单,对比Spring Security,可能没有Spring Security做的功能强大 ...

  3. (十二)整合 Shiro 框架,实现用户权限管理

    整合 Shiro 框架,实现用户权限管理 1.Shiro简介 1.1 基础概念 1.2 核心角色 1.3 核心理念 2.SpringBoot整合Shiro 2.1 核心依赖 2.2 Shiro核心配置 ...

  4. SpringBoot2.0 整合 Shiro 框架,实现用户权限管理

    本文源码:GitHub·点这里 || GitEE·点这里 一.Shiro简介 1.基础概念 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理.作为一款安全 ...

  5. Spring Cloud之路:(七)SpringBoot+Shiro实现登录认证和权限管理

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/sage_wang/article/details/79592269一.Shiro介绍1.Shiro是 ...

  6. shiro整合springmvc

    说明   代码及部分相关资料根据慕课网Mark老师的视频进行整理   其他资料: shiro官网 流程 配置 1) 配置web.xml整合shiro 把shiro整合到springMVC实质上是在we ...

  7. Apache Shiro(五)-登录认证和权限管理ssm

    创建一个web动态项目 jar包 web.xml web.xml做了如下几件事情1. 指定spring的配置文件有两个 applicationContext.xml: 用于链接数据库的 applica ...

  8. Shiro集成SSM基于URL权限管理(一)

    学习了shiro之后,我们就可以说尝试把shiro加入ssm中,并做一套基于URL的权限管理. 其他的准备工作就不多说了,直接动手操作,看到效果再去理解. 表结构 执行如下,数据库名字可以自行修改,不 ...

  9. Spring boot 入门(四):集成 Shiro 实现登陆认证和权限管理

    本文是接着上篇博客写的:Spring boot 入门(三):SpringBoot 集成结合 AdminLTE(Freemarker),利用 generate 自动生成代码,利用 DataTable 和 ...

随机推荐

  1. GetProcAddress 宏

    #define FUNC_ADDR(hDll, func) pf##func func = \ (pf##func)GetProcAddress(hDll,#func);\ if(! func) {\ ...

  2. 高版本正方教务系统上传后缀过滤不严导致能直接上传Webshell

    在旧版本中有一个利用插件上传文件的漏洞,但是在新版本中已经没有了这个插件.这个漏洞是由于过滤不严造成的,可以直接上传Webshell进行提权,由于代码在DLL中,全国大部分高校均有此漏洞,影响范围很大 ...

  3. Octopus系列之UploadValues异步上载

    不多说了直接上代码 public void ProcessRequest(HttpContext context) { context.Response.ContentType = "tex ...

  4. cocos2d-x 开头配置(Windows 平台)

    工欲善其事,必先利其器. 要使用 cocos2d-x 引擎,就要配置(或者安装)引擎,到 cocos2d-x 官网下载页下载引擎,官网给了2.x和3.x两个版本,我使用的是3.6的版本,3.x的版本类 ...

  5. IIS+PHP配置一次成功无错误版

    1.首先去PHP官网下载php的压缩包(.zip),由于web服务器是IIS所以尽量使用线程不安全版本的,我下载的是: VC11 x86 Non Thread Safe (2015-May-14 18 ...

  6. win7下用python3.3抓取网上图片并下载到本地

    这篇文章是看了网上有人写了之后,才去试试看的,但是因为我用的是python3.3,与python2.x有些不同,所以就写了下来,以供参考. get_webJpg.py #coding=utf-8 im ...

  7. JEECMS v8 发布,java 开源 CMS 系统

    JEECMSv8 是国内java开源CMS行业知名度最高.用户量最大的站群管理系统,支持栏目模型.内容模型交叉自定义.以及具备支付和财务结算的内容电商为一体:  对于不懂技术的用户来说,只要通过后台的 ...

  8. css3简单介绍

    关于css3我先介绍几个简单的选择器: 先进行设置: 字符串匹配属性选择器: E[alt^="a"]  选择属性中以a开头的元素: E[alt$="a"]  选 ...

  9. Ubuntu中安装eclipse ,双击eclipse出现invalid configuration location问题

    ubuntu invalid configuration location   标签: myeclipse for ubuntu   ubuntu myeclipse   ubuntu安装myecli ...

  10. html页面的head标签下

    head区是指首页html代码的<head>和</head>之间的内容.  必须加入的标签  1.公司版权注释  <!--- the site is designed b ...