springboot集成shiro和前后端分离配置

一,springboot集成shiro

1,导入依赖

        <dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring-boot-starter</artifactId><version>1.4.0</version></dependency>

2,Realm

shiro以来这个来进行认证和授权

package com.chen.admin.Realm;import com.alibaba.fastjson.JSON;
import com.chen.admin.dto.UserDto;
import com.chen.admin.entity.Role;
import com.chen.admin.entity.User;
import com.chen.admin.service.RoleService;
import com.chen.admin.service.UserService;
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.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;import java.util.*;/*** @Author @Chenxc* @Date 24-7-2 10:13*/
@Component
public class UserPasswordRealm extends AuthorizingRealm {@Autowiredprivate RoleService roleService;@Autowiredprivate UserService userService;@Autowiredprivate PasswordEncoder encoder;// @Autowired//private StringRedisTemplate stringRedisTemplate;//授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {UserDto user = (UserDto) principalCollection.getPrimaryPrincipal();//使用redis存放用户角色和权限
//        Object o = stringRedisTemplate.opsForValue().get("user:" + user.getId());
//        if(null == o){
//            List<Role> roleList = roleService.getRoleByUserId(user.getId());
//            if(null != roleList){
//                Set<String> roles = new HashSet<>();
//                Set<String> permissions = new HashSet<>();
//                for (Role role : roleList) {
//                    roles.add(role.getName());
//                    List<String> permission = roleService.getPermissionByRoleId(role.getId());
//                    if(null != permission){
//                        permissions.addAll(permission);
//                    }
//                }
//                user.setRoleList(roles);
//                user.setPermissions(permissions);
//            }
//            stringRedisTemplate.opsForValue().set("user:"+user.getId(), JSON.toJSONString(user));
//        }else{
//            String json = (String)o;
//            user = JSON.parseObject(json,UserDto.class);
//        }
//        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//        simpleAuthorizationInfo.addRoles(user.getRoleList());
//        simpleAuthorizationInfo.addStringPermissions(user.getPermissions());//本地存放用户角色和权限List<Role> roleList = roleService.getRoleByUserId(user.getId());if(null != roleList){Set<String> roles = new HashSet<>();Set<String> permissions = new HashSet<>();for (Role role : roleList) {roles.add(role.getName());List<String> permission = roleService.getPermissionByRoleId(role.getId());if (null != permission) {permissions.addAll(permission);}}user.setRoleList(roles);user.setPermissions(permissions);}SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();simpleAuthorizationInfo.addRoles(user.getRoleList());simpleAuthorizationInfo.addStringPermissions(user.getPermissions());return simpleAuthorizationInfo;}//认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;String username = token.getUsername();char[] password1 = token.getPassword();if(null == username || null  == password1){throw new AuthenticationException("用户名或密码错误");}String password = new String(password1);User user = userService.getUserByUsername(username);if(null == user){throw new AuthenticationException("用户名或密码错误");}boolean matches = encoder.matches(password, user.getPassword());if (!matches) {throw new AuthenticationException("用户名或密码错误");}if(user.getEnable().equals("0")){throw new DisabledAccountException("用户已禁用");}UserDto dto = new UserDto();BeanUtils.copyProperties(user,dto);SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(dto, password, getName());return authenticationInfo;}
}

3,shiro配置

package com.chen.admin.config;import com.chen.admin.dao.RedisSessionDao;
import com.chen.admin.filter.ShiroFormAuthenticationFilter;
import com.chen.admin.system.Constant;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
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.servlet.SimpleCookie;
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 org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;/*** @Author @Chenxc* @Date 24-7-2 10:10*/
@Configuration
public class ShiroConfig {@Beanpublic DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();// 设置为true则会在代理对象的方法执行过程中进行权限校验defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);return defaultAdvisorAutoProxyCreator;}@Beanpublic AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();advisor.setSecurityManager(securityManager);return advisor;}//上面的两个开启注解的支持,如果没有这两个方法,doGetAuthorizationInfo不会执行,加了@RequiresPermissions注解后会包找不到url//session保存在内存@Beanpublic DefaultWebSessionManager defaultWebSessionManager(){DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();sessionManager.setGlobalSessionTimeout(Constant.expireTime * 1000);sessionManager.setDeleteInvalidSessions(true);sessionManager.setSessionValidationSchedulerEnabled(true);//修改Cookie中的SessionId的key,默认为JSESSIONID,自定义名称sessionManager.setSessionIdCookie(new SimpleCookie(Constant.SHIRO_COOKIE_ID));return sessionManager;}//session保存在redis@Beanpublic DefaultWebSessionManager defaultWebSessionManager(RedisSessionDao redisSessionDao){DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();sessionManager.setGlobalSessionTimeout(Constant.expireTime * 1000);sessionManager.setDeleteInvalidSessions(true);sessionManager.setSessionDAO(redisSessionDao);sessionManager.setSessionValidationSchedulerEnabled(true);//修改Cookie中的SessionId的key,默认为JSESSIONID,自定义名称sessionManager.setSessionIdCookie(new SimpleCookie(Constant.SHIRO_COOKIE_ID));return sessionManager;}//上面的session存放选一个即可@Beanpublic DefaultWebSecurityManager defaultWebSecurityManager(DefaultWebSessionManager defaultWebSessionManager,Realm realm){DefaultWebSecurityManager manager = new DefaultWebSecurityManager();// 取消Cookie中的RememberMe参数manager.setRememberMeManager(null);manager.setRealm(realm);manager.setSessionManager(defaultWebSessionManager);return manager;}@Beanpublic ShiroFilterFactoryBean shiroFilterChainDefinition(DefaultWebSecurityManager defaultWebSecurityManager) {ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();factoryBean.setSecurityManager(defaultWebSecurityManager);factoryBean.setLoginUrl("/login");//factoryBean.setSuccessUrl("/loginSuccess");Map<String, String> map = new LinkedHashMap<>();//map.put("/login","anon");map.put("/static/**","anon");map.put("/ws/**","authc");map.put("/**", "authc");// 配置shiro默认登录界面地址,前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据
//        shiroFilterFactoryBean.setLoginUrl("/login/unauth");LinkedHashMap<String, Filter> filtsMap = new LinkedHashMap<>();// 这里使用自定义的filterfiltsMap.put("authc", new ShiroFormAuthenticationFilter());factoryBean.setFilters(filtsMap);factoryBean.setFilterChainDefinitionMap(map);return factoryBean;}}

如果上面使用redis还需要集成 AbstractSessionDAO 来读取redis中的数据来认证和授权

RedisSessionDao:

package com.chen.admin.dao;import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.chen.admin.system.Constant;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.util.JSONPObject;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.SimpleSession;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Collection;
import java.util.concurrent.TimeUnit;/**shiro集成redis* @author @Chenxc* @date 2024/7/3 0:46**/@Component
public class RedisSessionDao extends AbstractSessionDAO {@Autowiredprivate RedisTemplate redisTemplate;@Overrideprotected Serializable doCreate(Session session) {Serializable serializable = this.generateSessionId(session);this.assignSessionId(session,serializable);redisTemplate.opsForValue().set(session.getId(),session, Constant.expireTime, TimeUnit.SECONDS);return serializable;}@Overrideprotected Session doReadSession(Serializable serializable) {if(serializable == null){return null;}SimpleSession o = (SimpleSession)redisTemplate.opsForValue().get(serializable);if(o == null){return null;}return o;}@Overridepublic void update(Session session) throws UnknownSessionException {if(session != null && session.getId() != null){session.setTimeout( Constant.expireTime * 1000);redisTemplate.opsForValue().set(session.getId(),session, Constant.expireTime,TimeUnit.SECONDS);}}@Overridepublic void delete(Session session) {if (session != null && session.getId() != null) {redisTemplate.opsForValue().getOperations().delete(session.getId());}}@Overridepublic Collection<Session> getActiveSessions() {return redisTemplate.keys("*");}
}

二,前后端分离配置

如果是前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据,可以继承FormAuthenticationFilter重写里面的两个方法即可:

org.apache.shiro.web.filter.authc.FormAuthenticationFilter#onAccessDenied
org.apache.shiro.web.filter.authc.FormAuthenticationFilter#onLoginSuccess
package com.chen.admin.filter;import com.alibaba.fastjson.JSON;
import com.chen.admin.system.Result;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;/*** @author @Chenxc* @date 2024/7/8 1:29**/
public class ShiroFormAuthenticationFilter extends FormAuthenticationFilter {private static final Logger log = LoggerFactory.getLogger(ShiroFormAuthenticationFilter.class);/** 未登录时返回json* @auther: @Chenxc		//作者* @Description //TODO 	//描述* @param: 	//参数* @return: 	//返回值* @date:  	//创建日期*/@Overrideprotected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {if (this.isLoginRequest(request, response)) {if (this.isLoginSubmission(request, response)) {if (log.isTraceEnabled()) {log.trace("Login submission detected.  Attempting to execute login.");}return this.executeLogin(request, response);} else {if (log.isTraceEnabled()) {log.trace("Login page view.");}return true;}} else {if (log.isTraceEnabled()) {log.trace("Attempting to access a path which requires authentication.  Forwarding to the Authentication url [" + this.getLoginUrl() + "]");}//this.saveRequestAndRedirectToLogin(request, response);response.setContentType("application/json; charset=utf-8");response.setCharacterEncoding("UTF-8");PrintWriter out = response.getWriter();out.println(JSON.toJSONString(Result.unauthenticated()));out.flush();out.close();return false;}}/** 登录成功后返回json* @auther: @Chenxc		//作者* @Description //TODO 	//描述* @param: 	//参数* @return: 	//返回值* @date:  	//创建日期*/@Overrideprotected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request, ServletResponse response) throws Exception {if (log.isTraceEnabled()) {log.trace("Attempting to access a path which requires authentication.  Forwarding to the Authentication url [" + this.getLoginUrl() + "]");}//this.saveRequestAndRedirectToLogin(request, response);response.setContentType("application/json; charset=utf-8");response.setCharacterEncoding("UTF-8");PrintWriter out = response.getWriter();Result result = Result.success("登录成功");HttpServletResponse httpServletResponse = (HttpServletResponse) response;String header = httpServletResponse.getHeader("Set-Cookie");if(null != header){String[] split = header.split(";");if(null != split && split.length != 0){String tokenStr = split[0].split("=")[1];result.setData(tokenStr);}}out.println(JSON.toJSONString(result));out.flush();out.close();return false;}
}

最后controller

package com.chen.admin.controller;import com.chen.admin.entity.Menu;
import com.chen.admin.service.MenuService;
import com.chen.admin.system.Result;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;/*** @author @Chenxc* @date 2024/7/15 23:46**/
@RestController
@RequestMapping("/menu")
@RequiresPermissions({"MENU"})//访问该controller需要的权限
public class MenuController {@Autowiredprivate MenuService menuService;@RequestMapping("/list")public Result<Menu> list(){return menuService.menuList();}@RequestMapping("/save")public Result<Menu> save(Menu menu){return menuService.saveMenu(menu);}@RequestMapping("/delete")public Result delete(Long id){return menuService.delete(id);}@RequestMapping("/update")public Result update(Menu menu){return menuService.updateMenu(menu);}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/62003.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言数据结构——详细讲解 双链表

从单链表到双链表&#xff1a;数据结构的演进与优化 前言一、单链表回顾二、单链表的局限性三、什么是双链表四、双链表的优势1.双向遍历2.不带头双链表的用途3.带头双链表的用途 五、双链表的操作双链表的插入操作&#xff08;一&#xff09;双链表的尾插操作&#xff08;二&a…

MYSQL 表的增删改查(上)

目录 1.新增数据 2.查询数据 一般查询 去重查询 排序查询 关于NULL 条件查询 分页查询 1.新增数据 语法&#xff1a;insert into 表名[(字段1&#xff0c;字段2...)] values (值&#xff0c;值....); 插入一条新数据行&#xff0c;前面指定的列&#xff0c;要与后面v…

Docker pull镜像拉取失败

因为一些原因&#xff0c;很多镜像仓库拉取镜像失败&#xff0c;所以需要更换不同的镜像&#xff0c;这是2024/11/25测试可用的仓库。 标题1、 更换镜像仓库的地址&#xff0c;编辑daemon.json文件 vi /etc/docker/daemon.json标题2、然后将下面的镜像源放进去或替换掉都可以…

C语言学习 12(指针学习1)

一.内存和地址 1.内存 在讲内存和地址之前&#xff0c;我们想有个⽣活中的案例&#xff1a; 假设有⼀栋宿舍楼&#xff0c;把你放在楼⾥&#xff0c;楼上有100个房间&#xff0c;但是房间没有编号&#xff0c;你的⼀个朋友来找你玩&#xff0c;如果想找到你&#xff0c;就得挨…

VITE+VUE3+TS环境搭建

前言&#xff08;与搭建项目无关&#xff09;&#xff1a; 可以安装一个node管理工具&#xff0c;比如nvm&#xff0c;这样可以顺畅的切换vue2和vue3项目&#xff0c;以免出现项目跑不起来的窘境。我使用的nvm&#xff0c;当前node 22.11.0 目录 搭建项目 添加状态管理库&…

Zookeeper选举算法与提案处理概览

共识算法(Consensus Algorithm) 共识算法即在分布式系统中节点达成共识的算法&#xff0c;提高系统在分布式环境下的容错性。 依据系统对故障组件的容错能力可分为&#xff1a; 崩溃容错协议(Crash Fault Tolerant, CFT) : 无恶意行为&#xff0c;如进程崩溃&#xff0c;只要…

ffmpeg视频滤镜:提取缩略图-framestep

滤镜描述 官网地址 > FFmpeg Filters Documentation 这个滤镜会间隔N帧抽取一帧图片&#xff0c;因此这个可以用于设置视频的缩略图。总体上这个滤镜比较简单。 滤镜使用 滤镜参数 framestep AVOptions:step <int> ..FV....... set frame st…

微服务篇-深入了解使用 RestTemplate 远程调用、Nacos 注册中心基本原理与使用、OpenFeign 的基本使用

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 认识微服务 1.1 单体架构 1.2 微服务 1.3 SpringCloud 框架 2.0 服务调用 2.1 RestTemplate 远程调用 3.0 服务注册和发现 3.1 注册中心原理 3.2 Nacos 注册中心 …

TCP/IP学习笔记

TCP\IP从实际应用的五层结构开始&#xff0c;自顶而下的去分析每一层。 TCP/IP五层架构概述 学术上面是TCP/IP四层架构&#xff0c;OSI/ISO是七层架构&#xff0c;实际中使用的是TCP/IP五层架构。 数据链路层 ICMP数据包分析 Wireshark抓包分析ICMP协议_wireshark抓ping包分析…

互联网视频推拉流EasyDSS视频直播点播平台视频转码有哪些技术特点和应用?

视频转码本质上是一个先解码再编码的过程。在转码过程中&#xff0c;原始视频码流首先被解码成原始图像数据&#xff0c;然后再根据目标编码标准、分辨率、帧率、码率等参数重新进行编码。这样&#xff0c;转换前后的码流可能遵循相同的视频编码标准&#xff0c;也可能不遵循。…

深入理解 Java 基本语法之运算符

&#xff08;一&#xff09;研究背景 在 Java 编程中&#xff0c;运算符是处理数据和变量的基本工具&#xff0c;掌握各种运算符的使用方法对于提高编程效率至关重要。 &#xff08;二&#xff09;研究目的 深入理解 Java 基础运算符的概念、分类和作用&#xff0c;通过具体…

Excel把其中一张工作表导出成一个新的文件

excel导出一张工作表 一个Excel表里有多个工作表&#xff0c;怎么才能导出一个工作表&#xff0c;让其生成新的Excel文件呢&#xff1f; 第一步&#xff1a;首先打开Excel表格&#xff0c;然后选择要导出的工作表的名字&#xff0c;比如“Sheet1”&#xff0c;把鼠标放到“She…

ArcGIS pro中的回归分析浅析(加更)关于广义线性回归工具的补充内容

在回归分析浅析中篇的文章中&#xff0c; 有人问了一个问题&#xff1a; 案例里的calls数据貌似离散&#xff0c;更符合泊松模型&#xff0c;为啥不采用泊松而采用高斯呢&#xff1f; 确实&#xff0c;在中篇中写道&#xff1a; 在这个例子中我们为了更好地解释变量&#x…

计算机网络 第4章 网络层

计算机网络 &#xff08;第八版&#xff09;谢希仁 第 4 章 网络层4.2.2 IP地址**无分类编址CIDR**IP地址的特点 4.2.3 IP地址与MAC地址4.2.4 ARP 地址解析协议4.2.5 IP数据报的格式题目2&#xff1a;IP数据报分片与重组题目&#xff1a;计算IP数据报的首部校验和(不正确未改) …

极狐GitLab 17.6 正式发布几十项与 DevSecOps 相关的功能【三】

GitLab 是一个全球知名的一体化 DevOps 平台&#xff0c;很多人都通过私有化部署 GitLab 来进行源代码托管。极狐GitLab 是 GitLab 在中国的发行版&#xff0c;专门为中国程序员服务。可以一键式部署极狐GitLab。 学习极狐GitLab 的相关资料&#xff1a; 极狐GitLab 官网极狐…

直接抄作业!Air780E模组LuatOS开发:位运算(bit)示例

在嵌入式开发中&#xff0c;位运算是一种高效且常用的操作技巧。本文将介绍如何使用Air780E模组和LuatOS进行位运算&#xff0c;并通过示例代码帮助读者快速上手。 一、位运算概述 位运算是一种在计算机系统中对二进制数位进行操作的运算。由于计算机内部数据的存储和处理都是…

学习threejs,使用设置lightMap光照贴图创建阴影效果

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.MeshLambertMaterial…

11.23作业

4、将整个 /etc 目录下的文件全部打包并用 gzip 压缩成/back/etcback.tar.gz 5、使当前用户永久生效的命令别名&#xff1a;写一个命令命为hello,实现的功能为每输入一次hello命令&#xff0c;就有hello&#xff0c;everyone写入文件/file.txt中。 6、创建mygroup组群&#xf…

网安瞭望台第5期 :7zip出现严重漏洞、识别网络钓鱼诈骗的方法分享

国内外要闻 7 - Zip存在高危漏洞&#xff0c;请立刻更新 2024 年 11 月 24 日&#xff0c;do son 报道了 7 - Zip 中存在的一个高严重性漏洞 CVE - 2024 - 11477。7 - Zip 是一款广受欢迎的文件压缩软件&#xff0c;而这个漏洞可能会让攻击者在存在漏洞的系统中执行恶意代码。…

ESC字符背后的故事(27 <> 033 | x1B ?)

ANSI不可见字符转义&#xff0c;正确的理解让记忆和书写变得丝滑惬意。 (笔记模板由python脚本于2024年11月26日 15:05:33创建&#xff0c;本篇笔记适合python 基础扎实的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.python.org/ Free&#xf…