Spring Boot 安全

简介: 1.概述在后端来说,安全主要就是控制用户访问,让对应权限的用户能访问到对应的资源,主要是两点:认证授权认证,确定是谁。 授权,核实权限。每个安全框架其实都是为了实现这两点。目前常用的实现方式有如下几种:tokenJWToauthspring security前三种是理念,最后一种是开箱即食的框架。2.token2.1.理论token ,也叫“令牌”,是验证用户身份的凭证。token的组成具有随意性,能标识用户身份即可。

1.概述

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


认证

授权

认证,确定是谁。    


授权,核实权限。


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


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


token

JWT

oauth

spring security

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


2.token

2.1.理论

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


token的工作流程:


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

99de4e6793c84f73a39a12edf61b71c9.png

2.2.使用

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


token工具类:

d1ad1820948446d4b2b1547c0ea76320.png

controller:

5eb8ae010c3e4cb3b8a1cf4deb86648d.png

3.JWT

3.1.理论

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

2d524d64bf6c4582aea3bf444aa30eb3.png

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的流程示例,大家感受一下:

63e1a296142f4910991981b0a8fa0e83.png

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基本认证
   }
}

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

控制器:

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

5.3.加密

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


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


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


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


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


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


在Spring Security配置中定义PasswordEncoder bean。


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


在身份验证过程中,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");
}

目录
相关文章
|
6天前
|
安全 Java 数据安全/隐私保护
|
6天前
|
安全 Java API
第7章 Spring Security 的 REST API 与微服务安全(2024 最新版)(上)
第7章 Spring Security 的 REST API 与微服务安全(2024 最新版)
52 0
第7章 Spring Security 的 REST API 与微服务安全(2024 最新版)(上)
|
7月前
|
监控 前端开发 安全
Spring-MVC使用JSR303及拦截器,增强网络隐私安全
Spring-MVC使用JSR303及拦截器,增强网络隐私安全
26 0
|
8月前
|
安全 Java 开发者
深入了解Spring Cloud Security:构建安全的分布式微服务
随着微服务架构的流行,安全性成为了构建分布式系统的关键问题之一。Spring Cloud Security是Spring家族中的一个强大工具,它提供了一系列功能,帮助开发者轻松地保护其微服务应用程序。本文将深入探讨Spring Cloud Security的各个方面,从基本概念到实际应用,帮助您构建安全的分布式微服务。
|
6天前
|
安全 Java Maven
 Spring Boot 项目代码混淆实战:保护代码安全,防止泄露
iOS加固保护是直接针对ios ipa二进制文件的保护技术,可以对iOS APP中的可执行文件进行深度混淆、加密。使用任何工具都无法逆向、破解还原源文件。对APP进行完整性保护,防止应用程序中的代码及资源文件被恶意篡改。Ipa Guard通过修改 ipa 文件中的 macho 文件中二进制数据(代码模块配置)进行操作,无需源码。不限定开发技术平台。支持oc,swift,cocos2d-x、unity3d、quick-cocos,html5 ,react native等等各种开发技术。Ipa Guard主要包含代码混淆全面、资源文件处理、不需要源代码更安全、调试信息清理、即时测试运行。
|
7月前
|
存储 安全 Java
《Spring安全配置》
《Spring安全配置》
46 1
|
7月前
|
安全 Java Go
Spring安全配置: 构建安全稳固的Java应用
Spring安全配置: 构建安全稳固的Java应用
45 0
|
7月前
|
安全 Java Go
使用Spring Security保障你的Web应用安全
使用Spring Security保障你的Web应用安全
59 0
|
7月前
|
安全 Java 数据库
Spring Boot 3 + JWT + Security 联手打造安全帝国:一篇文章让你掌握未来!
`Spring Security`已经成为`java`后台权限校验的第一选择.今天就通过读代码的方式带大家深入了解一下Security,本文主要是基于开源项目[spring-boot-3-jwt-security](https://github.com/ali-bouali/spring-boot-3-jwt-security)来讲解Spring Security + JWT(Json Web Token).实现用户鉴权,以及权限校验. 所有代码基于`jdk17+`构建.现在让我们开始吧!
698 1
 Spring Boot 3 + JWT + Security 联手打造安全帝国:一篇文章让你掌握未来!
|
8月前
|
存储 安全 JavaScript
Spring WebSocket 认证与授权:掌控安全通道,迈向巅峰之旅!
- http和WebSocket的安全链和安全配置是完全独立的。 - SpringAuthenticationProvider根本不参与 Websocket 身份验证。 - 将要给出的示例中,身份验证不会发生在 HTTP 协商端点上,因为 JavaScript STOMP(websocket)库不会随 HTTP 请求一起发送必要的身份验证标头。 - 一旦在 CONNECT 请求上设置,用户( simpUser) 将被存储在 websocket 会话中,并且以后的消息将不再需要进行身份验证
236 1