0
点赞
收藏
分享

微信扫一扫

87-springboot+shiro+redis的配置及使用

application-dev.yml

server:
  port: 8080
  servlet:
    context-path: /
ip:
  mysql: localhost:3306
  localhost: localhost


spring:
  datasource:
    username: root
    password: 123456
    url: jdbc:mysql://${ip.mysql}/kuma?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver

  redis:
    host: ${ip.localhost}
    port: 6379
    jedis:
      pool:
        max-idle: 8
        min-idle: 0
        max-active: 8
        max-wait: -1
    timeout: 0
#  jpa:
#    hibernate:
#      ddl-auto: none
#    show-sql: true
  thymeleaf:
    cache: false

  devtools:
    restart:
      enabled: false
#      additional-paths: resources/**,static/**,templates/**,src/main/java

  resources:
    static-locations: classpath:/static/, classpath:/templates/

#  cache:
#    ehcache:
#      config: classpath:ehcache.xml
#
  cache:
    type: simple
  # 每次应用启动不检查Activiti数据表是否存在及版本号是否匹配,提升应用启动速度
#  activiti:
#    database-schema-update: false
#    history-level: full
#    font:
#      activityFontName: 宋体
#      labelFontName: 宋体
#    check-process-definitions: true


mybatis:
  mapper-locations: classpath:mapping/**/*.xml
  type-aliases-package: com.kuma.platform.model

#zookeeper:
#  address: 127.0.0.1:2181
#  timeout: 4000

#showSql
logging:
  level:
    com:
      kuma:
        platform:
          dao: debug

upload:
  server:
    domain: http://${ip.localhost}:${server.port}${server.servlet.context-path}
  image:
    dir: D:/upload/images
    format: swf,wmv,gif,png,jpg,jpeg,bmp
    size: 151200000
  file:
    dir: D:/upload/file
  video:
    dir: D:/upload/video

SpringShiroConfig.java

package com.kuma.platform.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.kuma.platform.shiro.CustomRealm;
import org.apache.shiro.mgt.SecurityManager;
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.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.MethodInvokingFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class SpringShiroConfig {

	@Value("${spring.redis.host}")
	String host;
	@Value("${spring.redis.port}")
	int port;
	@Value("${spring.redis.timeout}")
	private int timeout;

	@Autowired
	private CustomRealm realm;

	public SpringShiroConfig() {
		System.out.println("SpringShiroConfig init ......");
	}
	@Bean(name = "lifecycleBeanPostProcessor")
	public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
		return new LifecycleBeanPostProcessor();
	}

	@Bean
	@DependsOn("lifecycleBeanPostProcessor")
	public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
		DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
		creator.setProxyTargetClass(true);
//		creator.setUsePrefix(true);
		return creator;
	}


	@Bean
	public MethodInvokingFactoryBean getMethodInvokingFactoryBean(@Qualifier("securityManager")SecurityManager securityManager) {
		MethodInvokingFactoryBean methodInvokingFactoryBean=new MethodInvokingFactoryBean();
		methodInvokingFactoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager");
		methodInvokingFactoryBean.setArguments(securityManager);
		return methodInvokingFactoryBean;
	}



	//get
	@Bean
	public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager")SecurityManager securityManager) {
		AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
		authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
		return authorizationAttributeSourceAdvisor;
	}


	//get
	@Bean(name = "shiroFilter")
	public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager")SecurityManager securityManager){
		ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
		shiroFilterFactoryBean.setLoginUrl("/logon");
		shiroFilterFactoryBean.setUnauthorizedUrl("/logon");
		shiroFilterFactoryBean.setSuccessUrl("/index");
//		shiroFilterFactoryBean.setLoginUrl("/user/login.html");
//		shiroFilterFactoryBean.setUnauthorizedUrl("/user/login.html");
		shiroFilterFactoryBean.setSecurityManager(securityManager);

		loadShiroFilterChain(shiroFilterFactoryBean);

		return shiroFilterFactoryBean;
	}
	//get
	private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean) {
		Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
		filterChainDefinitionMap.put("/layuiadmin/**", "anon");

		filterChainDefinitionMap.put("/login.html", "anon");
		filterChainDefinitionMap.put("/**/login/**", "anon");
		filterChainDefinitionMap.put("/api/**", "anon");
		filterChainDefinitionMap.put("/logon", "anon");
		filterChainDefinitionMap.put("/logout", "anon");
		filterChainDefinitionMap.put("/", "anon");

		filterChainDefinitionMap.put("/index", "user");
		filterChainDefinitionMap.put("/index.html", "user");


		filterChainDefinitionMap.put("/**", "authc");

		/*
		 * filterChainDefinitionMap.put("/mydemo/login", "anon");
		 * filterChainDefinitionMap.put("/user/info**", "authc");
		 * filterChainDefinitionMap.put("/admin/listUser**","authc,perms[admin:manage]");
		 */

		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
	}

	//get
	@Bean(name = "sessionManager")
	public DefaultWebSessionManager sessionManager(){
		DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
		sessionManager.setCacheManager(cacheManager());
		sessionManager.setGlobalSessionTimeout(1000*60);//单位:毫秒
//		sessionManager.setDeleteInvalidSessions(true);
		sessionManager.setSessionIdCookieEnabled(true);
		sessionManager.setSessionDAO(redisSessionDAO());
		return sessionManager;
	}


	//get
	@Bean(name = "securityManager")
	public DefaultWebSecurityManager securityManager(@Qualifier("sessionManager") DefaultWebSessionManager sessionManager) {
		DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
		securityManager.setRealm(realm);
		securityManager.setSessionManager(sessionManager);
		securityManager.setCacheManager(cacheManager());
		securityManager.setRememberMeManager(rememberMeManager());
		return securityManager;
	}


	public SimpleCookie rememberMeCookie() {
		// 这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
		SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
		// 记住我cookie生效时间30天 ,单位秒。 注释掉,默认永久不过期 2018-07-15
        simpleCookie.setMaxAge(60*60);
		return simpleCookie;
	}
	/**
	 * cookie管理对象;记住我功能
	 *
	 * @return
	 */
	public CookieRememberMeManager rememberMeManager() {
		CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
		cookieRememberMeManager.setCookie(rememberMeCookie());
		//rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
//		cookieRememberMeManager.setCipherKey(Base64.decode("1QWLxg+NYmxraMoxAXu/Iw=="));
		return cookieRememberMeManager;
	}

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


	/**
	 * cacheManager 缓存 redis实现
	 * 使用的是shiro-redis开源插件
	 *
	 * @return
	 */
	public RedisCacheManager cacheManager() {
		RedisCacheManager redisCacheManager = new RedisCacheManager();
		redisCacheManager.setRedisManager(redisManager());
		return redisCacheManager;
	}

	/**
	 * 配置shiro redisManager
	 * 使用的是shiro-redis开源插件
	 *
	 * @return
	 */
	public RedisManager redisManager() {
		RedisManager redisManager = new RedisManager();
		redisManager.setHost(host);
		redisManager.setPort(port);
		redisManager.setExpire(1800);// 配置缓存过期时间
		redisManager.setTimeout(timeout);
		return redisManager;
	}

	/**
	 * RedisSessionDAO shiro sessionDao层的实现 通过redis
	 * 使用的是shiro-redis开源插件
	 */
	@Bean
	public RedisSessionDAO redisSessionDAO() {
		RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
		redisSessionDAO.setRedisManager(redisManager());
		return redisSessionDAO;
	}

}

CustomRealm.java

package com.kuma.platform.shiro;

import com.kuma.platform.model.po.admin.AdminMenuPo;
import com.kuma.platform.model.po.admin.AdminUserPo;
import com.kuma.platform.service.admin.AdminMenuService;
import com.kuma.platform.service.admin.AdminUserService;
import com.kuma.platform.utils.RedisApiUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
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.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * 自定义Realm
 * @author super_dev_001
 * @date 2020/4/6
 * @param
 * @return
 */
@Component
public class CustomRealm extends AuthorizingRealm {
	@Autowired
	private AdminUserService adminUserService;
	@Autowired
	private AdminMenuService adminMenuService;


	private static Logger logger= LoggerFactory.getLogger(CustomRealm.class);

	public CustomRealm() {
		logger.info("CustomRealm====================");
	}


	@Override
	public String getName() {
		return "CustomRealm";
	}

	@Bean(name = "credentialsMatcher")
	public HashedCredentialsMatcher credentialsMatcher(){
		HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
		credentialsMatcher.setHashAlgorithmName("md5");
		credentialsMatcher.setHashIterations(1024);
		return credentialsMatcher;
	}

	@Override
	public void setCredentialsMatcher(@Qualifier("credentialsMatcher")CredentialsMatcher credentialsMatcher){
		super.setCredentialsMatcher(credentialsMatcher);
	}

	/**
	 * realm授权方法 从输入参数principalCollection得到身份信息 根据身份信息到数据库查找权限信息 将权限信息添加给授权信息对象
	 * 返回 授权信息对象(判断用户访问url是否在权限信息中没有体现)
	 */
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
		AdminUserPo user = null;
//		AdminUserPo user = (AdminUserPo) principalCollection.getPrimaryPrincipal();

		Long userId = (Long)principalCollection.getPrimaryPrincipal();

		List<String> btnList = null;
		try{
			user = this.adminUserService.queryById(userId);
			String roleIds = user.getRoleIds();
			btnList = adminMenuService.queryBtnsByRoles(roleIds);
		}catch (Exception e){
			e.printStackTrace();
		}
		// 用户权限列表
		Set<String> permsSet = new HashSet<String>();
		if(btnList!=null && btnList.size()>0){
			permsSet.addAll(btnList);
		}
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		info.setStringPermissions(permsSet);
		return info;
	}

	/**
	 * 表单认证过滤器认证时会调用自定义Realm的认证方法进行认证,成功回到index.do,再跳转到index.jsp页面
	 *
	 * 前提:表单认证过滤器收集和组织用户名和密码信息封装为token对象传递给此方法
	 *
	 * token:封装了身份信息和凭证信息 2步骤:比对身份 信息;比对凭证
	 */
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
		UsernamePasswordToken upToken = (UsernamePasswordToken) token;
		String username = upToken.getUsername();
		String password = new String((char[]) token.getCredentials());

		// 查询用户信息
		AdminUserPo adminUserPo = null;
		try{
			adminUserPo = adminUserService.queryByUserName(username);
		}catch (Exception e){
			e.printStackTrace();
		}

		// 账号不存在
		if (adminUserPo == null ) {
			throw new UnknownAccountException("账号不存在!");
		}
		// 密码错误
		if (!password.equals(adminUserPo.getPassword())) {
			throw new IncorrectCredentialsException("账号或密码不正确!");
		}

		// 账号未分配角色
		if (adminUserPo.getRoleIds() == null ) {
			throw new UnknownAccountException("账号未分配角色!");
		}

		//super_dev_001 2020/2/8 登录成功,查询菜单
		try{
			List<AdminMenuPo> menuList = this.adminMenuService.queryByRoles(adminUserPo.getRoleIds());
			adminUserPo.setMenuList(menuList);
			RedisApiUtils.save(""+adminUserPo.getId(),adminUserPo);
//			EhcacheUtils.putUser(adminUserPo);
		}catch (Exception e){
			e.printStackTrace();
		}
		SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(adminUserPo.getId(), password, ByteSource.Util.bytes(username), getName());
		return info;
	}
}

ShiroUtils.java

package com.kuma.platform.shiro;

import com.alibaba.fastjson.JSON;
import com.kuma.platform.model.po.admin.AdminUserPo;
import com.kuma.platform.utils.RedisApiUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;

/**
 * super_dev_001 2020/2/3
 */
public class ShiroUtils {
    public static Session getSession() {
        return SecurityUtils.getSubject().getSession(true);
    }

    public static Subject getSubject() {
        return SecurityUtils.getSubject();
    }

    public static AdminUserPo getUserEntity() {
        Long userId = (Long)getSubject().getPrincipal();
        Object userObj = RedisApiUtils.get(""+userId);

        if(userObj!=null){
            AdminUserPo rec = JSON.parseObject(JSON.toJSONString(userObj),AdminUserPo.class);
            return rec;
        }
        return null;
    }

    public static Long getUserId() {
        return getUserEntity()==null?null:getUserEntity().getId();
    }
    public static String getUserName() {
        return getUserEntity()==null?null:getUserEntity().getUserName();
    }

    public static void setSessionAttribute(Object key, Object value) {
        getSession().setAttribute(key, value);
    }

    public static Object getSessionAttribute(Object key) {
        return getSession().getAttribute(key);
    }

    public static boolean isLogin() {
        return SecurityUtils.getSubject().getPrincipal() != null;
    }

    public static void logout() {
        RedisApiUtils.del(""+getUserId());
        SecurityUtils.getSubject().logout();

//        EhcacheUtils.removeUser();
    }

    public static String getKaptcha(String key) {
        String kaptcha = getSessionAttribute(key).toString();
        getSession().removeAttribute(key);
        return kaptcha;
    }
}

RedisApiUtils.java

package com.kuma.platform.utils;

import com.alibaba.fastjson.JSON;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import javax.annotation.PostConstruct;


/**
 * super_dev_007 2020/11/26
 */
@Component
public class RedisApiUtils{

    @Value("${spring.redis.host}")
    String host;
    @Value("${spring.redis.port}")
    int port;
    @Value("${spring.redis.timeout}")
    private int timeout;
    @Value("${spring.redis.jedis.pool.max-idle}")
    private int maxIdle;
    @Value("${spring.redis.jedis.pool.max-wait}")
    private long maxWaitMillis;

    @Autowired
    RedisSessionDAO redisSessionDAO;

    @Autowired
    JedisPool jedisPool;

    Jedis jedis;

    public static String pre = "re_";

    @Bean
    public JedisPool redisPoolFactory() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);

        JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port, timeout);

        return jedisPool;
    }


    private static RedisApiUtils staticInstance = new RedisApiUtils();
    @PostConstruct
    public void init(){
        staticInstance.redisSessionDAO = redisSessionDAO;
        staticInstance.jedisPool = jedisPool;
        staticInstance.jedis = jedisPool.getResource();
    }


    public static Object get(String key){
        String value = staticInstance.jedis.get(pre+key);
        return JSON.parseObject(value);
    }

    public static void save(String key,Object value){
        staticInstance.jedis.set(pre+key,JSON.toJSONString(value));
    }

    public static void del(String key){
        staticInstance.jedis.del(pre+key);
    }

}

最后是登录方法:

@RequestMapping(value = "login")
	@ResponseBody
	public Object login(@ModelAttribute("user") LoginUser user, HttpServletRequest request, Model model, HttpSession session) {
		BaseResp resp = new BaseResp();

		String access_token = "" + IdUtils.id();
		JSONObject jsonObject = new JSONObject();
		/**
		 * 使用Shiro编写认证操作
		 */
		try {
			Subject subject = SecurityUtils.getSubject();
			UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(),
					CommonUtils.md5(user.getPassword()),user.getRememberMe());
			subject.login(token);

			AdminUserPo adminUserPo = ShiroUtils.getUserEntity();

			jsonObject.put("access_token", access_token);
			jsonObject.put("user", rtnUser(adminUserPo));
			resp.setData(jsonObject);

			model.addAttribute("user",adminUserPo);
		} catch (UnknownAccountException e) {
			resp.setSuccess(false);
			resp.setMsg(e.getMessage());
		} catch (IncorrectCredentialsException e) {
			resp.setSuccess(false);
			resp.setMsg(e.getMessage());
		} catch (Exception e) {
			e.printStackTrace();
			resp.setSuccess(false);
			resp.setMsg("系统异常,请稍后再试");
		}
		return resp;
	}
举报

相关推荐

0 条评论