【知识库系统】JWT实现前后端分离验证

本文会先从理论和实践两部分讲述如何去理解和实现通过JWT进行身份认证。

一、理论

1. SpringSecurity 默认的认证是需要通过 UsernamePasswordAuthenticationFilter 进行认证的,该过滤器认证前,会到 SecurityContextHolder 中寻找是否有符合的 Authentication 认证信息,如果有已认证的信息,则 UsernamePasswordAuthenticationFilter 可以直接拿到认证信息,进行后面的授权操作。

2. SecurityFilterChain 中允许我们使用 addFilterBefore 在某个过滤器前面添加自定义过滤器,所以我们可以自定义一个 JwtFilter 对用户信息进行授权认证,认证成功后将授权信息写入 SecurityContextHolder,这样在后面的 UsernamePasswordAuthenticationFilter 过滤器就能直接拿到授权信息了。

根据以上两点,最后能够实现先进行 JWT 验证,通过则授权;不通过则进行 UsernamePassword 验证。

二、实践

1. 首先引入 JWT

<!-- jwt -->
<dependency>
	<groupId>com.auth0</groupId>
	<artifactId>java-jwt</artifactId>
	<version>4.0.0</version>
</dependency>

2. 编写 JwtUtil 工具,用于加密和解密 token 信息

public class JwtUtil {
    private static final String secret = "test123456";
    public static String createToken(String userName, String authentications){
        long expire = 7 * 24 * 3600 * 1000;
        return JWT.create().withAudience(userName)
                .withIssuedAt(new Date())
                .withExpiresAt(new Date(System.currentTimeMillis()+ expire))
                .withClaim("authentications", authentications)
                .sign(Algorithm.HMAC256(userName+secret));
    }

    public static boolean verifyToken(String token, String userName){
        DecodedJWT jwt = null;
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(userName+secret)).build();
            jwt = verifier.verify(token);
            return true;
        } catch (Exception e) {
            System.out.println(e);
        }
        return false;
    }
}

3. 实现 AuthticationSuccessHandler ,用于用户在第一次通过 UsernamePassword 验证的时候,返回一个 token

public class SuccessHandler implements AuthenticationSuccessHandler {
    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        UsernamePasswordAuthenticationToken user = (UsernamePasswordAuthenticationToken) authentication;
        String token = JwtUtil.createToken(user.getName(), user.getAuthorities().toString());
        response.setContentType("text/json;charset=utf-8");
        PrintWriter writer = response.getWriter();
        writer.write(token);
        writer.flush();
        writer.close();
    }
}

4. 创建一个 JwtFilter ,主要是实现验证 token 授权信息并将授权信息写入 SecurityContextHolder 中

@Component
public class JwtFilter extends OncePerRequestFilter {
    @Autowired
    private UserDetailsServiceImpl userDetailsService;
    @Autowired
    UserMapper userMapper;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = "";
        String username = "";
        for (Cookie cookie : request.getCookies()) {
            if (cookie.getName().equals("username")) {
                username = cookie.getValue();
            }
            if (cookie.getName().equals("token")) {
                token = cookie.getValue();
            }
        }
        if (JwtUtil.verifyToken(token, username)) {
            DecodedJWT jwt = JwtUtil.decodedJWT(token, username);
            String authentications = jwt.getClaims().get("authentications").toString();
            String authentication = authentications.substring(2, authentications.length()-2);
            User user = new User(username, "", AuthorityUtils.createAuthorityList(authentication));
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        } else {
            System.out.println(username + "JwtToken验证失败");
        }
        filterChain.doFilter(request, response);
    }
}

5. 将 SuccessHandler 和 JwtFilter 配置到 SecurityFilterChain 中才能生效。

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Autowired
    private JwtFilter jwtFilter;

    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .authorizeHttpRequests(authorize -> authorize
                        .requestMatchers("/admin").hasRole("ADMIN")
                        .requestMatchers("/user/**").hasRole("ADMIN")
                        .anyRequest().authenticated()
                )
                .formLogin(login -> login
                        .loginPage("/login")
                        .successHandler(new SuccessHandler())
                        .permitAll()
                )
                .addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class)
                .csrf(AbstractHttpConfigurer::disable);
        return http.build();
    }
}

6. 最后测试一下,发送一个登录请求,返回 token 信息,

然后将 token 放在cookie 里面再请求一个需要权限才能访问的页面,正常返回

否则会重定向到登录页面

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Issue 2046:Missing array size check in NewFixedArray

文章目录 环境搭建漏洞分析漏洞触发 漏洞利用总结参考 环境搭建 sudo apt install pythongit reset --hard 64cadfcf4a56c0b3b9d3b5cc00905483850d6559 export DEPOT_TOOLS_UPDATE0 gclient sync -D// debug version tools/dev/v8gen.py x64.debug ninja -C out.gn/x64.debug/…

java数据结构与算法刷题-----LeetCode135. 分发糖果

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 1. 左右遍历2. 进阶&#xff1a;常数空间遍历&#xff0c;升序降…

Visual Studio - 添加快捷键图标

Visual Studio - 添加快捷键图标 1. Text Editor Toolbar Options -> Add or Remove Buttons -> Customize2. Toolbars3. Commands -> Debug4. Add Command...References 1. Text Editor Toolbar Options -> Add or Remove Buttons -> Customize 2. Toolbars B…

并发编程之synchronized的详细解析

4.2 synchronized 解决方案 应用之互斥 为了避免临界区的竞态条件发生&#xff0c;有多种手段可以达到目的。 阻塞式的解决方案&#xff1a;synchronized&#xff0c;Lock 非阻塞式的解决方案&#xff1a;原子变量 本次课使用阻塞式的解决方案&#xff1a;synchronized&am…

长安链智能合约标准协议第二草案——BNS与DID协议邀请社区用户评审

长安链智能合约标准协议 在智能合约编写过程中&#xff0c;不同的产品及开发人员对业务理解和编程习惯不同&#xff0c;即使同一业务所编写的合约在具体实现上也可能有很大差异&#xff0c;在运维或业务对接中面临较大的学习和理解成本&#xff0c;现有公链合约协议规范又不能完…

C++:类和对象(上篇)

目录&#xff1a; 一&#xff1a;面向对象和过程的介绍 二&#xff1a;类的引入 三&#xff1a;类的定义 四&#xff1a;类的访问限定符以及封装 五&#xff1a;类的作用域 六&#xff1a;类的实例化 七&#xff1a;类对象大小的计算 八&#xff1a;类成员函数的this指…

C语言经典算法-7

文章目录 其他经典例题跳转链接36.排序法 - 改良的选择排序37.快速排序法&#xff08;一&#xff09;38.快速排序法&#xff08;二&#xff09;39.快速排序法&#xff08;三&#xff09;40.合并排序法 其他经典例题跳转链接 C语言经典算法-1 1.汉若塔 2. 费式数列 3. 巴斯卡三…

JJJ:改善ubuntu网速慢的方法

Ubuntu 系统默认的软件下载源由于服务器的原因&#xff0c; 在国内的下载速度往往比较慢&#xff0c;这时我 们可以将 Ubuntu 系统的软件下载源更改为国内软件源&#xff0c;譬如阿里源、中科大源、清华源等等&#xff0c; 下载速度相比 Ubuntu 官方软件源会快很多&#xff01;…

Linux实践 - 命令行解释器 简易版

~~~~ 前言解决的问题为什么shell要以子进程的方式执行我们的命令&#xff1f;为什么直接使用程序名ls&#xff0c;而不是路径/usr/bin/ls&#xff1f; 头文件包含命令行提示符接受用户命令行输入解析用户的输入内建命令&&特殊处理ls 时目录等文件不带高亮颜色cd时目录不…

electron-builder 打包问题,下载慢解决方案

目录 问题说明设置下载源 &#xff1f;解决方案思路下载Electron下载winCodeSign下载nsis下载nsis-resources 总结 问题说明 项目使用了Electron&#xff0c;在第一次打包时会遇见下载慢&#xff0c;导致打包进度几乎停滞不前&#xff0c;甚至可能直接报错 其实这是因为Electr…

【SpringBoot3+Mybatis】框架快速搭建

文章目录 GitHub 项目一、依赖二、 配置文件三、启动类四、SpringBoot3兼容Druid报错五、工具类5.1 结果封装类5.2 解决枚举类5.3 MD5加密工具类 GitHub 项目 springboot-part——springboot-integrate-07 Mybatis-plus版完整CRUD项目文档记录&#xff1a; 【SpringBoot3Myba…

【Python循环6/6】循环的综合运用

目录 回顾 for循环遍历列表 for循环进行累加/累乘的计算 复杂的条件判断 嵌套 嵌套循环 练习 遍历整数列表 总结 回顾 在之前的博文中&#xff0c;我们学习了for计数循环&#xff1b;while条件循环&#xff1b;以及跳出循环的两种方法break&#xff0c;continu…

CMU 10-414/714: Deep Learning Systems --hw3

实现功能 在ndarray.py文件中完成一些python array操作 我们实现的NDArray底层存储就是一个一维向量&#xff0c;只不过会有一些额外的属性&#xff08;如shape、strides&#xff09;来表明这个flat array在维度上的分布。底层运算&#xff08;如加法、矩阵乘法&#xff09;都…

幻兽帕鲁游戏搭建(docker)

系列文章目录 第一章&#xff1a; 幻兽帕陆游戏搭建 文章目录 系列文章目录前言一、镜像安装1.创建游戏目录2.拉取镜像3.下载配置文件4.启动游戏 二、自定义配置总结 前言 这段时间一直在写论文还有找工作&#xff0c;也没学啥新技术&#xff0c;所以博客也很长时间没写了&am…

【滑动窗口、矩阵】算法例题

目录 三、滑动窗口 30. 长度最小的子数组 ② 31. 无重复字符的最长子串 ② 32. 串联所有单词的子串 ③ 33. 最小覆盖子串 ③ 四、矩阵 34. 有效的数独 ② 35. 螺旋矩阵 ② 36. 旋转图像 ② 37. 矩阵置零 ② 38. 生命游戏 ② 三、滑动窗口 30. 长度最小的子数组 ② 给…

高效备考2025年AMC8竞赛:吃透2000-2024年600道真题(免费送题)

我们继续来随机看五道AMC8的真题和解析&#xff0c;根据实践经验&#xff0c;对于想了解或者加AMC8美国数学竞赛的考生来说&#xff0c;吃透AMC8历年真题是备考更加科学、有效的方法之一。 即使不参加AMC8竞赛&#xff0c;吃透了历年真题600道和背后的知识体系&#xff0c;那么…

Qt笔记 mainwindow

mainwindow是用来做应用界面的&#xff0c;有菜单栏&#xff0c;工具栏&#xff0c;浮动窗口,中心部件以及状态栏这几个部分组成。 举个例子&#xff1a; 1.菜单栏: #include <QMenuBar>QMenuBar *menubar new QMenuBar(this); setMenuBar(menubar);//设置到当前窗口 …

31-Java前端控制器模式(Front Controller Pattern)

Java前端控制器模式 实现范例 前端控制器模式&#xff08;Front Controller Pattern&#xff09;是用来提供一个集中的请求处理机制&#xff0c;所有的请求都将由一个单一的处理程序处理该处理程序可以做认证/授权/记录日志&#xff0c;或者跟踪请求&#xff0c;然后把请求传给…

AI系统性学习05—向量数据库

文章目录 1、Chroma向量数据库1.1 安装Chroma1.2 初始化Chroma客户端1.3 创建一个合集1.4 添加数据1.5 查询数据1.6 持久化数据1.7 集合操作1.7.1 创建集合1.7.2 获取集合1.7.3 删除集合1.7.4 其他操作1.8 向集合添加数据1.9 查询集合数据1.10 更新集合数据1.11 删除集合数据1.…

[CISCN2019 华北赛区 Day1 Web5]CyberPunk --不会编程的崽

继续sql,哈哈。我按照我的思路来讲。 四个功能&#xff0c;提交&#xff0c;查找&#xff0c;修改&#xff0c;删除。多半是sql注入&#xff0c;而且又有修改&#xff0c;查找功能。多半还是二次注入。昨天那个修改密码的&#xff0c;也是二次注入。这里需要先找到注入点 姓名 …