博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring 整合 shiro
阅读量:4550 次
发布时间:2019-06-08

本文共 14934 字,大约阅读时间需要 49 分钟。

   该架构采用spring + springMVC + shiro + ehcache搭建有哪里不对的地方请大神指明,万分感谢!!

    先来个标题

Shiro安全配置
  //别以为没啥用,这行代码代表功能的开始搭建,虽然对功能没什么软用。。。

  接下来是 shiroFilter  这个名称和要 web.xml 里面配置的 shiroFilter  相对应,

  说到这里了,顺便说下 web.xml 里面 shiroFilter 拦截和 springMVC 拦截

  按说 / /* 都是拦截,区别就在与一个有返回,一个没有返回,

  但是 springMVC 必须配置 / ,而 shiroFilter 必须配置 /* ,否则 shiroFilter 会拦截不到,

  看网上好多都说 shiroFiter 必须在 springMVC 前面,经测试,两者间的顺序没有讲究,

  在一个,登陆时候会拦截三次,按照本人的想法是,硬编码一次,springMVC 一次,shiroFilter 一次,具体原因因为没有测试,所以不明。

   
    
    
    
    
    
    
      
/captcha.jpg = anon /static/** = anon /logout = anon /login = anon /member/** = anon /manage/** = user
      <-- 也可以自定义 Filter -->       <--         
          
            
          
      -->
    
    

  接下来是安全管理器,三个属性

   
    

  然后是管理器里面的三个属性

   
   
   

  对应会话管理的最后一条属性,代码里有注释,建议看看

  

  会话DAO  

   

   这个是生命周期

   

  shiro密码加密配置

   
     
     

  密码错误一定次数后锁定账号

  

  shiro记住密码功能

   

  注入securityManager

  

  <!-- ajax session 超时处理 -->

   

  <! ---------------------------------------------------------------------------------------------------- -->

  下面是配置文件需要的一些java类

  myRealm  自定义realm

package com.conferencerooms.utils.shiro;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import org.apache.shiro.authc.AccountException;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.authc.credential.CredentialsMatcher;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.cache.CacheManager;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.apache.shiro.subject.SimplePrincipalCollection;import org.springframework.beans.factory.annotation.Autowired;import com.conferencerooms.entity.User;import com.conferencerooms.service.UserService;/** * 自定义realm *  * @author ForeignStudent * @version 2017/9/20 */public class MyRealm extends AuthorizingRealm {    private static final Logger LOGGER = LogManager.getLogger(MyRealm.class);    @Autowired    private UserService userService;    public MyRealm(CacheManager cacheManager, CredentialsMatcher matcher) {        super(cacheManager, matcher);    }    /**     * Shiro登录认证(原理:用户提交 用户名和密码 --- shiro 封装令牌 ---- realm 通过用户名将密码查询返回 ----     * shiro 自动去比较查询出密码和用户输入密码是否一致---- 进行登陆控制 )     */    @Override    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken)            throws AuthenticationException {        LOGGER.info("Shiro开始登录认证  **********doGetAuthenticationInfo**************");        UsernamePasswordToken token = (UsernamePasswordToken) authcToken;        String loginName = token.getUsername();        if (loginName == null) {            throw new AccountException("用户名不能为空");        }        User user = userService.getUsersByLoginName(loginName);        if (user != null && user.getDelFlag() != 0 && user.getStatus() != -1) {            ShiroUsers shiroUser = new ShiroUsers(user.getUserId(), user.getLoginName(), user.getUserName(), user);            return new SimpleAuthenticationInfo(shiroUser, user.getPassword(), ShiroByteSource.of(user.getSalt()),                    getName());        } else {            throw new AccountException("没有此用户");        }    }    /**     * Shiro权限认证     */    @Override    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {        ShiroUsers shiroUsers = (ShiroUsers) principals.getPrimaryPrincipal();        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();        /*         * info.setRoles(shiroUsers.getRoles());         * info.addStringPermissions(shiroUsers.getCodes());         */        return null;    }    @Override    public void onLogout(PrincipalCollection principals) {        super.clearCachedAuthorizationInfo(principals);        ShiroUsers shiroUser = (ShiroUsers) principals.getPrimaryPrincipal();        removeUserCache(shiroUser);    }    /**     * 清除用户缓存     *      * @param shiroUser     */    public void removeUserCache(ShiroUsers shiroUsers) {        removeUserCache(shiroUsers.getLoginName());    }    /**     * 清除用户缓存     *      * @param loginName     */    public void removeUserCache(String loginName) {        SimplePrincipalCollection principals = new SimplePrincipalCollection();        principals.add(loginName, super.getName());        super.clearCachedAuthenticationInfo(principals);    }}

  ShiroCacheManager  自定义缓存管理器

package com.conferencerooms.utils.shiro.cache;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import org.apache.shiro.cache.Cache;import org.apache.shiro.cache.CacheException;import org.apache.shiro.cache.CacheManager;import org.apache.shiro.util.Destroyable;public class ShiroCacheManager implements CacheManager, Destroyable {    private static final Logger logger = LogManager.getLogger(ShiroCacheManager.class);    private org.springframework.cache.CacheManager cacheManager;    public org.springframework.cache.CacheManager getCacheManager() {        return cacheManager;    }    public void setCacheManager(org.springframework.cache.CacheManager cacheManager) {        this.cacheManager = cacheManager;    }    @Override    public 
Cache
getCache(String name) throws CacheException { if (logger.isTraceEnabled()) { logger.trace("Acquiring ShiroSpringCache instance named [" + name + "]"); } org.springframework.cache.Cache cache = cacheManager.getCache(name); return new ShiroCache
(cache); } @Override public void destroy() throws Exception { cacheManager = null; }}

  ShiroCacheManager 需要的一个类

  ShiroCache  

package com.conferencerooms.utils.shiro.cache;import java.util.Collection;import java.util.Collections;import java.util.Set;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;import org.apache.shiro.cache.CacheException;import org.springframework.cache.Cache;import org.springframework.cache.Cache.ValueWrapper;@SuppressWarnings("unchecked")public class ShiroCache
implements org.apache.shiro.cache.Cache
{ private static final Logger logger = LogManager.getLogger(ShiroCache.class); private final org.springframework.cache.Cache cache; public ShiroCache(Cache cache) { if (cache == null) { throw new IllegalArgumentException("Cache argument cannot be null."); } this.cache = cache; } @Override public V get(K key) throws CacheException { if (logger.isTraceEnabled()) { logger.trace("Getting object from cache [" + this.cache.getName() + "] for key [" + key + "]key type:" + key.getClass()); } ValueWrapper valueWrapper = cache.get(key); if (valueWrapper == null) { if (logger.isTraceEnabled()) { logger.trace("Element for [" + key + "] is null."); } return null; } return (V) valueWrapper.get(); } @Override public V put(K key, V value) throws CacheException { if (logger.isTraceEnabled()) { logger.trace("Putting object in cache [" + this.cache.getName() + "] for key [" + key + "]key type:" + key.getClass()); } V previous = get(key); cache.put(key, value); return previous; } @Override public V remove(K key) throws CacheException { if (logger.isTraceEnabled()) { logger.trace("Removing object from cache [" + this.cache.getName() + "] for key [" + key + "]key type:" + key.getClass()); } V previous = get(key); cache.evict(key); return previous; } @Override public void clear() throws CacheException { if (logger.isTraceEnabled()) { logger.trace("Clearing all objects from cache [" + this.cache.getName() + "]"); } cache.clear(); } @Override public int size() { return 0; } @Override public Set
keys() { return Collections.emptySet(); } @Override public Collection
values() { return Collections.emptySet(); } @Override public String toString() { return "ShiroSpringCache [" + this.cache.getName() + "]"; }}

  PasswordHash 密码加密配置

package com.conferencerooms.utils.shiro;import org.apache.shiro.crypto.hash.SimpleHash;import org.springframework.beans.factory.InitializingBean;import org.springframework.util.Assert;/** * shiro密码加密配置 *  * @author ForeignStudent * @version 2017/9/20 */public class PasswordHash implements InitializingBean {    private String algorithmName;    private int hashIterations;    @Override    public void afterPropertiesSet() throws Exception {        Assert.hasLength(algorithmName, "algorithmName mast be MD5、SHA-1、SHA-256、SHA-384、SHA-512");    }    public String toHex(Object source, Object salt) {        return new SimpleHash(algorithmName, source, salt, hashIterations).toHex();    }    public String getAlgorithmName() {        return algorithmName;    }    public void setAlgorithmName(String algorithmName) {        this.algorithmName = algorithmName;    }    public int getHashIterations() {        return hashIterations;    }    public void setHashIterations(int hashIterations) {        this.hashIterations = hashIterations;    }}

  RetryLimitCredentialsMatcher 锁定   这里锁定的是5次

package com.conferencerooms.utils.shiro;import java.util.concurrent.atomic.AtomicInteger;import org.apache.logging.log4j.LogManager;import org.apache.logging.log4j.Logger;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;import org.springframework.beans.factory.InitializingBean;import org.springframework.util.Assert;/** * 密码错误5次锁定半小时 *  * @author ForeignStudent * @version 2017/9/20 */public class RetryLimitCredentialsMatcher extends HashedCredentialsMatcher implements InitializingBean {    private final static Logger logger = LogManager.getLogger(RetryLimitCredentialsMatcher.class);    private final static String DEFAULT_CHACHE_NAME = "retryLimitCache";    private final CacheManager cacheManager;    private String retryLimitCacheName;    private Cache
passwordRetryCache; private PasswordHash passwordHash; public RetryLimitCredentialsMatcher(CacheManager cacheManager) { this.cacheManager = cacheManager; this.retryLimitCacheName = DEFAULT_CHACHE_NAME; } public String getRetryLimitCacheName() { return retryLimitCacheName; } public void setRetryLimitCacheName(String retryLimitCacheName) { this.retryLimitCacheName = retryLimitCacheName; } public void setPasswordHash(PasswordHash passwordHash) { this.passwordHash = passwordHash; } @Override public boolean doCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo info) { String username = (String) authcToken.getPrincipal(); // retry count + 1 AtomicInteger retryCount = passwordRetryCache.get(username); if (retryCount == null) { retryCount = new AtomicInteger(0); passwordRetryCache.put(username, retryCount); } if (retryCount.incrementAndGet() > 5) { logger.warn("username: " + username + " tried to login more than 5 times in period"); throw new ExcessiveAttemptsException("用户名: " + username + " 密码连续输入错误超过5次,锁定半小时!"); } boolean matches = super.doCredentialsMatch(authcToken, info); if (matches) { passwordRetryCache.remove(username); } return matches; } @Override public void afterPropertiesSet() throws Exception { Assert.notNull(passwordHash, "you must set passwordHash!"); super.setHashAlgorithmName(passwordHash.getAlgorithmName()); super.setHashIterations(passwordHash.getHashIterations()); this.passwordRetryCache = cacheManager.getCache(retryLimitCacheName); }}

  <!-- ajax session超时时处理 -->

package com.conferencerooms.utils.shiro;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import org.apache.shiro.web.filter.authc.UserFilter;import org.apache.shiro.web.util.WebUtils;import com.conferencerooms.utils.StringUtils;/** * ajax超时处理类 *  * @author ForeignStudent * @version 2017/9/20 */public class ShiroAjaxSessionFilter extends UserFilter {    @Override    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {        HttpServletRequest req = WebUtils.toHttp(request);        String xmlHttpRequest = req.getHeader("X-Requested-With");        if (StringUtils.isNotBlank(xmlHttpRequest)) {            if (xmlHttpRequest.equalsIgnoreCase("XMLHttpRequest")) {                HttpServletResponse res = WebUtils.toHttp(response);                // 采用res.sendError(401);在Easyui中会处理掉error,$.ajaxSetup中监听不到                res.setHeader("oauthstatus", "401");                return false;            }        }        return super.onAccessDenied(request, response);    }}

shiro配置到此为之差不多了,以上大部分内容是网上整理来的   都是经过测试可用的,其中多处都是手打,测试时多注意下就OK了

  其中有几个地方不是很明白,在注释中也名提了下,如果哪位大神可以告知,感激不尽。

转载于:https://www.cnblogs.com/foreign-student/p/7592189.html

你可能感兴趣的文章
ExtJS下拉树
查看>>
android 调用系统相机录像并保存
查看>>
BW系统表的命名规则
查看>>
Asp.Net在IE10下出现_doPostBack未定义的解决办法 LinkButton
查看>>
《CLR via C#》Part2之Chapter5 基元类型、引用类型和值类型(一)
查看>>
接口和抽象类的对比,面向对象的三大特性和四大特性
查看>>
1-9 RHEL7-文件权限管理
查看>>
apache服务器安装
查看>>
Search a 2D Matrix
查看>>
文件解析漏洞
查看>>
弹性成像的一些术语
查看>>
ListBox 消息 (zz)
查看>>
计算机网络之万维网WWW
查看>>
作业2
查看>>
vim 笔记
查看>>
MySQL的基本使用命令
查看>>
第三次作业
查看>>
蓝桥杯-猜算式
查看>>
PHP定界符<<<EOF
查看>>
05_模板方法模式
查看>>