实现 HTTP 基本认证( Spring Boot 实践(✧ω✧))

读前扫盲

HTTP 基本认证

1. 身份验证方式

HTTP 基本认证是一种基于 用户名和密码 的客户端-服务器身份验证机制。它的工作原理如下:

  • 客户端(如浏览器)在访问受保护的资源时,需要提供用户名和密码。
  • 服务器验证客户端提供的凭证,如果验证通过,则允许访问资源;否则返回错误。
2. Authorization 头
  • 客户端在发送请求时,会将用户名和密码以 username:password 的形式拼接,然后进行 Base64 编码
  • 编码后的字符串通过 HTTP 请求头的 Authorization 字段发送给服务器。
    • 示例:Authorization: Basic dXNlcjpwYXNzd29yZA==
    • 其中 dXNlcjpwYXNzd29yZA==user:password 的 Base64 编码结果。
3. 401 Unauthorized
  • 如果客户端未提供凭证,或者提供的凭证无效,服务器会返回 401 Unauthorized 状态码。
  • 该状态码表示客户端未通过身份验证,无法访问请求的资源。
4. WWW-Authenticate: Basic
  • 当服务器返回 401 Unauthorized 时,会在响应头中包含 WWW-Authenticate: Basic 字段。
  • 该字段提示客户端需要使用 HTTP 基本认证,并提供用户名和密码。
    • 示例响应头:
      HTTP/1.1 401 Unauthorized
      WWW-Authenticate: Basic realm="My App"
      
5. Base64
  • Base64 是一种将二进制数据编码为 ASCII 字符串的编码方式。
  • 在 HTTP 基本认证中,用户名和密码以 username:password 的形式拼接,然后进行 Base64 编码。
    • 示例:
      • 原始字符串:user:password
      • Base64 编码后:dXNlcjpwYXNzd29yZA==
  • 注意:Base64 不是加密,只是一种编码方式,容易被解码。
6. 安全性
  • HTTP 基本认证的凭证(Base64 编码的用户名和密码)在传输过程中是 明文,容易被拦截和解码。
  • 为了提高安全性,必须与 HTTPS 结合使用,通过 SSL/TLS 加密传输数据,防止凭证被窃取。
7. HTTP 安全策略
  • 使用 HTTPS
    • 通过 SSL/TLS 加密通信,防止凭证在传输过程中被窃取。
  • 避免在 URL 中传递敏感信息
    • URL 中的参数可能会被记录在日志或浏览器历史中,导致信息泄露。
  • 强密码策略
    • 要求用户使用强密码,并定期更新密码。
  • 结合其他安全机制
    • 使用更安全的身份验证方式(如 OAuth2、JWT)来增强安全性。
  • 限制访问频率
    • 防止暴力破解,可以通过限制登录尝试次数来增强安全性。

总结

HTTP 基本认证是一种简单但安全性较低的身份验证方式,适用于内部系统或低安全性场景。它的核心流程如下:

  1. 客户端发送请求时,通过 Authorization 头传递 Base64 编码的用户名和密码。
  2. 服务器验证凭证,验证通过则允许访问,否则返回 401 Unauthorized
  3. 为了提高安全性,必须结合 HTTPS 使用,并遵循其他安全策略。

在实际应用中,建议在低安全性场景中使用 HTTP 基本认证,而在高安全性场景中结合 OAuth2、JWT 等更安全的机制。

正文开始:

1. HTTP 基本认证

HTTP 基本认证(Basic Authentication)是一种简单的身份验证方式,客户端在请求时通过 Authorization 头传递用户名和密码(Base64 编码)。

知识点
  1. 核心组件

    • httpBasic():启用 HTTP 基本认证。
    • UserDetailsService:提供用户信息。
    • PasswordEncoder:加密和验证密码。
  2. 流程

    • 客户端发送请求时,服务器返回 401 Unauthorized,并在响应头中包含 WWW-Authenticate: Basic
    • 客户端将用户名和密码以 username:password 的形式进行 Base64 编码,并通过 Authorization 头发送。
    • 服务器解码并验证用户名和密码。
  3. 安全性

    • HTTP 基本认证的凭证是 Base64 编码的,容易被解码,因此必须与 HTTPS 结合使用。

示例代码

以下是一个实现 HTTP 基本认证的 Spring Boot 项目示例:

1. 依赖配置

pom.xml 中添加 Spring Security 依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
2. 配置 SecurityFilterChain

SecurityConfig 类中配置 HTTP 基本认证:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authorize -> authorize
                .anyRequest().authenticated() // 所有请求都需要认证
            )
            .httpBasic(httpBasic -> httpBasic.realmName("My App")); // 启用 HTTP 基本认证
        return http.build();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user = User.builder()
            .username("user")
            .password(passwordEncoder().encode("password"))
            .roles("USER")
            .build();
        return new InMemoryUserDetailsManager(user);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
3. 控制器

创建一个简单的控制器:

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HomeController {

    @GetMapping("/home")
    public String home() {
        return "Welcome to the home page!";
    }
}
4. 运行项目

启动项目后,访问 http://localhost:8080/home,浏览器会弹出登录框,输入用户名 user 和密码 password 即可访问。


2. Remember-Me 功能

Remember-Me 功能允许用户在关闭浏览器后仍然保持登录状态。Spring Security 通过生成一个 Remember-Me Cookie 来实现这一功能。

知识点
  1. 核心组件

    • rememberMe():启用 Remember-Me 功能。
    • tokenRepository:用于管理 Remember-Me Token。
    • key():设置 Remember-Me 的密钥,用于加密 Token。
  2. 流程

    • 用户登录时,选择“记住我”。
    • 服务器生成一个 Remember-Me Token 并存储在 Cookie 中。
    • 用户再次访问时,服务器通过 Cookie 中的 Token 自动登录。
  3. 安全性

    • Remember-Me Token 默认有效期为 2 周。
    • 建议使用持久化 Token 存储(如数据库)以增强安全性。

示例代码

以下是一个实现 Remember-Me 功能的 Spring Boot 项目示例:

1. 依赖配置

pom.xml 中添加 Spring Security 和数据库依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <scope>runtime</scope>
</dependency>
2. 配置 SecurityFilterChain

SecurityConfig 类中配置 Remember-Me 功能:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final DataSource dataSource;

    public SecurityConfig(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(authorize -> authorize
                .anyRequest().authenticated() // 所有请求都需要认证
            )
            .formLogin(form -> form
                .loginPage("/login") // 自定义登录页面
                .permitAll()
            )
            .rememberMe(remember -> remember
                .tokenRepository(persistentTokenRepository()) // 使用数据库存储 Token
                .key("my-secure-key") // 设置 Remember-Me 密钥
                .tokenValiditySeconds(1209600) // Token 有效期为 2 周
            );
        return http.build();
    }

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        return tokenRepository;
    }

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails user = User.builder()
            .username("user")
            .password(passwordEncoder().encode("password"))
            .roles("USER")
            .build();
        return new InMemoryUserDetailsManager(user);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
3. 控制器

创建一个控制器来处理登录页面:

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class LoginController {

    @GetMapping("/login")
    public String login() {
        return "login"; // 返回 login.html
    }
}
4. 登录页面

src/main/resources/templates 下创建 login.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Login</title>
</head>
<body>
    <h1>Login</h1>
    <form th:action="@{/login}" method="post">
        <div>
            <label for="username">Username:</label>
            <input type="text" id="username" name="username" required>
        </div>
        <div>
            <label for="password">Password:</label>
            <input type="password" id="password" name="password" required>
        </div>
        <div>
            <input type="checkbox" id="remember-me" name="remember-me">
            <label for="remember-me">Remember Me</label>
        </div>
        <div>
            <button type="submit">Login</button>
        </div>
    </form>
</body>
</html>
5. 运行项目

启动项目后,访问 http://localhost:8080/login,输入用户名 user 和密码 password,勾选“Remember Me”即可启用 Remember-Me 功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值