SpringBoot添加密码安全配置以及Jwt配置

news2024/9/20 20:37:48

Maven仓库(依赖查找)

1、SpringBoot安全访问配置

首先添加依赖 spring-boot-starter-security

然后之后每次启动项目之后,访问任何的请求都会要求输入密码才能请求。(如下)

在没有配置的情况下,默认用户名为 user ,密码在控制台中查找(如下)。

  • 修改SpringBoot安全访问配置,首先要创建一个UserDetailsServiceImpl类来继承UserDetailsService来接入数据库信息,然后再实现一个utils的工具类UserDetailsImpl来实现UserDetails。最后的逻辑就是在那个安全验证中输入你的账号和密码,如果在数据库中找到了username就将这个条字段作为通关令牌存起来,当退出的时候再删除
  • 注:这里如果没有加密的话要使用的话在密码那个字段的属性中加一个{noop}

添加安全访问的配置文件如下。

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    public UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", username);
        User user = userMapper.selectOne(queryWrapper);
        if(user == null)
            return (UserDetails) new RuntimeException("用户不存在!");
        return new UserDetailsImpl(user);
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDetailsImpl implements UserDetails {
    private User user;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public String getPassword() {
        return user.getPasswd();
    }

    @Override
    public String getUsername() {
        return user.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

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

}

以上配置添加之后即可正常使用数据库中的密码进行验证。前提是userMapper可以正常使用,进行查找用户。

如果数据库中的密码没有加密,可以通过测试类将密码进行加密,然后用加密之后的字符串与数据库中的数据进行替换即可。(如下)

@SpringBootTest
class TestJwtApplicationTests {

    @Test
    void contextLoads() {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String encode = bCryptPasswordEncoder.encode("123456");
        System.out.println(encode);
    }
}

2、 配置JWT验证

2.1、配置类的编写添加

@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    private UserMapper userMapper;

    @Override
    protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull FilterChain filterChain) throws ServletException, IOException {
        String token = request.getHeader("Authorization");

        if (!StringUtils.hasText(token) || !token.startsWith("Bearer ")) {
            filterChain.doFilter(request, response);
            return;
        }

        token = token.substring(7);

        String userid;
        try {
            Claims claims = JwtUtil.parseJWT(token);
            userid = claims.getSubject();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        User user = userMapper.selectById(Integer.parseInt(userid));

        if (user == null) {
            throw new RuntimeException("用户名未登录");
        }

        UserDetailsImpl loginUser = new UserDetailsImpl(user);
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(loginUser, null, null);

        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        filterChain.doFilter(request, response);
    }
}

 下面类里面的JWT_KEY的字符串是必须自己随机生成然后长度是有限制的如果后期报错记得修改长度。这个东西很重要,是你密码的加密规则。

@Component
public class JwtUtil {
    public static final long JWT_TTL = 60 * 60 * 1000L * 24 * 14;  // 有效期14天
    public static final String JWT_KEY = "SDFGjhdsfalshdfHFdsjkdsfds121232131afasdfac";

    public static String getUUID() {
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    public static String createJWT(String subject) {
        JwtBuilder builder = getJwtBuilder(subject, null, getUUID());
        return builder.compact();
    }

    private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        SecretKey secretKey = generalKey();
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        if (ttlMillis == null) {
            ttlMillis = JwtUtil.JWT_TTL;
        }

        long expMillis = nowMillis + ttlMillis;
        Date expDate = new Date(expMillis);
        return Jwts.builder()
                .setId(uuid)
                .setSubject(subject)
                .setIssuer("sg")
                .setIssuedAt(now)
                .signWith(signatureAlgorithm, secretKey)
                .setExpiration(expDate);
    }

    public static SecretKey generalKey() {
        byte[] encodeKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
        return new SecretKeySpec(encodeKey, 0, encodeKey.length, "HmacSHA256");
    }

    public static Claims parseJWT(String jwt) throws Exception {
        SecretKey secretKey = generalKey();
        return Jwts.parserBuilder()
                .setSigningKey(secretKey)
                .build()
                .parseClaimsJws(jwt)
                .getBody();
    }
}

然后修改之前的SecurityConfig配置类,里面的configure方法里面的.antMatchers里面追加的url是不需要验证就能进行使用的请求,比如登录注册等url请求的放开,需要的话可以一直追加。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;

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

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/user/login", "/user/account/register/").permitAll()
                .antMatchers(HttpMethod.OPTIONS).permitAll()
                .anyRequest().authenticated();

        http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
    }
}

2.2、jwt的登录验证并且获取验证码

编写LoginServiceImpl,可以进行登录的验证,以及获取token并且返回给用户。之后访问其他请求的时候都需要验证该token验证身份,登录失败会报异常。

@Service
public class LoginServiceImpl{
    @Autowired
    // 认证管理器
    private AuthenticationManager authenticationManager;

    public Map<String, String> getToken(String username, String password) {
        // 将输入进来的username和password封装成一个密码加密过后的对象
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(username, password);
        // 该方法接收一个认证令牌对象,也就是认证请求作为参数,如果其中的信息匹配到目标账号,
        // 则该方法返回同一个认证令牌对象,不过其中被认证过程填充了更多的账号信息,比如授权和用户详情等。
        Authentication authenticate = authenticationManager.authenticate(authenticationToken);// 如果登录失败会自动报异常
        UserDetailsImpl loginUser = (UserDetailsImpl)authenticate.getPrincipal();
        User user = loginUser.getUser();
        String jwt = JwtUtil.createJWT(user.getId().toString());
        Map<String, String> map = new HashMap<>();
        map.put("error_message", "success");
        map.put("token", jwt);

        return map;
    }
}

前端正常调用接口即可,将获取的token进行存储即可,用于,存储位置尽量安全。

2.3、未放开url请求的处理

通过以下操作可以直接从token中获取用户的信息,然后通过用户的信息进行验证并返回用户需要的信息。

@Service
public class InfoServiceImpl {
    @Autowired
    private UserMapper userMapper;

    public Map getInfoById() {
        Map data = new HashMap<>();
        UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) SecurityContextHolder.getContext().getAuthentication();
        UserDetailsImpl loginUser = (UserDetailsImpl)token.getPrincipal();
        User user = loginUser.getUser();
        user.setPasswd("");
        data.put("user", user);
        data.put("error_message", "success");
        return data;
    }
}

前端的请求中需要加上token,注意Bearer后面要加一个空格。

 然后即可正常使用。

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

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

相关文章

LLM agentic模式之工具使用: Gorilla

Gorilla Gorilla出自2023年5月的论文《Gorilla: Large Language Model Connected with Massive APIs》&#xff0c;针对LLM无法准确地生成API调用时的参数&#xff0c;构建API使用数据集后基于Llama微调了一个模型。 数据集构建 API数据集APIBench的构建过程如下&#xff1…

《Programming from the Ground Up》阅读笔记:p75-p87

《Programming from the Ground Up》学习第4天&#xff0c;p75-p87总结&#xff0c;总计13页。 一、技术总结 1.persistent data p75, Data which is stored in files is called persistent data, because it persists in files that remain on disk even when the program …

C语言程序设计15

程序设计15 问题15_1代码15_1结果15_1 问题15_2代码15_2结果15_2 问题15_3代码15_3结果15_3 问题15_1 在 m a i n main main 函数中将多次调用 f u n fun fun 函数&#xff0c;每调用一次&#xff0c;输出链表尾部结点中的数据&#xff0c;并释放该结点&#xff0c;使链表缩短…

【SQL 新手教程 3/20】关系模型 -- 外键

&#x1f497; 关系数据库建立在关系模型上⭐ 关系模型本质上就是若干个存储数据的二维表 记录 (Record)&#xff1a; 表的每一行称为记录&#xff08;Record&#xff09;&#xff0c;记录是一个逻辑意义上的数据 字段 (Column)&#xff1a;表的每一列称为字段&#xff08;Colu…

Buildroot 构建 Linux 系统

Buildroot 是一个工具&#xff0c;以简化和自动化为嵌入式系统构建完整 Linux 系统的过程。使用交叉编译技术&#xff0c;Buildroot 能够生成交叉编译工具链、根文件系统、Linux 内核映像和针对目标设备的引导加载程序。可以独立地使用这些选项的任何组合&#xff0c;例如&…

Vitis AI 使用 VAI_Q_PYTORCH 工具

目录 1. 简介 2. 资料汇总 3. 示例解释 3.1 快速上手示例 4. 总结 1. 简介 vai_q_pytorch 是 Vitis AI Quantizer for Pytorch 的缩写&#xff0c;主要作用是优化神经网络模型。它是 Vitis AI 平台的一部分&#xff0c;专注于神经网络的深度压缩。 vai_q_pytorch 的作用…

大数据管理中心设计规划方案(可编辑的43页PPT)

引言&#xff1a;随着企业业务的快速发展&#xff0c;数据量急剧增长&#xff0c;传统数据管理方式已无法满足高效处理和分析大数据的需求。建立一个集数据存储、处理、分析、可视化于一体的大数据管理中心&#xff0c;提升数据处理能力&#xff0c;加速业务决策过程&#xff0…

Spring Boot:图书管理系统(一)

1.编写用户登录接口 代码&#xff1a; package com.example.demo;import jakarta.servlet.http.HttpSession; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotatio…

HarmonyOS和OpenHarmony区别联系

前言 相信我们在刚开始接触鸿蒙开发的时候经常看到HarmonyOS和OpenHarmony频繁的出现在文章和文档之中&#xff0c;那么这两个名词分别是什么意思&#xff0c;他们之间又有什么联系呢&#xff1f;本文将通过现有的文章和网站内容并与Google的AOSP和Android做对比&#xff0c;带…

Vue.js 2 项目实战(五):水果购物车

前言 Vue.js 是一个用于构建用户界面的渐进式 JavaScript 框架。它的设计目标是通过采用易于上手的结构和强大的功能&#xff0c;使前端开发变得更加简便和高效。以下是 Vue.js 的一些关键特性和优点&#xff1a; 核心特性 声明式渲染 Vue.js 使用声明式语法来描述用户界面&a…

AI周报(7.21-7.27)

AI应用-一款能提供情绪价值的智能鸟类喂食器&#xff08;Bird Buddy&#xff09; 图像识别技术&#xff1a;Bird Buddy装备了图像识别技术&#xff0c;能够识别超过1000种鸟类&#xff0c;涵盖了常见的鸟类品种。这种技术能够在鸟类经过时&#xff0c;通过内置麦克风捕捉的声音…

PID 控制实验 - 整定实验

Arduino PID Arduino-PID-LibraryArduino-PID-AutoTune-Library PID控制实验 – 制作测试台 PID Control Experiment – Making the Testing Rig PID (Proportional, Integral, Derivative) control is a classic control algorithm that I have used for a few projects,…

Debug-018-elementUI-el-tree中通过CSS隐藏任意一项的选择框checkbox

前情提要&#xff1a; 我们项目中使用的是elementUI&#xff0c;业务中经常需要使用到el-tree组件去实现一些有层级关系的功能。现在有一个需求描述一下&#xff1a;首先是这个el-tree是个有checkbox的树&#xff0c;每一子节点都可以被选择&#xff0c;用于去实现一些系统的权…

Shell编程之正则表达式与文本三剑客

目录 一、正则表达式 1.引言--什么是正则表达式 1.1正则表达式的功能 2.基础正则表达式&#xff08;BRE&#xff09; 2.1特殊字符 2.2定位符 2.3非打印字符 3.扩展正则表达式(ERE) 4.元字符操作的案列 二、命令小工具 1.cut&#xff1a;列截取工具 2.sort排序 …

vue3获取、设置元素高度

前言 在web端常见的需求场景中&#xff0c;会经常遇到table表格需要根据页面可视区域使高度自适应的情况。 傻喵(作者本人)昨天在尝试使用vue3实现这个需求时&#xff0c;看了几篇网上写的回答&#xff0c;都不太全面&#xff0c;所以干脆自己写个总结吧.(第一次写&#xff0c…

深入探讨 I/O 多路复用:提升系统 I/O 效率的关键技术

摘要 I/O&#xff08;输入/输出&#xff09;操作是计算机系统中不可或缺的一部分&#xff0c;而 I/O 多路复用技术则是提高系统 I/O 效率的重要手段。本文将浅谈 I/O 的基本概念&#xff0c;重点探讨 I/O 多路复用技术的原理、优势以及在现代系统中的应用。 引言 在现代计算…

php收银系统源码-收银员操作权限

收银系统是很多门店&#xff0c;尤其是连锁门店营业的必备工具&#xff0c;收银员每天需要通过收银系统记录商品的售卖数量&#xff0c;以及收款&#xff0c;会员开卡&#xff0c;核销订单等工作。但很多门店都不希望给收银员太高的权限&#xff0c;自然就离不开收银员的权限管…

flask开启调试模式,热部署

这里写自定义目录标题 功能快捷键 什么是热部署&#xff1f;简单说就是你程序改了&#xff0c;现在要重新启动服务器&#xff0c;嫌麻烦&#xff1f;不用重启&#xff0c;服务器会自己悄悄的把更新后的程序给重新加载一遍&#xff0c;这就是热部署&#xff08;抄的&#xff09;…

NameSilo域名注册和解析2024版教程(附优惠码)

上次给大家介绍了国外知名的域名注册商Dynadot&#xff0c;今天再给大家分享另一家国外知名的域名注册商NameSilo&#xff0c;同样性价比很高。使用本站提供的优惠码&#xff1a;ieearn.com&#xff0c;你还可以在首次注册购买域名时享受1美元的优惠&#xff1a; NameSilo简介…

10 VUE Element

文章目录 VUE1、概述2、快速入门3、Vue 指令4、生命周期5、案例 Elemant1、快速入门2、Element 布局3、常用组件-案例 VUE 1、概述 Vue 是一套前端框架&#xff0c;免除原生JavaScript中的DOM操作&#xff0c;简化书写基于MVVM(Model-View-ViewModel)思想&#xff0c;实现数据…