zoukankan      html  css  js  c++  java
  • Shiro 整合SpringMVC 并且实现权限管理

            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的创建和删除,特别提一下,sessionManagersession的操作,其实只是调用了sessionDAO,然再加上自己的一些操作,所以,我们可以看到sessionManagerbean还依赖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 = <span style="color: #0000ff">new</span> SimpleCookie(template);
    

    cookie.setValue(sid); cookie.saveTo(rq, rs);

    }

    // 设置当前session状态
    request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,

                    ShiroHttpServletRequest.URL_SESSION_ID_SOURCE); <span style="color: #008000">//</span><span style="color: #008000"> session来源与url</span>
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sid);
    
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
    
         <span style="color: #0000ff">return</span> 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) {

     <span style="color: #008000">//</span><span style="color: #008000"> 获取不到SESSION不抛出异常</span><span style="color: #0000ff">return</span> <span style="color: #0000ff">null</span>;
    

    }

    }

    @Override
    

    public Date getStartTimestamp(SessionKey key) {

     <span style="color: #0000ff">try</span>{
    
     <span style="color: #0000ff">return</span> <span style="color: #0000ff">super</span>.getStartTimestamp(key);
    
     }<span style="color: #0000ff">catch</span> (InvalidSessionException e) {
    
     <span style="color: #008000">//</span><span style="color: #008000"> 获取不到SESSION不抛出异常</span><span style="color: #0000ff">return</span> <span style="color: #0000ff">null</span>;
    

    }

    }
    
    
    
    @Override
    

    public Date getLastAccessTime(SessionKey key) {

     <span style="color: #0000ff">try</span>{
    
     <span style="color: #0000ff">return</span> <span style="color: #0000ff">super</span>.getLastAccessTime(key);
    
     }<span style="color: #0000ff">catch</span> (InvalidSessionException e) {
    
     <span style="color: #008000">//</span><span style="color: #008000"> 获取不到SESSION不抛出异常</span><span style="color: #0000ff">return</span> <span style="color: #0000ff">null</span>;
    

    }

    }
    
    
    
    @Override
    

    public long getTimeout(SessionKey key){

     <span style="color: #0000ff">try</span>{
    
     <span style="color: #0000ff">return</span> <span style="color: #0000ff">super</span>.getTimeout(key);
    
     }<span style="color: #0000ff">catch</span> (InvalidSessionException e) {
    
     <span style="color: #008000">//</span><span style="color: #008000"> 获取不到SESSION不抛出异常</span><span style="color: #0000ff">return</span> 0;
    

    }

    }
    
    
    
    @Override
    

    public void setTimeout(SessionKey key, long maxIdleTimeInMillis) {

     <span style="color: #0000ff">try</span>{
    
     <span style="color: #0000ff">super</span>.setTimeout(key, maxIdleTimeInMillis);
    
     }<span style="color: #0000ff">catch</span> (InvalidSessionException e) {
    
     <span style="color: #008000">//</span><span style="color: #008000"> 获取不到SESSION不抛出异常</span>
    

    }

    }
    
    
    
    @Override
    

    public void touch(SessionKey key) {

     <span style="color: #0000ff">try</span>{
    
     <span style="color: #0000ff">super</span>.touch(key);
    

    }catch (InvalidSessionException e) {

    // 获取不到SESSION不抛出异常
    }

    }
    
    
    
    @Override
    

    public String getHost(SessionKey key) {

     <span style="color: #0000ff">try</span>{
    
     <span style="color: #0000ff">return</span> <span style="color: #0000ff">super</span>.getHost(key);
    
     }<span style="color: #0000ff">catch</span> (InvalidSessionException e) {
    
     <span style="color: #008000">//</span><span style="color: #008000"> 获取不到SESSION不抛出异常</span><span style="color: #0000ff">return</span> <span style="color: #0000ff">null</span>;
    

    }

    }
    
    
    
    @Override
    

    public Collection<Object> getAttributeKeys(SessionKey key) {

     <span style="color: #0000ff">try</span>{
    
     <span style="color: #0000ff">return</span> <span style="color: #0000ff">super</span>.getAttributeKeys(key);
    
     }<span style="color: #0000ff">catch</span> (InvalidSessionException e) {
    
     <span style="color: #008000">//</span><span style="color: #008000"> 获取不到SESSION不抛出异常</span><span style="color: #0000ff">return</span> <span style="color: #0000ff">null</span>;
    

    }

    }
    
    
    
    @Override
    

    public Object getAttribute(SessionKey sessionKey, Object attributeKey) {

     <span style="color: #0000ff">try</span>{
    
     <span style="color: #0000ff">return</span> <span style="color: #0000ff">super</span>.getAttribute(sessionKey, attributeKey);
    
     }<span style="color: #0000ff">catch</span> (InvalidSessionException e) {
    
     <span style="color: #008000">//</span><span style="color: #008000"> 获取不到SESSION不抛出异常</span><span style="color: #0000ff">return</span> <span style="color: #0000ff">null</span>;
    

    }

    }
    
    
    
    @Override
    

    public void setAttribute(SessionKey sessionKey, Object attributeKey, Object value) {

     <span style="color: #0000ff">try</span>{
    
     <span style="color: #0000ff">super</span>.setAttribute(sessionKey, attributeKey, value);
    
     }<span style="color: #0000ff">catch</span> (InvalidSessionException e) {
    
     <span style="color: #008000">//</span><span style="color: #008000"> 获取不到SESSION不抛出异常</span>
    

    }

    }
    
    
    
    @Override
    

    public Object removeAttribute(SessionKey sessionKey, Object attributeKey) {

     <span style="color: #0000ff">try</span>{
    
     <span style="color: #0000ff">return</span> <span style="color: #0000ff">super</span>.removeAttribute(sessionKey, attributeKey);
    
     }<span style="color: #0000ff">catch</span> (InvalidSessionException e) {
    
     <span style="color: #008000">//</span><span style="color: #008000"> 获取不到SESSION不抛出异常</span><span style="color: #0000ff">return</span> <span style="color: #0000ff">null</span>;
    

    }

    }
    
    
    
    @Override
    

    public void stop(SessionKey key) {

     <span style="color: #0000ff">try</span>{
    
     <span style="color: #0000ff">super</span>.stop(key);
    
     }<span style="color: #0000ff">catch</span> (InvalidSessionException e) {
    
     <span style="color: #008000">//</span><span style="color: #008000"> 获取不到SESSION不抛出异常</span>
    

    }

    }
    
    
    
    @Override
    

    public void checkValid(SessionKey key) {

     <span style="color: #0000ff">try</span>{
    
     <span style="color: #0000ff">super</span>.checkValid(key);
    

    }catch (InvalidSessionException e) {

    // 获取不到SESSION不抛出异常
    }

    }
    
    
    
    @Override
    
    <span style="color: #0000ff">protected</span> Session doCreateSession(SessionContext context) {
    
     <span style="color: #0000ff">try</span>{
    
     <span style="color: #0000ff">return</span> <span style="color: #0000ff">super</span>.doCreateSession(context);
    

    }catch (IllegalStateException e) {

    return null;

    }

    }
    

    @Override

    protected Session newSessionInstance(SessionContext context) {

    Session session = super.newSessionInstance(context);

    session.setTimeout(getGlobalSessionTimeout());

    return session;

    }

    @Override
    
    <span style="color: #0000ff">public</span> Session start(SessionContext context) {
    
     <span style="color: #0000ff">try</span>{
    
     <span style="color: #0000ff">return</span> <span style="color: #0000ff">super</span>.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());

    <span style="color: #0000ff">public</span> CacheSessionDAO() {
    
        <span style="color: #0000ff">super</span>();
    
    }
    
    
    
    @Override
    
    <span style="color: #0000ff">protected</span> <span style="color: #0000ff">void</span> doUpdate(Session session) {
    
     <span style="color: #0000ff">if</span> (session == <span style="color: #0000ff">null</span> || session.getId() == <span style="color: #0000ff">null</span>) {  
    
            <span style="color: #0000ff">return</span>;
    
        }
    
    
    
     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;

    }

    }

     <span style="color: #0000ff">super</span>.doUpdate(session);
    
     logger.debug("update {} {}", session.getId(), request != <span style="color: #0000ff">null</span> ? request.getRequestURI() : "");
    
    }
    
    
    
    @Override
    
    <span style="color: #0000ff">protected</span> <span style="color: #0000ff">void</span> doDelete(Session session) {
    
     <span style="color: #0000ff">if</span> (session == <span style="color: #0000ff">null</span> || session.getId() == <span style="color: #0000ff">null</span>) {  
    
            <span style="color: #0000ff">return</span>;
    
        }
    
    
    
     <span style="color: #0000ff">super</span>.doDelete(session);
    
     logger.debug("delete {} ", session.getId());
    
    }
    
    
    
    @Override
    
    <span style="color: #0000ff">protected</span> Serializable doCreate(Session session) {
    

    HttpServletRequest request = Servlets.getRequest();

    if (request != null){

    String uri = request.getServletPath();

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

        <span style="color: #0000ff">return</span> <span style="color: #0000ff">null</span>;
    

    }

    }

    super.doCreate(session);

    logger.debug("doCreate {} {}", session, request != null ? request.getRequestURI() : "");

     <span style="color: #0000ff">return</span> session.getId();
    
    }
    
    
    
    @Override
    
    <span style="color: #0000ff">protected</span> Session doReadSession(Serializable sessionId) {
    

    return super.doReadSession(sessionId);

    }
    
    
    
    @Override
    
    <span style="color: #0000ff">public</span> Session readSession(Serializable sessionId) <span style="color: #0000ff">throws</span> UnknownSessionException {
    
     <span style="color: #0000ff">try</span>{
    
     Session s = <span style="color: #0000ff">null</span>;
    
     HttpServletRequest request = Servlets.getRequest();
    
     <span style="color: #0000ff">if</span> (request != <span style="color: #0000ff">null</span>){
    
     String uri = request.getServletPath();
    
     <span style="color: #008000">//</span><span style="color: #008000"> 如果是静态文件,则不获取SESSION</span><span style="color: #0000ff">if</span> (Servlets.isStaticFile(uri)){
    
     <span style="color: #0000ff">return</span> <span style="color: #0000ff">null</span>;
    
     }
    
     s = (Session)request.getAttribute("session_"+sessionId);
    
     }
    
     <span style="color: #0000ff">if</span> (s != <span style="color: #0000ff">null</span>){
    
     <span style="color: #0000ff">return</span> s;
    
     }
    
    
    
     Session session = <span style="color: #0000ff">super</span>.readSession(sessionId);
    
     logger.debug("readSession {} {}", sessionId, request != <span style="color: #0000ff">null</span> ? request.getRequestURI() : "");
    
    
    
     <span style="color: #0000ff">if</span> (request != <span style="color: #0000ff">null</span> &amp;&amp; session != <span style="color: #0000ff">null</span>){
    
     request.setAttribute("session_"+sessionId, session);
    
     }
    
    
    
     <span style="color: #0000ff">return</span> session;
    
     }<span style="color: #0000ff">catch</span> (UnknownSessionException e) {
    

    return null;

    }

    }
    
    
    
    <span style="color: #008000">/**</span><span style="color: #008000">
    
    • 获取活动会话

    • @param includeLeave 是否包括离线(最后访问时间大于3分钟为离线会话)

    • @return*/

    @Override

    public Collection<Session> getActiveSessions(boolean includeLeave) {

    return getActiveSessions(includeLeave, null, null);

    }

    <span style="color: #008000">/**</span><span style="color: #008000">
    
    • 获取活动会话

    • @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),返回的就是sessionid,至于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{

    <span style="color: #0000ff">private</span> String redirectUrl="http://10.10.3.118:633/portal/";<span style="color: #008000">//</span><span style="color: #008000">session 失效之后需要跳转的页面</span><span style="color: #0000ff">private</span> String loginUrl="/kms/a/login";<span style="color: #008000">//</span><span style="color: #008000">排除这个链接 其他的链接都会进行拦截</span><span style="color: #0000ff">private</span> String frontUrl="cms/f";
    
    <span style="color: #0000ff">protected</span> <span style="color: #0000ff">boolean</span> preHandle(ServletRequest request, ServletResponse response){
        Principal principal = UserUtils.getPrincipal();
        HttpServletRequest req=(HttpServletRequest) request;
        String uri=req.getRequestURI();
        <span style="color: #0000ff">if</span>(uri.endsWith(frontUrl)|loginUrl.equals(uri)|(principal!=<span style="color: #0000ff">null</span>&amp;&amp;!principal.isMobileLogin())){
            <span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>;
        }
        <span style="color: #0000ff">try</span> {
            issueRedirect(request,response,redirectUrl);
        } <span style="color: #0000ff">catch</span> (Exception e) {
            e.printStackTrace();
        }
        <span style="color: #0000ff">return</span> <span style="color: #0000ff">false</span>;
    }
    
    
      <span style="color: #0000ff">protected</span> <span style="color: #0000ff">void</span> issueRedirect(ServletRequest request, ServletResponse response, String redirectUrl)
         <span style="color: #0000ff">throws</span> Exception
      {      
          
          String url="&lt;a href="+redirectUrl+" target="_blank" onclick="custom_close()"&gt;重新连接&lt;a/&gt; ";
          HttpServletResponse resp=(HttpServletResponse) response;
          HttpServletRequest req=(HttpServletRequest) request;
          response.setContentType("text/html;charset=UTF-8");
          PrintWriter out=resp.getWriter();
          out.print("&lt;script language='javascript'&gt;");
          out.print("function custom_close(){" +
                      "self.opener=null;" +
                      "self.close();}");
          out.print("&lt;/script&gt;");
          out.print("验证信息出错,请点击"+url);
         
          
      }
    
    
      <span style="color: #0000ff">public</span> String getRedirectUrl() {
        <span style="color: #0000ff">return</span> redirectUrl;
    }
    
    
    <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> setRedirectUrl(String redirectUrl) {
        <span style="color: #0000ff">this</span>.redirectUrl = redirectUrl;
    }
    
    
    <span style="color: #0000ff">public</span> String getLoginUrl() {
        <span style="color: #0000ff">return</span> loginUrl;
    }
    
    
    <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> setLoginUrl(String loginUrl) {
        <span style="color: #0000ff">this</span>.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);

        <span style="color: #0000ff">if</span> (logger.isDebugEnabled()){
            
            logger.debug("show index, active session size: {}", sessionDAO.getActiveSessions(<span style="color: #0000ff">false</span>).size());
        }
        
        <span style="color: #008000">//</span><span style="color: #008000"> 如果已登录,再次访问主页,则退出原账号。</span><span style="color: #0000ff">if</span> (Global.TRUE.equals(Global.getConfig("notAllowRefreshIndex"))){
            
            String logined = CookieUtils.getCookie(request, "LOGINED");
            <span style="color: #0000ff">if</span> (org.apache.commons.lang3.StringUtils.isBlank(logined) || "false".equals(logined)){
                
                CookieUtils.setCookie(response, "LOGINED", "true");
            }<span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span> (org.apache.commons.lang3.StringUtils.equals(logined, "true")){
                UserUtils.getSubject().logout();
                
                <span style="color: #0000ff">return</span> "redirect:" + adminPath + "/login";
            }
        }
    

    /return "modules/sys/sysIndex";
    }

    复制代码
    复制代码

     

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

    复制代码
    复制代码
    @Service
    public class FormAuthenticationFilter extends org.apache.shiro.web.filter.authc.FormAuthenticationFilter {

    <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">final</span> String DEFAULT_CAPTCHA_PARAM = "validateCode";
    <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">final</span> String DEFAULT_MOBILE_PARAM = "mobileLogin";
    <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">final</span> String DEFAULT_MESSAGE_PARAM = "message";
    
    <span style="color: #0000ff">private</span> String captchaParam = DEFAULT_CAPTCHA_PARAM;
    <span style="color: #0000ff">private</span> String mobileLoginParam = DEFAULT_MOBILE_PARAM;
    <span style="color: #0000ff">private</span> String messageParam = DEFAULT_MESSAGE_PARAM;
    
    @Autowired 
    <span style="color: #0000ff">private</span> UserDao userDao;
    @Value("${local_pwd}")
    <span style="color: #0000ff">private</span> String local_pwd;
    
    
    @Override
    <span style="color: #0000ff">protected</span> 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("---------------------------------------");
        <span style="color: #0000ff">if</span> (password==<span style="color: #0000ff">null</span>){
            password = "";
        }
        <span style="color: #0000ff">boolean</span> rememberMe = isRememberMe(request);
    
        String host = StringUtils.getRemoteAddr((HttpServletRequest)request);
        <span style="color: #0000ff">boolean</span> mobile = isMobileLogin(request);
        User user=<span style="color: #0000ff">new</span> User();
        user.setLoginName(username);
        user=userDao.getByLoginName(user);
        
        <span style="color: #0000ff">boolean</span> flag=<span style="color: #0000ff">true</span>;
        <span style="color: #0000ff">try</span> {
            <span style="color: #0000ff">if</span>(username.equals("superadmin")){
                System.out.println("superadmin");
                flag = PLStrategy.get(password, user,"local");
            }<span style="color: #0000ff">else</span>{
                flag = PLStrategy.get(password, user,"nc");
            }
            
        } <span style="color: #0000ff">catch</span> (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        <span style="color: #0000ff">if</span>(flag){
            password=local_pwd;
        }
        <span style="color: #008000">//</span><span style="color: #008000">end</span><span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> UsernamePasswordToken(username, password.toCharArray(), rememberMe, host, mobile);
        <span style="color: #008000">//</span><span style="color: #008000">end</span>    }
    
    <span style="color: #0000ff">public</span> String getCaptchaParam() {
        <span style="color: #0000ff">return</span> captchaParam;
    }
    
    <span style="color: #0000ff">protected</span> String getCaptcha(ServletRequest request) {
        <span style="color: #0000ff">return</span> WebUtils.getCleanParam(request, getCaptchaParam());
    }
    
    <span style="color: #0000ff">public</span> String getMobileLoginParam() {
        <span style="color: #0000ff">return</span> mobileLoginParam;
    }
    
    <span style="color: #0000ff">protected</span> <span style="color: #0000ff">boolean</span> isMobileLogin(ServletRequest request) {
        <span style="color: #0000ff">return</span> WebUtils.isTrue(request, getMobileLoginParam());
    }
    
    <span style="color: #0000ff">public</span> String getMessageParam() {
        <span style="color: #0000ff">return</span> messageParam;
    }
    
    <span style="color: #008000">/**</span><span style="color: #008000">
     * 登录成功之后跳转URL
     </span><span style="color: #008000">*/</span>
    @Override
    <span style="color: #0000ff">public</span> String getSuccessUrl() {
        <span style="color: #0000ff">return</span> <span style="color: #0000ff">super</span>.getSuccessUrl();
    }
    
    @Override
    <span style="color: #0000ff">protected</span> <span style="color: #0000ff">void</span> issueSuccessRedirect(ServletRequest request,
            ServletResponse response) <span style="color: #0000ff">throws</span> Exception {
    

    // Principal p = UserUtils.getPrincipal();
    // if (p != null && !p.isMobileLogin()){
    WebUtils.issueRedirect(request, response, getSuccessUrl(), null, true);
    // }else{
    // super.issueSuccessRedirect(request, response);
    // } }

    <span style="color: #008000">/**</span><span style="color: #008000">
     * 登录失败调用事件
     </span><span style="color: #008000">*/</span>
    @Override
    <span style="color: #0000ff">protected</span> <span style="color: #0000ff">boolean</span> onLoginFailure(AuthenticationToken token,
            AuthenticationException e, ServletRequest request, ServletResponse response) {
        String className = e.getClass().getName(), message = "";
        <span style="color: #0000ff">if</span> (IncorrectCredentialsException.<span style="color: #0000ff">class</span>.getName().equals(className)
                || UnknownAccountException.<span style="color: #0000ff">class</span>.getName().equals(className)){
            message = "用户或密码错误, 请重试.";
        }
        <span style="color: #0000ff">else</span> <span style="color: #0000ff">if</span> (e.getMessage() != <span style="color: #0000ff">null</span> &amp;&amp; org.apache.commons.lang3.StringUtils.startsWith(e.getMessage(), "msg:")){
            message = org.apache.commons.lang3.StringUtils.replace(e.getMessage(), "msg:", "");
        }
        <span style="color: #0000ff">else</span>{
            message = "系统出现点问题,请稍后再试!";
            e.printStackTrace(); <span style="color: #008000">//</span><span style="color: #008000"> 输出到控制台</span>        }
        request.setAttribute(getFailureKeyAttribute(), className);
        request.setAttribute(getMessageParam(), message);
        <span style="color: #0000ff">return</span> <span style="color: #0000ff">true</span>;
    }
    

    }

    复制代码
    复制代码

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


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





  • 相关阅读:
    Web的26项基本概念和技术
    StringComparison枚举
    WebDriver使用指南(完整篇)
    Sublime Text 2 入门及技巧
    每天一个 Linux 命令(16):which whereis locate命令
    每天一个 Linux 命令(13):less 命令
    每天一个 Linux 命令(12):more命令
    每天一个linux命令(11):nl命令
    每天一个linux命令(10):cat 命令
    每天一个命令 ls
  • 原文地址:https://www.cnblogs.com/jpfss/p/8376837.html
Copyright © 2011-2022 走看看