Spring Boot 安全

news2025/3/13 4:10:07

目录

1.概述

2.token

2.1.理论

2.2.使用

3.JWT

3.1.理论

3.2.使用

4.oauth

5.Spring Security

5.1.概述

5.2.基本认证授权

5.3.加密


1.概述

在后端来说,安全主要就是控制用户访问,让对应权限的用户能访问到对应的资源,主要是两点:

  • 认证
  • 授权

认证,确定是谁。     

授权,核实权限。

每个安全框架其实都是为了实现这两点。

目前常用的实现方式有如下几种:

  • token
  • JWT
  • oauth
  • spring security

前三种是理念,最后一种是开箱即食的框架。

2.token

2.1.理论

token ,也叫“令牌”,是验证用户身份的凭证。token的组成具有随意性,能标识用户身份即可。

token的工作流程:

 客户端向服务器发送请求,服务器收到后生成token返回给客户端,此后客户端的任何鉴权都基于该token进行。

2.2.使用

以下是一个简单的在Spring Boot中用token检验用户是否合法的一个代码示例。当然实际工作中token里面可以放很多内容,比如可以放权限,后端解析后基于权限来进行鉴权,也可以给token里面加上时限等相关信息,用来控制token的有效期等。

token工具类:

 controller:

3.JWT

3.1.理论

JWT,Json web token,即一种基于json的通用token标准,token本质上具有任意性,JWT规范了token的格式。

JWT 规定token由三部分组成:

  • header

    头部,承载两块信息:

    • 声明类型,即声明这是jwt

    • 声明加密算法,默认使用 HMAC SHA256加密算法

  • payload

    载荷,存放有效信息(数据信息)的地方。

  • signature

    签证,可以用于验证整个token的完整性以及是否被篡改,由三部分组成:

    • header(base64之后的)

    • payload(base64之后的)

    • secret私钥

3.2.使用

JWT本质上就是个有标准报文格式的token,其实只要愿意的话我们可以自己手写一个,这个没什么难度,定义一个类罢了。JWT市面上也有很多开源实现,直接拿来用就行了,以下是使用Spring Boot+JJWT来实现鉴权的一个简单demo,不用深究,就是感受一下别人的实现。

工具类:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.function.Function;

@Component
public class JwtUtil {

    // 读取配置文件中的JWT秘钥
    @Value("${jwt.secret}")
    private String secret;

    // JWT的过期时间,单位毫秒
    private final long JWT_EXPIRATION = 1000 * 60 * 60 * 24;

    /**
     * 生成JWT
     * @param username 用户名
     * @return JWT
     */
    public String generateToken(String username) {
        // 设置JWT的过期时间为当前时间 + JWT_EXPIRATION
        Date expiration = new Date(System.currentTimeMillis() + JWT_EXPIRATION);

        // 使用JWT的Builder类构造JWT
        return Jwts.builder()
                .setSubject(username) // 设置JWT的主题为用户名
                .setIssuedAt(new Date()) // 设置JWT的发行时间为当前时间
                .setExpiration(expiration) // 设置JWT的过期时间
                .signWith(SignatureAlgorithm.HS256, secret) // 使用HS256算法和秘钥对JWT进行签名
                .compact(); // 构造JWT并返回
    }

    /**
     * 验证JWT是否有效
     * @param token JWT
     * @return JWT是否有效
     */
    public boolean validateToken(String token) {
        try {
            // 使用JWT的parser类解析JWT
            Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();

            // 如果JWT的过期时间早于当前时间,则JWT无效
            Date expiration = claims.getExpiration();
            if (expiration.before(new Date())) {
                return false;
            }

            // JWT有效
            return true;
        } catch (Exception e) {
            // 解析JWT失败,则JWT无效
            return false;
        }
    }

    /**
     * 从JWT中获取主题
     * @param token JWT
     * @return 主题
     */
    public String extractUsername(String token) {
        return extractClaim(token, Claims::getSubject);
    }

    /**
     * 从JWT中获取指定claim的值
     * @param token JWT
     * @param claimsResolver 指定claim的解析器
     * @param <T> 指定claim的类型
     * @return 指定claim的值
     */
    private <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = extractAllClaims(token);
        return claimsResolver.apply(claims);
    }

    /**
     * 解析JWT中的所有claim
     * @param token JWT
     * @return 包含所有claim的Claims对象
     */
    private Claims extractAllClaims(String token) {
        return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
    }
}

控制器:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/api/auth")
public class AuthController {

    @Autowired
    private JwtUtil jwtUtil;

    @PostMapping("/login")
    public ResponseEntity<?> login(@RequestBody LoginRequest loginRequest) {
        // TODO: 实现用户登录逻辑
        String username = "exampleUser";
        String token = jwtUtil.generateToken(username);
        return ResponseEntity.ok(new JwtResponse(token));
    }

    @GetMapping("/validateToken")
    public ResponseEntity<?> validateToken(@RequestParam("token") String token) {
        if (jwtUtil.validateToken(token)) {
            return ResponseEntity.ok().build();
        } else {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
        }
    }

    private static class LoginRequest {
        private String username;
        private String password;

        // getters and setters
    }

    private static class JwtResponse {
        private String token;

        public JwtResponse(String token) {
            this.token = token;
        }

        // getter
    }
}

4.oauth

OAUTH,Open Authorization,开放授权协议,为用户资源的授权提供了一个安全的、开放而又简易的标准。目的是让第三方对用户的数据只有有限访问权,而无法触及到用户的核心信息。

例如,在第三方网站上使用微信或者QQ作为账号进行登录,就是使用的oauth协议,只返回给第三方注入用户名、头像等信息,而不会返回给第三方秘密等核心数据。

注意:oauth这里暂时不做展开,也不提供代码实现示例,因为展开的话篇幅会比较长,这里只是简单提一下这个概念,下一篇博文,博主会专门写oauth。

以下是一个用QQ在慕课网上做oauth的流程示例,大家感受一下:

5.Spring Security

5.1.概述

Spring Security是一个基于Spring框架的安全框架,它提供了一系列的安全服务和管理应用程序安全的能力。Spring Security的主要目标是保护应用程序,防止未经授权的访问,同时支持常见的认证和授权方案。

注意:由于本文只是介绍一下一些可以和Spring Boot结合起来使用的安全方案,Spring Security我们只限定于讲解基础使用,下下篇文章,作者会专门用一个大篇幅来详细写Spring Security。

5.2.基本认证授权

依赖:

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

配置:

配置一个基于内存的用户存储库,其中包含两个用户("user"和"admin"),并使用密码编码器"{noop}"指定它们的密码。该配置还指定了"/admin/**"端点需要ADMIN角色才能访问,并且所有其他端点需要进行身份验证。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

   // 配置内存中的用户存储库
   @Autowired
   public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
      auth.inMemoryAuthentication()
         .withUser("user").password("{noop}password").roles("USER")
         .and()
         .withUser("admin").password("{noop}password").roles("USER", "ADMIN");
         // 创建两个用户: "user"和"admin",使用密码编码器"{noop}"指定密码
   }

   // 配置HTTP请求的安全性
   @Override
   protected void configure(HttpSecurity http) throws Exception {
      http.authorizeRequests()
         .antMatchers("/admin/**").hasRole("ADMIN") // /admin/**端点需要ADMIN角色
         .anyRequest().authenticated() // 其他端点需要进行身份验证
         .and()
         .formLogin() // 启用基于表单的登录
         .and()
         .httpBasic(); // 启用HTTP基本认证
   }
}

用户的角色除了可以放在内存中,还可以放在其它存储介质上,如果有需要的话可以存在数据库:

控制器:

@RestController
@RequestMapping("/admin")
public class AdminController {

   @GetMapping("/")
   public String adminHome() {
      return "Welcome to the admin page!";
   }
}

5.3.加密

Spring Security提供了多种加密方式,包括以下几种:

  1. BCryptPasswordEncoder:这是最常用的加密算法之一,它使用哈希和随机盐来加密密码。

  2. Pbkdf2PasswordEncoder:这也是一种密码加密算法,它使用基于密码的密钥导出函数(PBKDF2)来加密密码。

  3. SCryptPasswordEncoder:这是一种基于内存的密码哈希算法,它使用大量的内存来防止散列碰撞攻击。

  4. NoOpPasswordEncoder:这是一种不安全的加密算法,它仅仅是将明文密码作为加密后的密码。不建议在生产环境中使用。

使用Spring Security进行加密通常需要以下几个步骤:

  1. 在Spring Security配置中定义PasswordEncoder bean。

  2. 使用PasswordEncoder bean对用户密码进行加密,然后将其保存到数据库中。

  3. 在身份验证过程中,Spring Security会将用户输入的密码与加密后的密码进行比较,以确定用户是否有权访问该资源。

以下是一个使用BCryptPasswordEncoder加密密码的示例:

spring security对支持的不同加密算法提供了不同的Encoder。

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

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

   // ...其他配置
}

使用encoder进行加密:

@Autowired
private PasswordEncoder passwordEncoder;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
   auth.inMemoryAuthentication()
      .withUser("user").password(passwordEncoder.encode("password")).roles("USER")
      .and()
      .withUser("admin").password(passwordEncoder.encode("password")).roles("USER", "ADMIN");
}

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

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

相关文章

AOP通知中获取数据

AOP通知中获取数据 之前我们写AOP仅仅是在原始方法前后追加一些操作&#xff0c;接下来我们要说说AOP中数据相关的内容&#xff0c;我们将从获取参数、获取返回值和获取异常三个方面来研究切入点的相关信息。 获取切入点方法的参数&#xff1a;所有的通知类型都可以获取参数 …

Vulhub开源漏洞靶场用Java远程访问

事件起因&#xff0c;被迫参加某竞赛&#xff0c;中途发现&#xff0c;全员摸鱼&#xff0c;遂一起摸鱼Vulhub是一个面向大众的开源漏洞靶场&#xff0c;无需docker知识&#xff0c;简单执行一条命令即可编译、运行一个完整的漏洞靶场镜像。 Installation 在Ubuntu 20.04下安…

JVM 垃圾回收详解之内存分配和回收原则+死亡对象判断方法

前言 当需要排查各种内存溢出问题、当垃圾收集成为系统达到更高并发的瓶颈时&#xff0c;我们就需要对这些“自动化”的技术实施必要的监控和调节。 堆空间的基本结构 Java 的自动内存管理主要是针对对象内存的回收和对象内存的分配。同时&#xff0c;Java 自动内存管理最核…

【STM32】基础知识 第七课 存储器映射 寄存器映射

【STM32】基础知识 第七课 存储器映射 & 寄存器映射 STM32 寻址范围存储器映射存储器功能划分 (F1 为例)Block 0Block 1Block 2寄存器映射 寄存器映射 (F1 为例)寄存器映射举例寄存器地址计算GPIO 外设基地址及偏移量寄存器地址及偏移量寄存器地址计算过程 使用结构体映射寄…

《2-数组》

数组 1.简介&#xff1a; 数组&#xff08;Array&#xff09;是一种固定长度的存储相同数据类型在连续内存空间中的数据结构 引出&#xff1a;[索引 &#xff08;Index&#xff09;]----元素在数组中的位置 2.初始化 写法&#xff1a;一般用到无初始值、给定初始值 在不给定…

中国制造业连续13年全球第一,MES管理系统,打造竞争新优势

根据工业和信息化部最近发布的数据&#xff0c;在2022年&#xff0c;中国的制造业增加值在全球的占比接近30&#xff05;&#xff0c;制造业规模已连续13年位居世界第一。根据国家统计局的最新数字&#xff0c;一到二月份&#xff0c;我国的生产值与去年同期相比上升了2.1&…

实现声明式锁,支持分布式锁自定义锁、SpEL和结合事务

目录 2.实现 2.1 定义注解2.2 定义锁接口2.3 锁的实现 2.3.1 什么是SPI2.3.2 通过SPI实现锁的多个实现类2.3.3 通过SPI自定义实现锁3.定义切面 3.1 切面实现3.2 SpEL表达式获取动态key3.3 锁与事务的结合4.测试 4.1 ReentrantLock测试4.2 RedissonClient测试4.3 自定义锁测试5…

移动硬盘如何分区?教您快速解决!

案例&#xff1a;怎么对移动硬盘进行分区&#xff1f; 【我平常找一个文件需要耗费很长时间&#xff0c;十分麻烦。我现在想通过对移动硬盘进行分区的方式&#xff0c;整理好我的文件&#xff0c;方便使用时查找。有没有人知道移动硬盘怎么分区&#xff1f;教教我&#xff01;…

深入浅出JS定时器:从setTimeout到setInterval

前言 当谈到 JavaScript 编程语言最基本的概念时&#xff0c;定时器就是一个必须掌握的知识点。在编写网站时&#xff0c;你经常会遇到需要在一定时间间隔内执行一些代码的情况。这时候&#xff0c;JavaScript 定时器就可以派上用场了。 什么是定时器&#xff1f; JS 定时器是…

[Gitops--2]Argocd和Gitlab-runner安装配置

ArgoCd Argo是一组k8s原生工具集,用于运行和管理k8s上的作业和应用程序.Argo提供了一种在k8s上创建工作和应用的三种计算模式:服务模式,工作流模式和基于事件模式.所有的Argo工具都实现为了创建控制器和自定义资源. 为什么选ArgoCD 应用程序的定义,配置和环境都应该是声明性…

ChatGPT和GPT-4帮你写人物传记

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于机器学习算法研究与应用。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。拥有多项发明专利。对机器学习和深度学习拥有自己独到的见解。曾经辅导过若干个非计算机专业的学生进入到算法…

研读Rust圣经解析——Rust learn-11(测试,迭代器,闭包)

研读Rust圣经解析——Rust learn-11&#xff08;测试&#xff0c;迭代器&#xff0c;闭包&#xff09; 测试编写测试模块声明test模块编写测试方法执行测试测试结果检查 闭包定义一个闭包完整写法闭包可以捕获环境闭包类比函数闭包类型推断闭包获取所有权将被捕获的值移出闭包和…

Jenkins配置邮件通知

1、下载Email Extension插件 2、配置发件人邮箱地址 系统管理 > 系统配置 3、配置邮件通知 系统管理 > 系统配置 > 邮件通知 往下滑找到 通过发送测试邮件测试配置 测试 如果以上配置没有问题,会发送一封测试邮件到服务器中,如果有问题请优先检查一下端口号和是…

网络协议-HTTP协议详情讲解

目录 HTTP协议内容和方法 HTTP请求常见请求头 HTTP常见返回头 HTTP协议基本方法 常见HTTP状态码 面试解惑&#xff1a;301 vs 308 面试解惑&#xff1a;302 / 303 / 307 常见HTTP头 User-Agent Content-Type Origin Accept Referer Connection HTTP协议内容和方法…

Nginx中location规则 与 URL重写(rewrite)详解

1.Nginx中location与rewrite 1.1 location与rewrite常用的正则表达式 符号作用^匹配输入字符串的起始位置$ 匹配输入字符串的结束位置*匹配前面的字符零次或多次。如“ol*”能匹配“o”及“ol”、“oll” 匹配前面的字符一次或多次。如“ol”能匹配“ol”及“oll”、“olll”…

微信为什么使用 SQLite 保存聊天记录

SQLite “只是”一个库&#xff0c;它不是传统意义上的服务器。因此&#xff0c;在某些场合下&#xff0c;它确实不合适。但是&#xff0c;在相当多的其他场合&#xff0c;它却是最合适的选择。SQLite 号称是部署和使用最广泛的数据库引擎。我认为这很有可能&#xff0c;因为 S…

《PyTorch 深度学习实践》第10讲 卷积神经网络(基础篇)

文章目录1 卷积层1.1 torch.nn.Conv2d相关参数1.2 填充&#xff1a;padding1.3 步长&#xff1a;stride2 最大池化层3 手写数字识别该专栏内容为对该视频的学习记录&#xff1a;【《PyTorch深度学习实践》完结合集】 专栏的全部代码、数据集和课件全放在个人GitHub了&#xff…

SpringCloud之OpenFeign介绍案例+相关面试题

概述 OpenFeign是一个声明式的WEB服务客户端&#xff0c;它使WEB服务客户端变得更加容易。具有可插拔的注解支持&#xff0c;SpringCloud中添加了SpringMVC注解的支持。SpringCloud中集成了Ribbon和Eureka&#xff0c;以及SpringCloud LoadBalance&#xff0c;以便在使用Feign时…

C++数据结构:树

树 树是一种数据结构&#xff0c;它是n(n>0)个节点的有限集。n0时称为空树。n>0时&#xff0c;有限集的元素构成一个具有层次感的数据结构。 根 有且仅有一个结点的非空树&#xff0c;那个结点就是根。 A就是上面树的根节点 子树 在一棵非空树中&#xff0c;除根外&a…

由浅入深,一文彻底搞懂Mybatis+面试题分享

mybatis常见面试题链接&#xff1a;2023年-Mybatis常见面试题_是Smoky呢的博客-CSDN博客 MVC架构模式和三层架构 在说Mybatis之前&#xff0c;需要知道MVC架构模式和三层架构的这种思想 MVC架构模式 M&#xff1a;Model&#xff0c;数据层。都是和数据相关&#xff0c;比如实体…