SpringBoot配置shiro安全框架的实现

作者:BeiShangBuZaiLai 时间:2023-09-07 19:55:38 

首先引入pom


 <!--SpringBoot 2.1.0-->
 <parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>2.1.0.RELEASE</version>
 </parent>
 <!--shiro-->
 <dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-core</artifactId>
  <version>${shiro.version}</version>
 </dependency>
 <dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-web</artifactId>
  <version>${shiro.version}</version>
 </dependency>
 <dependency>
  <groupId>org.apache.shiro</groupId>
  <artifactId>shiro-spring</artifactId>
  <version>${shiro.version}</version>
 </dependency>
 <!-- shiro-redis -->
 <dependency>
  <groupId>org.crazycake</groupId>
  <artifactId>shiro-redis</artifactId>
  <version>3.1.0</version>
 </dependency>

<!-- shiro-freemarker-tag -->
 <dependency>
  <groupId>net.mingsoft</groupId>
  <artifactId>shiro-freemarker-tags</artifactId>
  <version>1.0.0</version>
 </dependency>

<!-- freemarker -->
 <dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-freemarker</artifactId>
 </dependency>

ShiroConfig.java


package com.jx.cert.web.framework.config.shiro;

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

import javax.servlet.Filter;

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.MemoryConstrainedCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import com.jx.cert.web.framework.config.shiro.filter.KickoutSessionControlFilter;
import com.jx.cert.web.framework.config.shiro.filter.ShiroPermissionsFilter;
import com.jx.cert.web.framework.config.shiro.filter.SystemLogoutFilter;
import com.jx.common.utils.CacheConstants;

/**
* @ClassName: gyu  
* @Description: TODO(shrio配置)  
* @author gangyu
* @date 2018年12月4日 下午2:28:07  
*/
@Configuration
public class ShiroConfig {
Logger log=LoggerFactory.getLogger(ShiroConfig.class);
@Value("${spring.redis.host}")
   private String host;
   @Value("${spring.redis.prot}")
   private int port;
   @Value("${spring.redis.timeout}")
   private int timeout;
   @Value("${spring.redis.password}")
   private String password;
   @Value("${spring.redis.database}")
   private int database;

//注意这里需要设置成 static 否则 @Value 注入不了数据
   @Bean(name = "lifecycleBeanPostProcessor")
   public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
       return new LifecycleBeanPostProcessor();
   }

@Bean(name = "shiroFilter")
   public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
 ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
 log.debug("-----------------Shiro * 工厂类注入开始");

Map<String,Filter> filterMap=shiroFilterFactoryBean.getFilters();
 //权限过滤器
 filterMap.put("perms", new ShiroPermissionsFilter());

shiroFilterFactoryBean.setFilters(filterMap);

// 配置shiro安全管理器 SecurityManager
 shiroFilterFactoryBean.setSecurityManager(securityManager);

// 指定要求登录时的链接
 shiroFilterFactoryBean.setLoginUrl("/login");
 // 登录成功后要跳转的链接
 shiroFilterFactoryBean.setSuccessUrl("/index");

// filterChainDefinitions * =map必须用:LinkedHashMap,因为它必须保证有序
 Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();

//对外应用开发接口不验证
 filterChainDefinitionMap.put("/app/**", "anon");
       filterChainDefinitionMap.put("/ajaxLogin", "anon");
       // 放开验证码
 filterChainDefinitionMap.put("/public/getGifCode", "anon");
 // 退出
 filterChainDefinitionMap.put("/logout", "logout");

//TODO 全部放行
//  filterChainDefinitionMap.put("/manage/**", "anon[*]");

//公共资源
       filterChainDefinitionMap.put("/static/**", "anon");
       filterChainDefinitionMap.put("/css/**", "anon");
       filterChainDefinitionMap.put("/img/**", "anon");
       filterChainDefinitionMap.put("/js/**", "anon");

// authc:所有url都必须认证通过才可以访问;
 filterChainDefinitionMap.put("/**", "authc");
 shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
 log.debug("-----------------Shiro * 工厂类注入成功");
 return shiroFilterFactoryBean;
   }

@Bean
   public HashedCredentialsMatcher hashedCredentialsMatcher() {
       HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
       hashedCredentialsMatcher.setHashAlgorithmName("MD5");//散列算法:这里使用MD5算法;
       hashedCredentialsMatcher.setHashIterations(1);//散列的次数,比如散列两次,相当于 md5(md5(""));
       return hashedCredentialsMatcher;
   }

//权限缓存到内存
   @Bean(name = "shiroRealm")
   @DependsOn("lifecycleBeanPostProcessor")
   public MyShiroRealm myShiroRealm() {
       MyShiroRealm myShiroRealm = new MyShiroRealm();
       myShiroRealm.setCacheManager(new MemoryConstrainedCacheManager());
       myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher());
       return myShiroRealm;
   }

@Bean(name = "securityManager")
   public SecurityManager securityManager() {
       DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
       securityManager.setRealm(myShiroRealm());
       // 自定义session管理 使用redis
       securityManager.setSessionManager(sessionManager());
       // 自定义缓存实现 使用redis
       securityManager.setCacheManager(cacheManager());
       return securityManager;
   }

/**
    * 配置shiro redisManager
    * @return
    */
   public RedisManager redisManager() {
       RedisManager redisManager = new RedisManager();
       redisManager.setHost(host);
       redisManager.setPort(port);
       redisManager.setTimeout(timeout);
//        redisManager.setPassword(password);
       redisManager.setDatabase(database);
       return redisManager;
   }

//自定义sessionManager
   @Bean
   public SessionManager sessionManager() {
       MySessionManager mySessionManager = new MySessionManager();
       mySessionManager.setSessionDAO(redisSessionDAO());
       //默认1个小时session过期
       mySessionManager.setGlobalSessionTimeout(CacheConstants.SHIRO_SESSION_MS);
       return mySessionManager;
   }

/**
    * RedisSessionDAO shiro sessionDao层的实现 通过redis
    */
   @Bean
   public RedisSessionDAO redisSessionDAO() {
       RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
       redisSessionDAO.setRedisManager(redisManager());
       return redisSessionDAO;
   }

/**
    * cacheManager 缓存 redis实现
    * @return
    */
   @Bean
   public RedisCacheManager cacheManager() {
       RedisCacheManager redisCacheManager = new RedisCacheManager();
       redisCacheManager.setRedisManager(redisManager());
       redisCacheManager.setExpire(CacheConstants.USER_DATA_TTL);
       return redisCacheManager;
   }    
}

MyShiroRealm.java


package com.jx.cert.web.framework.config.shiro;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import com.jx.cert.web.framework.config.shiro.exception.SysUsreNotLoginAPPException;
import com.jx.cert.web.framework.config.shiro.exception.SystemNotExistException;
import com.jx.common.utils.SysCode;
import com.jx.core.api.model.vo.cert.SysPermission;
import com.jx.core.api.model.vo.cert.SysRole;
import com.jx.core.api.model.vo.cert.SysSystem;
import com.jx.core.api.model.vo.cert.SysUser;
import com.jx.core.api.service.business.cert.SysPermissionService;
import com.jx.core.api.service.business.cert.SysRoleService;
import com.jx.core.api.service.business.cert.SysSystemService;
import com.jx.core.api.service.business.cert.SysUserService;

public class MyShiroRealm extends AuthorizingRealm {

private Logger logger = LoggerFactory.getLogger(MyShiroRealm.class);

@Autowired
   private SysUserService sysUserService;
   @Autowired
   private SysRoleService sysRoleService;
   @Autowired
   private SysPermissionService sysPermissionService;
   @Autowired
   private SysSystemService systemService;

@Override
   protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
       logger.info("####################开始配置权限####################");
       SysUser user = (SysUser) principals.getPrimaryPrincipal();
       if (user != null) {
           //权限信息对象info,用来存放查出的用户的所有的角色(role)及权限(permission)
           SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
           List<String> roleStrlist = new ArrayList<String>();//用户的角色集合
           List<String> perminsStrlist = new ArrayList<String>();//用户的菜单权限集合
           for (SysRole role : user.getRoleList()) {
               roleStrlist.add(role.getRoleName());
           }
           for (SysPermission permission : user.getPermissList()) {
               perminsStrlist.add(permission.getUrl());
           }
           //用户的角色集合
           authorizationInfo.addRoles(roleStrlist);
           //用户的菜单按钮权限集合
           authorizationInfo.addStringPermissions(perminsStrlist);
           return authorizationInfo;
       }
       return null;
   }

/*主要是用来进行身份认证的,也就是说验证用户输入的账号和密码是否正确。*/
   @Override
   protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
           throws AuthenticationException {
       logger.info("####################身份认证####################");
       String userStr = (String) token.getPrincipal();

SysUser user = sysUserService.getUserByUserName(userName);

//认证系统用户
       List<SysRole> roleList = sysRoleService.findRoleByUserId(user.getUserId(),systemId);
       user.setRoleList(roleList);//获取用户角色
       List<SysPermission> list=sysPermissionService.getUserPermission(user.getUserId(),systemId);
       SysPermission permis=new SysPermission();
       list.add(permis);
       user.setPermissList(list);//获取用户权限

return new SimpleAuthenticationInfo(user, DigestUtils.md5Hex(user.getPassword()),getName());
   }
}

ShiroTagsFreeMarkerCfg.java


package com.jx.cert.web.framework.config.shiro;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;

import com.jagregory.shiro.freemarker.ShiroTags;

import freemarker.template.TemplateModelException;

/**  
* @ClassName: ShiroTagsFreeMarkerCfg  
* @Description: TODO(ftl shiro 标签)  
* @author gangyu
* @date 2018年12月5日 下午5:16:27  
*    
*/
@Component
public class ShiroTagsFreeMarkerCfg {

@Autowired
   private FreeMarkerConfigurer freeMarkerConfigurer;

@PostConstruct
   public void setSharedVariable() throws TemplateModelException {
       freeMarkerConfigurer.getConfiguration().setSharedVariable("shiro", new ShiroTags());
   }
}

ShiroPermissionsFilter.java


/**    
* @Title: ShiroPermissionsFilter.java  
* @Package com.jx.cert.web.config.shiro  
* @Description: TODO(用一句话描述该文件做什么)  
* @author gangyu
* @date 2018年12月5日 上午11:47:00  
* @version V1.0    
*/
package com.jx.cert.web.framework.config.shiro.filter;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

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

import org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.jx.cert.web.framework.config.shiro.ShiroUtil;
import com.jx.common.utils.Result;
import com.jx.common.utils.enums.CodeEnum;
import com.jx.core.api.model.vo.cert.SysPermission;
import com.jx.core.api.model.vo.cert.SysUser;

/**  
* @ClassName: ShiroPermissionsFilter  
* @Description: TODO(权限验证)  
* @author gangyu
* @date 2018年12月5日 上午11:47:00  
*/
public class ShiroPermissionsFilter extends PermissionsAuthorizationFilter {

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

/**
    * 权限检测验证
    */
   @Override
   protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws IOException {
       logger.info("----------权限校验-------------");
       HttpServletRequest request = (HttpServletRequest) servletRequest;
       HttpServletResponse response = (HttpServletResponse) servletResponse;
       String reqUrl=request.getRequestURI();
       List<SysPermission> permsList=ShiroUtil.getUser().getPermissList();
       String contextPath=request.getContextPath();
       reqUrl=reqUrl.substring(contextPath.length()+1, reqUrl.length());
       String header = request.getHeader("X-Requested-With");
       boolean isAjax = "XMLHttpRequest".equals(header);
       SysUser user=ShiroUtil.getUser();
   if(!new Gson().toJson(permsList).contains(reqUrl)){
           if (isAjax) {
               logger.info("----------AJAX请求拒绝-------------");
               response.setCharacterEncoding("UTF-8");
               response.setContentType("application/json");
               response.getWriter().write(new Gson().toJson(new Result(CodeEnum.NOT_PERMISSION)));
           } else {
               logger.info("----------普通请求拒绝-------------");
               response.sendRedirect(request.getContextPath()+"/403");
           }
           return false;
       }else {
        return true;
       }
   }
}

ShiroUtil.java


package com.jx.cert.web.framework.config.shiro;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;

import com.jx.core.api.model.vo.cert.SysUser;

public class ShiroUtil {
   /**
    * 获取当前 Subject
    *
    * @return
    */
   public static Subject getSubject() {
       return SecurityUtils.getSubject();
   }

/**
    * 获取shiro指定的sessionKey
    *
    * @param key
    * @param <T>
    * @return
    */
   public static <T> T getSessionAttr(String key) {
       Session session = getSession();
       return session != null ? (T) session.getAttribute(key) : null;
   }

/**
    * 设置shiro指定的sessionKey
    *
    * @param key
    * @param value
    */
   public static void setSessionAttr(String key, Object value) {
       Session session = getSession();
       session.setAttribute(key, value);
   }

/**
    * 获取当前用户对象
    *
    * @return
    */
   public static SysUser getUser() {
    if(getSubject().isAuthenticated()){
           return (SysUser) getSubject().getPrincipals().getPrimaryPrincipal();
    }
    return null;
   }
   /**
    * 获取当前用户对象UserID
    *
    * @return
    */
   public static String getUserId() {
       return getUser().getUserId();
   }

/**
    * 移除shiro指定的sessionKey
    *
    * @param key
    */
   public static void removeSessionAttr(String key) {
       Session session = getSession();
       if (session != null)
           session.removeAttribute(key);
   }

/**
    * 验证当前用户是否属于该角色
    *
    * @param roleName 角色名称
    * @return 属于该角色:true,否则false
    */
   public static boolean hasRole(String roleName) {
       return getSubject() != null && roleName != null
               && roleName.length() > 0 && getSubject().hasRole(roleName);
   }

/**
    * shiro 中获取session
    *
    * @return session
    */
   public static Session getSession() {
       return getSubject().getSession();
   }

/**
    * 验证当前用户是否属于以下所有角色
    * 多权限“,”分割
    *
    * @param roleNames 权限名称
    * @return 属于:true,否则false
    */
   public static boolean hasAllRoles(String roleNames) {
       boolean hasAllRole = true;
       Subject subject = getSubject();
       if (subject != null && roleNames != null && roleNames.length() > 0) {
           for (String role : roleNames.split(",")) {
               if (!subject.hasRole(role.trim())) {
                   hasAllRole = false;
                   break;
               }
           }
       }
       return hasAllRole;
   }

/**
    * 验证当前用户是否属于以下任意一个角色
    * 多权限“,”分割
    * @param roleNames
    * @return
    */
   public static boolean hasAnyRoles(String roleNames) {
       boolean hasAnyRole = false;
       Subject subject = getSubject();
       if (subject != null && roleNames != null && roleNames.length() > 0) {
           for (String role : roleNames.split(",")) {
               if (subject.hasRole(role.trim())) {
                   hasAnyRole = true;
                   break;
               }
           }
       }
       return hasAnyRole;
   }
}

来源:https://blog.csdn.net/BeiShangBuZaiLai/article/details/86541690

标签:SpringBoot,配置,shiro
0
投稿

猜你喜欢

  • java基于JDBC连接Oracle 11g Release2实例分析

    2022-06-06 02:36:36
  • 一篇文章教你使用枚举来实现java单例模式

    2023-08-23 22:24:36
  • 解决springboot配置logback-spring.xml不起作用问题

    2022-09-10 11:21:24
  • C#中如何使用Chart图表问题

    2023-04-02 16:35:06
  • android实现倒计时功能(开始、暂停、0秒结束)

    2021-09-29 11:02:29
  • SpringBoot内置tomcat启动原理详解

    2021-11-02 19:32:33
  • 基于Flutter实现多边形和多角星组件

    2023-06-19 06:02:50
  • Android仿Iphone屏幕底部弹出半透明PopupWindow效果

    2023-08-17 06:14:43
  • java_object的简单使用详解

    2023-08-22 11:35:57
  • 在SpringBoot中整合使用Netty框架的详细教程

    2023-03-26 23:59:53
  • Spring Cloud Ribbon的踩坑记录与原理详析

    2023-02-06 04:06:55
  • C#实现文件上传及文件下载功能实例代码

    2022-12-13 23:57:23
  • C#及WPF获取本机所有字体和颜色的方法

    2022-12-23 01:23:13
  • Java获取环境变量(System.getenv)的方法

    2021-10-06 03:23:47
  • c#调用存储过程实现登录界面详解

    2023-01-02 22:03:07
  • MyBatis的SQL执行结果和客户端执行结果不一致问题排查

    2022-12-30 20:37:22
  • Tomcat 实现WebSocket详细介绍

    2023-08-12 21:22:11
  • Android中Service的全面总结

    2022-12-30 22:09:09
  • Android实现ListView分页加载数据

    2023-11-09 10:05:45
  • C#验证码识别基础方法实例分析

    2021-11-19 00:24:13
  • asp之家 软件编程 m.aspxhome.com