SpringSecurity+jwt使用
参考文章链接
自定义SpringSecurity用户
package com.daben.springsecurityjwt.vo;import com.daben.springsecurityjwt.entity.SysUser;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import java.util.Collection;
/*** SpringSecurity用户** @Author JinDongSheng* @Date 2023-11-16 09:21*/
public class SpringSecurityUser extends User {/*** 系统用户*/private SysUser sysUser;/*** 构造函数*/public SpringSecurityUser(SysUser sysUser, Collection<? extends GrantedAuthority> authorities) {super(sysUser.getUsername(), sysUser.getPassword(), authorities);this.sysUser = sysUser;}public SysUser getSysUser() {return sysUser;}public void setSysUser(SysUser sysUser) {this.sysUser = sysUser;}
}
自定义认证失败处理类
package com.daben.springsecurityjwt.handle;import com.alibaba.fastjson2.JSON;
import com.daben.springsecurityjwt.vo.Result;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/*** 未登录处理类** @Author JinDongSheng* @Date 2023-11-15 17:37*/
@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {@Overridepublic void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {response.setStatus(200);response.setContentType("application/json");response.setCharacterEncoding("utf-8");response.getWriter().print(JSON.toJSONString(Result.error("认证失败,无法访问系统资源!")));}
}
自定义Security用户服务实现类
package com.daben.springsecurityjwt.service;import com.daben.springsecurityjwt.entity.SysUser;
import com.daben.springsecurityjwt.vo.SpringSecurityUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.Collections;
/*** Security用户服务实现类** @Author JinDongSheng* @Date 2023-11-16 09:14*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate SysUserServiceImpl sysUserServiceImpl;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {// 根据用户名称查询用户SysUser sysUser = sysUserServiceImpl.selectSysUserByName(username);// 查询用户权限List<GrantedAuthority> authorities = Collections.emptyList();// 返回Security指定的用户对象return new SpringSecurityUser(sysUser, authorities);}
}
自定义JWT工具类
package com.daben.springsecurityjwt.utils;import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import com.daben.springsecurityjwt.entity.SysUser;
import io.jsonwebtoken.*;
import org.apache.commons.lang3.StringUtils;
import java.util.Date;
/*** JWT工具类** @Author JinDongSheng* @Date 2023-11-16 15:49*/
public class JwtUtil {/*** Token有效期为30分钟*/public static final int EXPIRE_TIME = 30;/*** 秘钥*/private final static String SECRET_KEY = "ABCDE";/*** 生成token*/public static String createToken(SysUser user) {return Jwts.builder()// 将user放进JWT.setSubject(JSONUtil.toJsonStr(user))// 设置过期时间.setExpiration(DateUtil.offsetMinute(new Date(), EXPIRE_TIME))// 设置加密算法和秘钥.signWith(SignatureAlgorithm.HS512, SECRET_KEY).compact();}public static Claims parseToken(String token) {// 如果是空字符串直接返回nullif (StringUtils.isEmpty(token)) {return null;}// 这个Claims对象包含了许多属性,比如签发时间、过期时间以及存放的数据等Claims claims = null;// 解析失败了会抛出异常,所以我们要捕捉一下。token过期、token非法都会导致解析失败try {claims = Jwts.parser().setSigningKey(SECRET_KEY) // 设置秘钥.parseClaimsJws(token).getBody();} catch (JwtException e) {// 这里应该用日志输出,为了演示方便就直接打印了System.err.println("解析失败!");}return claims;}
}
自定义token认证过滤器
package com.daben.springsecurityjwt.filter;import cn.hutool.json.JSONUtil;
import com.daben.springsecurityjwt.entity.SysUser;
import com.daben.springsecurityjwt.utils.JwtUtil;
import io.jsonwebtoken.Claims;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;
/*** 登录过滤器** @Author JinDongSheng* @Date 2023-11-16 14:48*/
@Component
public class LoginFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {// 解析tokenClaims claims = JwtUtil.parseToken(request.getHeader("Authorization"));if (claims != null) {// 获取用户SysUser sysUser = JSONUtil.toBean(claims.getSubject(), SysUser.class);// 手动组装一个认证对象Authentication authentication = new UsernamePasswordAuthenticationToken(sysUser, null, Collections.emptyList());// 将认证对象放到上下文中SecurityContextHolder.getContext().setAuthentication(authentication);}filterChain.doFilter(request, response);}
}
自定义SpringSecurity配置类
package com.daben.springsecurityjwt.config;import com.daben.springsecurityjwt.filter.LoginFilter;
import com.daben.springsecurityjwt.handle.AuthenticationEntryPointImpl;
import com.daben.springsecurityjwt.service.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
/*** spring security 配置** @Author JinDongSheng* @Date 2023-11-15 17:16*/
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {/*** 登录认证过滤器*/@Autowiredprivate LoginFilter loginFilter;/*** Security用户服务实现类*/@Autowiredprivate UserDetailsServiceImpl userDetailsService;/*** 未登录处理类*/@Autowiredprivate AuthenticationEntryPointImpl authenticationEntryPoint;@Overrideprotected void configure(HttpSecurity http) throws Exception {// 关闭csrfhttp.csrf().disable();// 关闭frameOptionshttp.headers().frameOptions().disable();// 指定未登录处理类http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);// 前置登录认证过滤器http.addFilterBefore(loginFilter, UsernamePasswordAuthenticationFilter.class);// 禁用sessionhttp.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);// 配置认证和授权接口http.authorizeRequests()// 指出放行接口.antMatchers("/sys/port/*").permitAll()// 拦截剩余接口.anyRequest().authenticated();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {// 指定UserDetailService和加密器auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());}@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}@Beanpublic PasswordEncoder passwordEncoder() {// 使用bcrypt加密return new BCryptPasswordEncoder();}
}
登录入口
package com.daben.springsecurityjwt.controller;import com.daben.springsecurityjwt.entity.SysUser;
import com.daben.springsecurityjwt.utils.JwtUtil;
import com.daben.springsecurityjwt.vo.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/*** 登录控制器** @Author JinDongSheng* @Date 2023-11-15 17:25*/
@RestController
@RequestMapping("/sys/port")
public class SysPortController {@Autowiredprivate AuthenticationManager authenticationManager;@PostMapping("/login")public Result login(@RequestBody SysUser sysUser) {// 认证Authentication authenticate = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(sysUser.getUsername(), sysUser.getPassword()));if (authenticate.isAuthenticated()) {// 生成tokenString token = JwtUtil.createToken(sysUser);// 返回tokenreturn Result.success(token);}return Result.error("用户名或密码错误");}
}
整体调用流程
- 服务启动,根据【自定义SpringSecurity配置类】配置信息(指定放行和认证接口、token认证过滤器、认证失败处理器、密码加密器、用户查询服务等。)
- 用户发起登录请求。
- token认证过滤器过滤,因为不携带token,直接放行调用登录接口,在登录接口中手动调用AuthenticationManager进行用户信息认证。
- AuthenticationManager进行用户信息认证时会调用【自定义Security用户服务实现类】查询数据库用户,然后将数据库用户封装成Security指定用户返回。
- 认证失败调用【自定义认证失败处理类】,认证成功则返回token
- 用户发起非登录请求,token过滤器过滤,token校验成功将认证对象放入上下文中。调用请求接口。token校验失败,调用【自定义认证失败处理类】。
pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.vitalframework</groupId><artifactId>vital-framework-dependencies</artifactId><version>1.1.0</version></parent><groupId>com.citic</groupId><artifactId>vital-portal-core</artifactId><version>1.0.0</version><name>vital-portal-core</name><description>系统管理(门面工程)模块</description><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.rep4orting.outputEncoding>UTF-8</project.rep4orting.outputEncoding><java.version>1.8</java.version><maven.compiler.source>${java.version}</maven.compiler.source><maven.compiler.target>${java.version}</maven.compiler.target></properties><dependencies><!--CITIC 一些公共包--><dependency><groupId>com.vitalframework.web</groupId><artifactId>vital-framework-web-common</artifactId><version>1.0.0</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId></dependency><dependency><groupId>commons-net</groupId><artifactId>commons-net</artifactId></dependency><dependency><groupId>com.jcraft</groupId><artifactId>jsch</artifactId></dependency><!--代码生成器--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-generator</artifactId></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml-schemas</artifactId></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-scratchpad</artifactId></dependency><dependency><groupId>org.codehaus.castor</groupId><artifactId>castor-xml</artifactId></dependency></dependencies><build>
<!-- <finalName>${project.artifactId}</finalName>--><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><fork>true</fork><skip>true</skip></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-source-plugin</artifactId><version>${maven-source-plugin.version}</version></plugin></plugins></build>
</project>
相关文章:

SpringSecurity+jwt使用
参考文章链接 自定义SpringSecurity用户 package com.daben.springsecurityjwt.vo;import com.daben.springsecurityjwt.entity.SysUser; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.User; import j…...

html-网站菜单-点击显示导航栏
一、效果图 1.点击显示菜单栏,点击x号关闭; 2.点击一级菜单,展开显示二级,并且加号变为减号; 3.点击其他一级导航,自动收起展开的导航。 二、代码实现 <!DOCTYPE html> <html><head>&…...

【C++函数的进化】函数指针,模板,仿函数,lambda表达式
/*** poject * author jUicE_g2R(qq:3406291309)* file C函数的进化* * language C* EDA Base on VS2022* editor Obsidian(黑曜石笔记软件)* * copyright 2023* COPYRIGHT 原创学习笔记:转载需获得博…...

云服务器windows service2022 部署git服务器
1 安装 下载地址gitblit 解压到你的一个目录,我这里给的是C:\gitblit 根据官网提示要下载jre or jdk7.0,这里建议使用下载jre (jdk 有时候运行出问题,或者2个都安装),自行安装java,这里不做环境配置的说明 进入c:\gitblit\data 目录里面找到,defaults.properties 文件,编辑主…...

Linux_Docker修改Docker Root Dir
今天遇到需求,要修改一下docker容器和镜像的存储位置,默认位置为/var/lib/docker目录下,要修改到/new/dockerFile目录下。 停止docker服务 sudo service docker stop 备份docker容器镜像 移动/var/lib/docker目录下的文件到/dockerFile目录…...

解决requests 2.28.x版本SSL错误:证书验证失败
1、问题背景 在使用requests 2.28.1版本时,我进行HTTP post传输报告负载时,由于SSL验证设置为True,请求失败,错误如下:(Caused by SSLError(SSLCertVerificationError(1, ‘[SSL: CERTIFICATE_VERIFY_FAILED] certifi…...

【开源】基于Vue.js的开放实验室管理系统的设计和实现
项目编号: S 013 ,文末获取源码。 \color{red}{项目编号:S013,文末获取源码。} 项目编号:S013,文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、研究内容2.1 实验室类型模块2.2 实验室模块2.3 实…...

使用composer安装ffmpeg的步骤
以下是使用composer安装ffmpeg的步骤: 1.在laravel根目录下执行以下命令安装ffmpeg: composer require php-ffmpeg/php-ffmpeg 2.如果不指定版本号,则默认使用0.14版本。 3.执行以上命令后,composer会自动下载并安装ffmpeg。 …...

RT-DETR优化策略:轻量级Backbone改进 | 高效模型 (Efficient MOdel, EMO),现代倒残差移动模块设计|ICCV2023
🚀🚀🚀本文改进:面向移动端的轻量化网络模型——EMO,它能够以相对较低的参数和 FLOPs 超越了基于 CNN/Transformer 的 SOTA 模型,支持四个版本EMO_1M, EMO_2M, EMO_5M, EMO_6M,参数量如下,相对于自带的rtdetr-l、rtdetr-x有很大提升 layersparametersgradientsEMO_1…...

一些nginx命令
1.停止nginx nginx -s quit systemctl stop nginx.service 立即停止 nginx-s stop 杀死nginx进程 killall nginx 2.启动命令 nginx systemctl start nginx.service 3.查看nginx进程 ps aux | grep nginx 4.重启nginx服务 systemctl restart nginx.service 5.重载…...

WPF自定义控件介绍
在WPF中,自定义控件通常是指从头开始创建一个新控件或从现有控件继承并扩展其功能。自定义控件与用户控件(User Control)不同,用户控件是通过组合其他控件来构建的,而自定义控件通常涉及对控件的更底层的渲染和行为进行…...

JUNIT使用和注意、以及断言的介绍使用、SpringBoot Test测试类的使用、maven配置使用junit详细介绍
参考文章: https://www.cnblogs.com/zhukaile/p/14514238.html,https://blog.csdn.net/qq_36448800/article/details/126438339 一、什么是单元测试 在平时的开发当中,一个项目往往包含了大量的方法,可能有成千上万个。如何去保…...

强化学习在文生图中的应用:Training Diffusion Models with Reinforcement Learning
论文链接:Training Diffusion Models with Reinforcement Learning项目地址:Training Diffusion Models with Reinforcement Learning官方代码:https://github.com/kvablack/ddpo-pytorch/tree/maintrl实现:https://huggingface.co/docs/trl/ddpo_trainer🤗关注公众号 fu…...

【C语言】数组下标为啥从0开始?下标越界访问一定报错吗?
本篇文章目录 0. 相关文章1. 下标从0开始问题2. 数组下标越界不报错问题 0. 相关文章 指针与指针变量数组名不是首元素地址的的2个例外拨开指针和数组名之间的迷雾 1. 下标从0开始问题 原因是:数组下标访问本质是“指针解引用操作”,而指针又是地址&am…...

机器学习-搜索技术:从技术发展到应用实战的全面指南
在本文中,我们全面探讨了人工智能中搜索技术的发展,从基础算法如DFS和BFS,到高级搜索技术如CSP和优化问题的解决方案,进而探索了机器学习与搜索的融合,最后展望了未来的趋势和挑战,提供了对AI搜索技术深刻的…...

Axelar、J.P.Morgan Onyx、Apollo 完成概念验证,向跨区块链自动化投资领域探索
J.P.Morgan Onyx、Apollo、Axelar、Oasis Pro 以及 Provenance Block Chain 展开合作,共同进行互操作性概念验证(Proof-of-Concept,PoC)。 新加坡 — Axelar Inc.、Oasis Pro 、Provenance Blockchain 与 J.P.Morgan Onyx 以及 Apollo 通过新…...

wpf devexpress添加TreeListControl到项目
此教程示范如何添加TreeListControl到项目和绑定控件自引用数据源: 添加数据模型 绑定tree,并添加如下字段到数据源对象: Key字段包含唯一值索引节点 Parent字段包含父索引节点 添加数据模型(Employee和Staff类)到…...

WPF创建自定义控件编译通过但是找不到资源
报错: 原因: 路径写错了: 不是这样: Source"pack://application:,,,/Controls/Styles/xTabControl.xaml" 而是这样: Source"pack://application:,,,/项目名;component/Controls/Styles/xTabControl.xaml …...

PHP 中传值与传引用的区别,什么时候传值什么时候传引用?
传值:当使用传值的方式时,函数或方法会创建原始变量的一个副本,并将该副本传递给函数或方法。在函数或方法内部,对副本的任何修改都不会影响到原始变量。当函数或方法执行完毕后,副本被销毁,不再使用。 传引…...

es安装方式
es安装方式 1.下载镜像的方式 分词器 kibana和es和容器互通的方式 docker network create es-net开始拉去镜像的方式 docker pull kibana:7.12.1运行镜像的方式 docker run -d \--name es \-e "ES_JAVA_OPTS-Xms512m -Xmx512m" \-e "discovery.typesingle-…...

苍穹外卖项目笔记(2)
1 Nginx 反向代理和负载均衡 1.1 概念 【Tips】可以看到前端请求地址和后端接口地址并不匹配,这里涉及到 nginx 反向代理 ,就是将前端发送的动态请求由 nginx 转发到后端服务器 使用 nginx 作反向代理的好处: 提高访问速度(在请…...

hive更改表结构的时候报错
现象 FAILED: ParseException line 1:48 cannot recognize input near ADD COLUMN compete_company_id in alter table statement 23/11/14 17:59:27 ERROR org.apache.hadoop.hive.ql.Driver: FAILED: ParseException line 1:48 cannot recognize input near ADD COLUMN compe…...

redis运维(六)redis-cli命令
一 redis-cli 注意: redis-cli核redis-server版本必须适配 --> 见 redis-cli --version提示: 不过一般安装服务端 redis-server 时内置了客户端 redis-cli说明: redis-cli 是 redis 的一种命令行的客户端工具备注: redis-se…...

JDK1.8 新特性(二)【Stream 流】
前言 上节我们学了 lambda 表达式,很快我就在 Flink 的学习中用到了,我学的是 Java 版本的 Flink,一开始会以为代码会很复杂,但事实上 Flink 中很多地方都用到了 函数接口,这也让我们在编写 Flink 程序的时候可以使用 …...

阿里云CentOS主机开启ipv6
目录 一、云主机开启和使用 ipv6 1、网络和交换机开启 ipv6 2、创建 / 编辑云主机,开启ipv6 3、安全组放行ipv6端口 二、使用 ipv6 地址进行 ssh 连接 三、ipv6 地址绑定域名 一、云主机开启和使用 ipv6 1、网络和交换机开启 ipv6 进入网络、交换机详情页面…...

【Git】第五篇:基本操作(添加文件)
.git目录结构 我们在前文中提过了.git目录,也明确说了我们不能手动去.git目录下创建修改等任何操作。 添加文件 我们现在已经了解到,git是一个版本控制器,可以对我们的文件进行管理。而我们需要使用git管理文件的时候,我们必须将…...

vue通过span-method合并列之后,合并列显示在中间位置,根据鼠标滑动跟随展示
当vue通过span-method合并列之后,出现的合并列显示在中间位置,但是如果页面没有分页,如何进行展示呢,难道要滑到最下面去看吗,下面我们来根据鼠标滑动跟随展示 没有处理的合并页面 <template> <el-table:dat…...

gRPC 四模式之 一元RPC模式
一元RPC模式 一元 RPC 模式也被称为简单 RPC 模式。在该模式中,当客户端调用服务器端的远程方法时,客户端发送请求至服务器端并获得一个响应,与响应一起发送的还有状态细节以及 trailer 元数据(这部分不是默认发送的,…...

Java GUI实现贪吃蛇游戏
贪吃蛇是一款经典的游戏,玩法相对简单但富有挑战性。以下是贪吃蛇游戏的基本玩法说明: 目标:控制一条蛇,在游戏区域内吃到尽可能多的食物,使蛇身变长,同时避免撞到自己的身体或游戏区域的边界。 控制&…...

Vue3 使用教程
目录 一、创建vue3工程1. 使用vue-cli创建2.使用 vite 创建 二、setup使用三、ref函数四、reactive函数五、计算属性与监视属性5.1 computed函数5.2 watch函数5.3 watchEffect函数 六、自定义hook函数七、toRef函数八、shallowReactive 与 shallowRef九、readonly 与 shallowRe…...