springboot shiro 整合

最近在springboot项目中使用了shiro,于是在网上找了很多资料,但是良莠不齐,我把有用的转载下来。

本贴转自http://blog.csdn.net/u014695188/article/details/52356158

权限信息缓存处理

实际中我们的权限信息是不怎么会改变的,所以我们希望是第一次访问,然后进行缓存处理,那么Shiro是否支持呢,答案是肯定的,我们在下一小节进行讲解,如何在Shiro中加入缓存机制。

主要分这么几个步骤:在pom.xml中加入缓存依赖;注入缓存;
(a) 在pom.xml文件中加入依赖:

<!-- shiro ehcache -->  
        <dependency>  
            <groupId>org.apache.shiro</groupId>  
            <artifactId>shiro-ehcache</artifactId>  
            <version>1.2.3</version>  
        </dependency>  
        <!-- 包含支持UI模版(Velocity,FreeMarker,JasperReports), 邮件服务, 脚本服务(JRuby), 缓存Cache(EHCache),   
            任务计划Scheduling(uartz)。 -->  
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-context-support</artifactId>  
        </dependency>  
    </dependencies>  
(b)注入缓存
在ShiroConfiguration中加入如下方法:

/**  
    * shiro缓存管理器;  
    * 需要注入对应的其它的实体类中:  
    * 1、安全管理器:securityManager  
    * 可见securityManager是整个shiro的核心;  
    * @return  
    */  
  
   @Bean  
   public EhCacheManager ehCacheManager(){  
      System.out.println("ShiroConfiguration.getEhCacheManager()");  
      EhCacheManager cacheManager = new EhCacheManager();  
      cacheManager.setCacheManagerConfigFile("classpath:config/ehcache-shiro.xml");  
      return cacheManager;  
  
   }  
将缓存对象注入到SecurityManager中:

@Bean  
public SecurityManager securityManager(){  
       DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();  
       //设置realm.  
       securityManager.setRealm(myShiroRealm());  
       //注入缓存管理器;  
       securityManager.setCacheManager(ehCacheManager());//这个如果执行多次,也是同样的一个对象;  
       return securityManager;  
    }  
(c)添加缓存配置文件:
在src/main/resouces/config添加ehcache-shiro.xml配置文件:

<?xml version="1.0" encoding="UTF-8"?>  
<ehcache name="es">  
    <diskStore path="java.io.tmpdir"/>  
         <!--  
       name:缓存名称。  
       maxElementsInMemory:缓存最大数目  
       maxElementsOnDisk:硬盘最大缓存个数。   
       eternal:对象是否永久有效,一但设置了,timeout将不起作用。   
       overflowToDisk:是否保存到磁盘,当系统当机时  
       timeToIdleSeconds:设置对象在失效前的允许闲置时间(单位:秒)。仅当eternal=false对象不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大。  
       timeToLiveSeconds:设置对象在失效前允许存活时间(单位:秒)。最大时间介于创建时间和失效时间之间。仅当eternal=false对象不是永久有效时使用,默认是0.,也就是对象存活时间无穷大。  
       diskPersistent:是否缓存虚拟机重启期数据 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.   
       diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区。   
       diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒。  
       memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用)。   
       clearOnFlush:内存数量最大时是否清除。  
       memoryStoreEvictionPolicy:  
            Ehcache的三种清空策略;  
            FIFO,first in first out,这个是大家最熟的,先进先出。  
            LFU, Less Frequently Used,就是上面例子中使用的策略,直白一点就是讲一直以来最少被使用的。如上面所讲,缓存的元素有一个hit属性,hit值最小的将会被清出缓存。  
            LRU,Least Recently Used,最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。  
    -->  
    <defaultCache  
            maxElementsInMemory="10000"  
            eternal="false"  
            timeToIdleSeconds="120"  
            timeToLiveSeconds="120"  
            overflowToDisk="false"  
            diskPersistent="false"  
            diskExpiryThreadIntervalSeconds="120"  
            />  
    <!-- 登录记录缓存锁定10分钟 -->  
    <cache name="passwordRetryCache"  
           maxEntriesLocalHeap="2000"  
           eternal="false"  
           timeToIdleSeconds="3600"  
           timeToLiveSeconds="0"  
           overflowToDisk="false"  
           statistics="true">  
    </cache>  
</ehcache> 

在配置文件上已经有很详细的解释了,所以这里就过多介绍ehcache的配置了。
运行程序访问:http://127.0.0.1:8080/userInfo/userAdd
查看控制台的打印信息:
权限配置-->MyShiroRealm.doGetAuthorizationInfo()

这个信息就只打印一次了,说明我们的缓存生效了


密码多次输入错误

CredentialsMatcher是shiro提供的用于加密密码和验证密码服务的接口,而HashedCredentialsMatcher正是CredentialsMatcher的一个实现类

public class SimpleCredentialsMatcher extends CodecSupport implements CredentialsMatcher  
  
public class HashedCredentialsMatcher extends SimpleCredentialsMatcher 
自定义RetryLimitHashedCredentialsMatcher继承HashedCredentialsMatcher

import java.util.concurrent.atomic.AtomicInteger;  
  
import org.apache.shiro.authc.AuthenticationInfo;  
import org.apache.shiro.authc.AuthenticationToken;  
import org.apache.shiro.authc.ExcessiveAttemptsException;  
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;  
import org.apache.shiro.cache.Cache;  
import org.apache.shiro.cache.CacheManager;  
  
public class RetryLimitHashedCredentialsMatcher extends  HashedCredentialsMatcher{  
    private Cache<String, AtomicInteger> passwordRetryCache;    
        
    public RetryLimitHashedCredentialsMatcher(CacheManager cacheManager) {    
        passwordRetryCache = cacheManager.getCache("passwordRetryCache");    
    }    
    
    @Override    
    public boolean doCredentialsMatch(AuthenticationToken token,    
            AuthenticationInfo info) {    
        String username = (String) token.getPrincipal();    
        // retry count + 1    
        AtomicInteger retryCount = passwordRetryCache.get(username);    
        if (retryCount == null) {    
            retryCount = new AtomicInteger(0);    
            passwordRetryCache.put(username, retryCount);    
        }    
        if (retryCount.incrementAndGet() > 5) {    
            // if retry count > 5 throw    
            throw new ExcessiveAttemptsException();    
        }    
    
        boolean matches = super.doCredentialsMatch(token, info);    
        if (matches) {    
            // clear retry count    
            passwordRetryCache.remove(username);    
        }    
        return matches;    
    }    
  
}  

在回调方法doCredentialsMatch(AuthenticationToken token,AuthenticationInfo info)中进行身份认证的密码匹配,这里我们引入了Ehcahe用于保存用户登录次数,如果登录失败retryCount变量则会一直累加,如果登录成功,那么这个count就会从缓存中移除,从而实现了如果登录次数超出指定的值就锁定。


修改ShiroConfiguration的方法

/**  
 * 凭证匹配器 (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了  
 * 所以我们需要修改下doGetAuthenticationInfo中的代码; )  
 *   
 * @return  
 */  
@Bean  
public HashedCredentialsMatcher hashedCredentialsMatcher() {  
    HashedCredentialsMatcher hashedCredentialsMatcher = new RetryLimitHashedCredentialsMatcher(ehCacheManager());  
            //new HashedCredentialsMatcher();  
    hashedCredentialsMatcher.setHashAlgorithmName("md5");// 散列算法:这里使用MD5算法;  
    hashedCredentialsMatcher.setHashIterations(2);// 散列的次数,比如散列两次,相当于  
                                                    // md5(md5(""));  
  
    return hashedCredentialsMatcher;  
}  

ehcache-shiro.xml 加入配置

<!-- 登录记录缓存锁定10分钟 -->  
    <cache name="passwordRetryCache"  
           maxEntriesLocalHeap="2000"  
           eternal="false"  
           timeToIdleSeconds="3600"  
           timeToLiveSeconds="0"  
           overflowToDisk="false"  
           statistics="true">  
    </cache> 

登录方法加入异常判断

            else if (ExcessiveAttemptsException.class.getName().equals(exception)) {    
                System.out.println("ExcessiveAttemptsException -- > 登录失败次数过多:");    
                msg = "ExcessiveAttemptsException -- > 登录失败次数过多:";    
            }  

记住我

记住密码实现起来也是比较简单的,主要看下是如何实现的。
在ShiroConfiguration加入两个方法:

@Bean  
public SimpleCookie rememberMeCookie(){  
  
       System.out.println("ShiroConfiguration.rememberMeCookie()");  
       //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe  
       SimpleCookie simpleCookie = new SimpleCookie("rememberMe");  
       //<!-- 记住我cookie生效时间30天 ,单位秒;-->  
       simpleCookie.setMaxAge(259200);  
       return simpleCookie;  
}  
/**  
  * cookie管理对象;  
  * @return  
  */  
@Bean  
public CookieRememberMeManager rememberMeManager(){  
  
       System.out.println("ShiroConfiguration.rememberMeManager()");  
       CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();  
       cookieRememberMeManager.setCookie(rememberMeCookie());  
       return cookieRememberMeManager;  
}  
将rememberMeManager注入到SecurityManager中

@Bean  
public SecurityManager securityManager() {  
    DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();  
    // 设置realm.  
    securityManager.setRealm(myShiroRealm());  
    //注入缓存管理器;  
     securityManager.setCacheManager(ehCacheManager());//这个如果执行多次,也是同样的一个对象;  
    //注入记住我管理器;  
    securityManager.setRememberMeManager(rememberMeManager());  
    return securityManager;  
}  

在ShiroFilterFactoryBean添加记住我过滤器

@Bean  
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {  
    System.out.println("ShiroConfiguration.shiroFilter()");  
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();  
  
    // 必须设置SecuritManager  
    shiroFilterFactoryBean.setSecurityManager(securityManager);  
  
    // 拦截器  
    Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();  
  
    // 配置退出过滤器,其中的具体代码Shiro已经替我们实现了  
    filterChainDefinitionMap.put("/logout", "logout");  
      
    //配置记住我或认证通过可以访问的地址  
  
       filterChainDefinitionMap.put("/index", "user");  
       filterChainDefinitionMap.put("/", "user");  
         
    // <!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;  
    // <!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->  
    filterChainDefinitionMap.put("/servlet/safecode", "anon");  
    filterChainDefinitionMap.put("/**", "authc");  
  
    // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面  
    shiroFilterFactoryBean.setLoginUrl("/login");  
    // 登录成功后要跳转的链接  
    shiroFilterFactoryBean.setSuccessUrl("/index");  
    // 未授权界面;  
    shiroFilterFactoryBean.setUnauthorizedUrl("/403");  
      
    shiroFilterFactoryBean  
            .setFilterChainDefinitionMap(filterChainDefinitionMap);  
    return shiroFilterFactoryBean;  
  
} 

主要是加入了:
//配置记住我或认证通过可以访问的地址
filterChainDefinitionMap.put("/index", "user");
filterChainDefinitionMap.put("/", "user");

修改登录界面加入rememberMe复选框:
在login.html中加入:
<P><input type="checkbox" name="rememberMe" />记住我</P>

这时候运行程序,登录之后跳转到/index页面,然后我们关闭浏览器,然后直接访问/index还是可以访问的,说明我们写的记住密码已经生效了,如果访问http://127.0.0.1:8080/userInfo/userAdd 的
话还是需要重新登录的。

------

thymleaf使用shiro标签

shiro权限框架,前端验证是为jsp设计的,其中的tag只能用于jsp系列的模板引擎。最近项目使用了thymeleaf作为前端模板引擎,使用HTML文件,没法引入shiro的tag lib,此时如果要使用shiro的话,可以引入 thymeleaf-extras-shiro.jar这个拓展包来曲线实现shiro的前端验证。

https://github.com/theborakompanioni/thymeleaf-extras-shiro

在pom.xml中加入如下依赖:

        <dependency>  
            <groupId>com.github.theborakompanioni</groupId>  
            <artifactId>thymeleaf-extras-shiro</artifactId>  
            <version>1.2.1</version>  
        </dependency>  

ShiroConfiguration.java中添加

/**  
   * ShiroDialect,为了在thymeleaf里使用shiro的标签的bean  
   * @return  
   */  
  @Bean  
  public ShiroDialect shiroDialect(){  
      return new ShiroDialect();  
  }

index.html引入

<html xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<!DOCTYPE html>    
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"  
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3"  
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">  
<head>    
<meta charset="UTF-8" />    
<title>Insert title here</title>    
</head>    
<body>    
    <h3>index</h3>   
    <!-- 验证当前用户是否为“访客”,即未认证(包含未记住)的用户。 -->  
    <p shiro:guest="">Please <a href="login.html">login</a></p>  
      
      
    <!-- 认证通过或已记住的用户。 -->  
    <p shiro:user="">  
       Welcome back John! Not John? Click <a href="login.html">here</a> to login.  
    </p>  
      
    <!-- 已认证通过的用户。不包含已记住的用户,这是与user标签的区别所在。 -->  
    <p shiro:authenticated="">  
      Hello, <span shiro:principal=""></span>, how are you today?  
    </p>   
    <a shiro:authenticated="" href="updateAccount.html">Update your contact information</a>  
      
    <!-- 输出当前用户信息,通常为登录帐号信息。 -->  
    <p>Hello, <shiro:principal/>, how are you today?</p>  
      
      
    <!-- 未认证通过用户,与authenticated标签相对应。与guest标签的区别是,该标签包含已记住用户。 -->  
    <p shiro:notAuthenticated="">  
       Please <a href="login.html">login</a> in order to update your credit card information.  
    </p>  
       
    <!-- 验证当前用户是否属于该角色。 -->  
    <a shiro:hasRole="admin" href="admin.html">Administer the system</a><!-- 拥有该角色 -->  
      
    <!-- 与hasRole标签逻辑相反,当用户不属于该角色时验证通过。 -->  
    <p shiro:lacksRole="developer"><!-- 没有该角色 -->  
      Sorry, you are not allowed to developer the system.  
    </p>  
      
    <!-- 验证当前用户是否属于以下所有角色。 -->  
    <p shiro:hasAllRoles="developer, admin"><!-- 角色与判断 -->  
       You are a developer and a admin.  
    </p>  
      
    <!-- 验证当前用户是否属于以下任意一个角色。  -->  
    <p shiro:hasAnyRoles="admin, vip, developer"><!-- 角色或判断 -->  
         You are a admin, vip, or developer.  
    </p>  
      
    <!--验证当前用户是否拥有指定权限。  -->  
    <a shiro:hasPermission="userInfo:add" href="createUser.html">添加用户</a><!-- 拥有权限 -->  
      
    <!-- 与hasPermission标签逻辑相反,当前用户没有制定权限时,验证通过。 -->  
    <p shiro:lacksPermission="userInfo:del"><!-- 没有权限 -->  
         Sorry, you are not allowed to delete user accounts.  
    </p>  
      
    <!-- 验证当前用户是否拥有以下所有角色。 -->  
    <p shiro:hasAllPermissions="userInfo:view, userInfo:add"><!-- 权限与判断 -->  
           You can see or add users.  
    </p>  
      
    <!-- 验证当前用户是否拥有以下任意一个权限。  -->  
    <p shiro:hasAnyPermissions="userInfo:view, userInfo:del"><!-- 权限或判断 -->  
               You can see or delete users.  
    </p>  
      
</body>    
</html>










  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值