springboot+shiro+ehcache

 

项目中有使用shiro特地把它记录下来,免得自己又忘了:

<dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>${shiro-version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${shiro-version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>${shiro-version}</version>
        </dependency>
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache</artifactId>
            <version>2.4.8</version>
        </dependency>

ehcahe的版本使用的2.5之前的版本,2.5之后的版本不允许使用同一个缓存空间;

自己定义的一个缓存对象,自定义两个方法存取:

package com.koala.console.cache;

import lombok.Data;

import java.io.Serializable;

/**
 * @author PC_gongyiyang
 * @Auther: gongyiyang
 * @Date: 2018/10/18 19:19
 * @Description:
 */
@Data
public class AuthenticationSession implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * @Fields <font color="blue">cacheName</font>
     * @description 缓存名
     */
    private String cacheName;
    /**
     * @Fields <font color="blue">identify</font>
     * @description 唯一区别串
     */
    private String identify;
    /**
     * @Fields <font color="blue">data</font>
     * @description 缓存主体数据
     */
    private Object data;


    public AuthenticationSession() {

    }

    public AuthenticationSession(String cacheName, String identify) {
        this.cacheName = cacheName;
        this.identify = identify;
    }

    public AuthenticationSession(String cacheName, String identify, Object data) {
        this.cacheName = cacheName;
        this.identify = identify;
        this.data = data;
    }

    public <T> T get(Class<T> type) {
        return data == null ? null : (T) data;
    }

}
package com.koala.console.cache;

import com.koala.console.constant.ModelConstant;
import org.apache.commons.lang.StringUtils;
import org.springframework.cache.Cache;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.stereotype.Component;

/**
 * @author PC_gongyiyang
 * @Auther: gongyiyang
 * @Date: 2018/10/18 18:07
 * @Description:
 */
@Component
public class EhcacheCacheManager extends EhCacheCacheManager {

    public void setSession(AuthenticationSession session) {
        this.getCache(session.getCacheName()).put(session.getIdentify().substring(ModelConstant.TOKEN_LENGTH), session);
    }

    public AuthenticationSession getSession(AuthenticationSession session) {
        if (StringUtils.isBlank(session.getCacheName())) {
            throw new RuntimeException("cache name is empty");
        }
        String identify = session.getIdentify();
        if (StringUtils.isBlank(identify) || identify.length() <= ModelConstant.TOKEN_LENGTH) {
            throw new RuntimeException("login token identify length lacks");
        }
        Cache cache = this.getCache(session.getCacheName());
        AuthenticationSession authenticationSession = cache.get(identify.substring(ModelConstant.TOKEN_LENGTH), AuthenticationSession.class);
        if (authenticationSession != null && identify.equals(authenticationSession.getIdentify())) {
            return authenticationSession;
        }
        return null;
    }

}

 

package com.koala.console.ac.oauth2;

import com.koala.console.constant.StatusCode;
import com.koala.console.exception.GlobalException;
import lombok.extern.slf4j.Slf4j;

import java.security.MessageDigest;
import java.util.UUID;


/**
 * @author <font color="red"><b>Gong.YiYang</b></font>
 * @Date 2018年8月27日
 * @Version
 * @Description 生成token
 */
@Slf4j
public class TokenGenerator {

    private TokenGenerator() {
    }

    static String uu;

    public static String generateValue() {
        try {
            uu = generateValue(UUID.randomUUID().toString());
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return uu;
    }

    private static final char[] HEX_CODE = "0123456789abcdef".toCharArray();

    public static String toHexString(byte[] data) {
        if (data == null) {
            return null;
        }
        StringBuilder r = new StringBuilder(data.length * 2);
        for (byte b : data) {
            r.append(HEX_CODE[(b >> 4) & 0xF]);
            r.append(HEX_CODE[(b & 0xF)]);
        }
        return r.toString();
    }

    public static String generateValue(String param) throws GlobalException {
        try {
            MessageDigest algorithm = MessageDigest.getInstance("MD5");
            algorithm.reset();
            algorithm.update(UUID.randomUUID().toString().getBytes());
            byte[] messageDigest = algorithm.digest();
            return toHexString(messageDigest) + param;
        } catch (Exception e) {
            throw new GlobalException(StatusCode.FAILED, "生成Token失败");
        }
    }
}
package com.koala.console.ac.config;

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.filter.DelegatingFilterProxy;


/**
 * @author <font color="red"><b>Gong.YiYang</b></font>
 * @Date 2018年8月27日
 * @Version 
 * @Description Filter配置
 */
@Configuration
public class FilterConfig {

	@Bean
    public FilterRegistrationBean shiroFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new DelegatingFilterProxy("shiroFilter"));
        //该值缺省为false,表示生命周期由SpringApplicationContext管理,设置为true则表示由ServletContainer管理
        registration.addInitParameter("targetFilterLifecycle", "true");
        registration.setEnabled(true);
        registration.setOrder(Integer.MAX_VALUE - 1);
        registration.addUrlPatterns("/*");
        return registration;
    }

}
package com.koala.console.ac.config;

import com.koala.console.ac.oauth2.Oauth2Filter;
import com.koala.console.ac.oauth2.Oauth2Realm;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author <font color="red"><b>Gong.YiYang</b></font>
 * @Date 2018年8月27日
 * @Version
 * @Description Shiro配置
 */
@Configuration
public class ShiroConfig {

    @Bean("oAuth2Realm")
    public Oauth2Realm oauth2Realm() {
        Oauth2Realm oauth2Realm = new Oauth2Realm();
        oauth2Realm.setCacheManager(ehCacheManager());
        oauth2Realm.setAuthorizationCacheName("authorization_cache");
        oauth2Realm.setAuthenticationCacheName("authentication_cache");
        return oauth2Realm;
    }

    @Bean("sessionManager")
    public SessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionValidationSchedulerEnabled(true);
        sessionManager.setSessionIdCookieEnabled(false);
        return sessionManager;
    }

    @Bean("securityManager")
    public SecurityManager securityManager(Oauth2Realm oAuth2Realm, SessionManager sessionManager) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(oAuth2Realm);
        securityManager.setCacheManager(ehCacheManager());
        securityManager.setSessionManager(sessionManager);

        return securityManager;
    }

    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
        shiroFilter.setSecurityManager(securityManager);
        // oauth过滤
        Map<String, Filter> filters = new HashMap<>(16);
        filters.put("oauth2", new Oauth2Filter());
        shiroFilter.setFilters(filters);
        Map<String, String> filterMap = new LinkedHashMap<>();
        filterMap.put("/api/v1/ac/user/token/login", "anon");
        filterMap.put("/api/v1/classificationPicture/findClassificationPictureById", "anon");
        filterMap.put("/api/v1/file/**", "anon");
        filterMap.put("/api/**", "oauth2");
        filterMap.put("/**", "anon");
        shiroFilter.setFilterChainDefinitionMap(filterMap);

        return shiroFilter;
    }

    @Bean("lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
        proxyCreator.setProxyTargetClass(true);
        return proxyCreator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

    @Bean
    public EhCacheManager ehCacheManager() {
        EhCacheManager manager = new EhCacheManager();
        manager.setCacheManagerConfigFile("classpath:ehcache.xml");
        return manager;
    }
}
package com.koala.console.ac.oauth2;

import com.alibaba.fastjson.JSON;
import com.koala.console.utils.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpStatus;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


/**
 * @author <font color="red"><b>Gong.YiYang</b></font>
 * @Date 2018年8月27日
 * @Version
 * @Description oauth2过滤器 自定义token替换shiro的token实现
 */
@Slf4j
public class Oauth2Filter extends AuthenticatingFilter {

    @Override
    protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
        //获取请求token
        String token = getRequestToken((HttpServletRequest) request);

        if(StringUtils.isBlank(token)){
            return null;
        }

        return new Oauth2Token(token);
    }

    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        return false;
    }

    /**
     * 检查token
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
        //获取请求token,如果token不存在,直接返回401
        String token = getRequestToken((HttpServletRequest) request);
        if(StringUtils.isBlank(token)){
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            Result<Void> result = new Result<>();
            result.setStatus(HttpStatus.SC_UNAUTHORIZED);
            result.setMessage("Token can not be empty");
            String json = JSON.toJSONString(result);
            httpResponse.getWriter().print(json);

            return false;
        }

        return executeLogin(request, response);
    }

    /**
     * 登录失败
     */
    @Override
    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        httpResponse.setContentType("application/json;charset=utf-8");
        try {
            Throwable throwable = e.getCause() == null ? e : e.getCause();
            Result<Void> result = new Result<>();
            result.setStatus(HttpStatus.SC_UNAUTHORIZED);
            result.setMessage(throwable.getMessage());
            String json = JSON.toJSONString(result);
            httpResponse.getWriter().print(json);
        } catch (Exception ee) {
            log.debug("登录失败");
        }

        return false;
    }

    /**
     * 获取请求的token
     */
    private String getRequestToken(HttpServletRequest httpRequest){
        //从header中获取token
        String token = httpRequest.getHeader("token");
        //如果header中不存在token,则从参数中获取token
        if(StringUtils.isBlank(token)){
            token = httpRequest.getParameter("token");
        }
        return token;
    }


}
package com.koala.console.ac.oauth2;

import com.koala.console.ac.model.SysUser;
import com.koala.console.ac.service.SysUserService;
import com.koala.console.cache.AuthenticationSession;
import com.koala.console.cache.EhcacheCacheManager;
import com.koala.console.constant.ModelConstant;
import com.koala.console.utils.ShiroUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

import javax.annotation.Resource;
import java.util.Set;


/**
 * @author <font color="red"><b>Gong.YiYang</b></font>
 * @Date 2018年8月27日
 * @Version
 * @Description 认证
 */
public class Oauth2Realm extends AuthorizingRealm {

    @Resource
    private EhcacheCacheManager cacheManager;
    @Autowired
    @Lazy
    private SysUserService sysUserService;

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof Oauth2Token;
    }

    /**
     * 授权(验证权限时调用)
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        Long userId = ShiroUtils.getUserId();
        //用户角色
        Set<String> rolesSet = sysUserService.listUserRoles(userId);
        //用户权限
        Set<String> permsSet = sysUserService.listUserPerms(userId);
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(rolesSet);
        info.setStringPermissions(permsSet);
        return info;
    }

    /**
     * 认证(登录时调用)
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
        String accessToken = (String) token.getPrincipal();
        AuthenticationSession session = cacheManager.getSession(new AuthenticationSession(ModelConstant.CLOUD_USER, accessToken));
        //token失效
        if (session == null) {
            throw new IncorrectCredentialsException("token失效,请重新登录");
        }
        SysUser sysUser = session.get(SysUser.class);
        //查询用户信息
        SysUser user = sysUserService.getUserById(sysUser.getId());
        //账号锁定
        if (null == user || user.getStatus() == 0) {
            throw new LockedAccountException("账号已被锁定,请联系管理员");
        }
        return new SimpleAuthenticationInfo(user, accessToken, getName());
    }

}
package com.koala.console.ac.oauth2;


import org.apache.shiro.authc.AuthenticationToken;


/**
 * @author <font color="red"><b>Gong.YiYang</b></font>
 * @Date 2018年8月27日
 * @Version
 * @Description token
 */
public class Oauth2Token implements AuthenticationToken {

	private static final long serialVersionUID = 1L;

	private String token;

    public Oauth2Token(String token){
        this.token = token;
    }

    @Override
    public String getPrincipal() {
        return token;
    }

    @Override
    public Object getCredentials() {
       return getPrincipal();
    }
}
public Result<SysUserToken> login(@RequestBody SysUser sysUser) {
		Result<SysUserToken> res = new Result<>();
		try {

			SysUser user = sysUserService.getByUserName(sysUser.getUsername());
			if (user == null || !sysUser.getPassword().equals(user.getPassword())) {
				res.setStatus(StatusCode.FAILED);
				res.setMessage("用户名或密码错误");
				return res;
			} else if (user.getStatus() == 0) {
				res.setStatus(StatusCode.ACCOUNT_LOCKOUT);
				res.setMessage("账号已被锁定,请联系管理员");
				return res;
			}
			SysUserToken sysUserToken = sysUserService.saveUserToken(user);
			List<String> rolelist = sysUserService.getRoleByUserId(user.getId());
			sysUserToken.setRoleName(rolelist);
			res.setData(sysUserToken);
			res.setStatus(StatusCode.SUCCESSFUL);
			res.setMessage("登录成功");
		} catch (Exception e) {
			res.setStatus(StatusCode.FAILED);
			res.setMessage(e.getMessage());
		}
		return res;
	}
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
         updateCheck="false">

    <diskStore path="java.io.tmpdir/Tmp_EhCache"/>

    <defaultCache
            eternal="false"
            maxElementsInMemory="10000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="259200"
            memoryStoreEvictionPolicy="LRU"/>

    <cache
            name="cloud_user"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>
    <cache
            name="authentication_cache"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>
    <cache
            name="authorization_cache"
            eternal="false"
            maxElementsInMemory="5000"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="1800"
            timeToLiveSeconds="1800"
            memoryStoreEvictionPolicy="LRU"/>

</ehcache>

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值