好的,下面是一篇详细介绍Spring Security中身份验证的文章,涵盖身份验证的基本概念、实现机制、常见配置和实践示例。

Spring Security中的身份验证

引言

身份验证是任何应用程序安全体系的核心部分,它确保系统的用户确实是他们声称的那个人。Spring Security作为一个强大的安全框架,提供了灵活且全面的身份验证机制。本篇文章将深入探讨Spring Security中身份验证的各个方面,包括基本概念、实现机制、常见配置和最佳实践。

什么是身份验证

身份验证(Authentication)是指确认用户身份的过程。通过身份验证,可以确保只有经过验证的用户才能访问系统资源,从而保护系统免受未经授权的访问。

Spring Security中的身份验证机制

Spring Security提供了多种身份验证机制,常见的有以下几种:

  1. 表单登录(Form Login)
  2. HTTP Basic认证
  3. OAuth2
  4. JWT(JSON Web Token)
  5. LDAP(轻量目录访问协议)
  6. 自定义身份验证

表单登录

表单登录是最常见的身份验证方式,用户通过提交包含用户名和密码的表单进行身份验证。Spring Security提供了默认的表单登录支持,并允许自定义登录页面。

配置表单登录
  1. import org.springframework.context.annotation.Bean;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  4. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  5. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  6. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  7. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  8. import org.springframework.security.crypto.password.PasswordEncoder;
  9. @Configuration
  10. @EnableWebSecurity
  11. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  12. @Override
  13. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  14. auth.inMemoryAuthentication()
  15. .withUser("user")
  16. .password(passwordEncoder().encode("password"))
  17. .roles("USER")
  18. .and()
  19. .withUser("admin")
  20. .password(passwordEncoder().encode("admin"))
  21. .roles("ADMIN");
  22. }
  23. @Override
  24. protected void configure(HttpSecurity http) throws Exception {
  25. http.authorizeRequests()
  26. .antMatchers("/admin/**").hasRole("ADMIN")
  27. .antMatchers("/user/**").hasRole("USER")
  28. .antMatchers("/", "/home").permitAll()
  29. .and()
  30. .formLogin()
  31. .loginPage("/login")
  32. .permitAll()
  33. .and()
  34. .logout()
  35. .permitAll();
  36. }
  37. @Bean
  38. public PasswordEncoder passwordEncoder() {
  39. return new BCryptPasswordEncoder();
  40. }
  41. }

HTTP Basic认证

HTTP Basic认证是一种简单的身份验证机制,用户通过在HTTP头部发送用户名和密码进行身份验证。虽然简单,但由于明文传输的特性,不推荐在生产环境中使用。

配置HTTP Basic认证
  1. @Override
  2. protected void configure(HttpSecurity http) throws Exception {
  3. http.authorizeRequests()
  4. .antMatchers("/admin/**").hasRole("ADMIN")
  5. .antMatchers("/user/**").hasRole("USER")
  6. .antMatchers("/", "/home").permitAll()
  7. .and()
  8. .httpBasic();
  9. }

OAuth2

OAuth2是一种用于授权的开放标准,允许第三方应用以有限的权限访问用户的资源。Spring Security提供了对OAuth2的支持。

配置OAuth2
  1. import org.springframework.context.annotation.Configuration;
  2. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  3. import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
  4. import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
  5. @Configuration
  6. @EnableResourceServer
  7. public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
  8. @Override
  9. public void configure(HttpSecurity http) throws Exception {
  10. http.authorizeRequests()
  11. .antMatchers("/admin/**").hasRole("ADMIN")
  12. .antMatchers("/user/**").hasRole("USER")
  13. .antMatchers("/", "/home").permitAll()
  14. .and()
  15. .oauth2Login();
  16. }
  17. }

JWT(JSON Web Token)

JWT是一种用于在网络应用环境中传递声明的方式。Spring Security支持通过JWT实现无状态认证。

配置JWT

首先,引入相关依赖:

  1. <dependency>
  2. <groupId>io.jsonwebtoken</groupId>
  3. <artifactId>jjwt</artifactId>
  4. <version>0.9.1</version>
  5. </dependency>

然后,创建JWT工具类:

  1. import io.jsonwebtoken.Claims;
  2. import io.jsonwebtoken.Jwts;
  3. import io.jsonwebtoken.SignatureAlgorithm;
  4. import org.springframework.security.core.userdetails.UserDetails;
  5. import org.springframework.stereotype.Component;
  6. import java.util.Date;
  7. import java.util.HashMap;
  8. import java.util.Map;
  9. import java.util.function.Function;
  10. @Component
  11. public class JwtUtil {
  12. private String SECRET_KEY = "secret";
  13. public String extractUsername(String token) {
  14. return extractClaim(token, Claims::getSubject);
  15. }
  16. public Date extractExpiration(String token) {
  17. return extractClaim(token, Claims::getExpiration);
  18. }
  19. public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {
  20. final Claims claims = extractAllClaims(token);
  21. return claimsResolver.apply(claims);
  22. }
  23. private Claims extractAllClaims(String token) {
  24. return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
  25. }
  26. private Boolean isTokenExpired(String token) {
  27. return extractExpiration(token).before(new Date());
  28. }
  29. public String generateToken(UserDetails userDetails) {
  30. Map<String, Object> claims = new HashMap<>();
  31. return createToken(claims, userDetails.getUsername());
  32. }
  33. private String createToken(Map<String, Object> claims, String subject) {
  34. return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis()))
  35. .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10))
  36. .signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact();
  37. }
  38. public Boolean validateToken(String token, UserDetails userDetails) {
  39. final String username = extractUsername(token);
  40. return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
  41. }
  42. }

创建JWT过滤器:

  1. import org.springframework.beans.factory.annotation.Autowired;
  2. import org.springframework.security.core.context.SecurityContextHolder;
  3. import org.springframework.security.core.userdetails.UserDetails;
  4. import org.springframework.security.core.userdetails.UserDetailsService;
  5. import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
  6. import org.springframework.stereotype.Component;
  7. import org.springframework.web.filter.OncePerRequestFilter;
  8. import io.jsonwebtoken.ExpiredJwtException;
  9. import javax.servlet.FilterChain;
  10. import javax.servlet.ServletException;
  11. import javax.servlet.http.HttpServletRequest;
  12. import javax.servlet.http.HttpServletResponse;
  13. import java.io.IOException;
  14. @Component
  15. public class JwtRequestFilter extends OncePerRequestFilter {
  16. @Autowired
  17. private UserDetailsService userDetailsService;
  18. @Autowired
  19. private JwtUtil jwtUtil;
  20. @Override
  21. protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
  22. throws ServletException, IOException {
  23. final String authorizationHeader = request.getHeader("Authorization");
  24. String username = null;
  25. String jwt = null;
  26. if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
  27. jwt = authorizationHeader.substring(7);
  28. try {
  29. username = jwtUtil.extractUsername(jwt);
  30. } catch (ExpiredJwtException e) {
  31. logger.warn("JWT Token has expired");
  32. }
  33. }
  34. if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
  35. UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
  36. if (jwtUtil.validateToken(jwt, userDetails)) {
  37. UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
  38. userDetails, null, userDetails.getAuthorities());
  39. usernamePasswordAuthenticationToken
  40. .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
  41. SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
  42. }
  43. }
  44. chain.doFilter(request, response);
  45. }
  46. }

配置JWT过滤器:

  1. import org.springframework.beans.factory.annotation.Autowired;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  5. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  6. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  7. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  8. import org.springframework.security.config.http.SessionCreationPolicy;
  9. import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
  10. @Configuration
  11. @EnableWebSecurity
  12. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  13. @Autowired
  14. private JwtRequestFilter jwtRequestFilter;
  15. @Override
  16. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  17. // 配置身份验证逻辑
  18. }
  19. @Override
  20. protected void configure(HttpSecurity http) throws Exception {
  21. http.csrf().disable()
  22. .authorizeRequests().antMatchers("/authenticate").permitAll()
  23. .anyRequest().authenticated()
  24. .and().sessionManagement()
  25. .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
  26. http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
  27. }
  28. }

LDAP(轻量目录访问协议)

LDAP是一种用于访问和维护分布式目录信息服务的开放标准协议。

Spring Security提供了对LDAP的内置支持。

配置LDAP

首先,引入相关依赖:

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-data-ldap</artifactId>
  4. </dependency>
  5. <dependency>
  6. <groupId>org.springframework.security</groupId>
  7. <artifactId>spring-security-ldap</artifactId>
  8. </dependency>

然后,配置LDAP:

  1. import org.springframework.context.annotation.Bean;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  4. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  5. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  6. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  7. import org.springframework.security.ldap.DefaultSpringSecurityContextSource;
  8. import org.springframework.security.ldap.authentication.LdapAuthenticationProvider;
  9. import org.springframework.security.ldap.authentication.ad.ActiveDirectoryLdapAuthenticationProvider;
  10. import org.springframework.security.ldap.userdetails.DefaultLdapAuthoritiesPopulator;
  11. import org.springframework.security.ldap.userdetails.LdapAuthoritiesPopulator;
  12. import org.springframework.security.ldap.userdetails.LdapUserDetailsService;
  13. @Configuration
  14. @EnableWebSecurity
  15. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  16. @Override
  17. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  18. auth.ldapAuthentication()
  19. .userDnPatterns("uid={0},ou=people")
  20. .groupSearchBase("ou=groups")
  21. .contextSource(contextSource())
  22. .passwordCompare()
  23. .passwordEncoder(new BCryptPasswordEncoder())
  24. .passwordAttribute("userPassword");
  25. }
  26. @Bean
  27. public DefaultSpringSecurityContextSource contextSource() {
  28. return new DefaultSpringSecurityContextSource(
  29. Arrays.asList("ldap://localhost:8389/"), "dc=springframework,dc=org");
  30. }
  31. }

自定义身份验证

有时候,默认的身份验证机制可能无法满足特定需求,此时可以实现自定义身份验证逻辑。可以通过自定义AuthenticationProvider来实现。

实现自定义AuthenticationProvider

  1. import org.springframework.beans.factory.annotation.Autowired;
  2. import org.springframework.security.authentication.AuthenticationProvider;
  3. import org.springframework.security.authentication.BadCredentialsException;
  4. import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  5. import org.springframework.security.core.Authentication;
  6. import org.springframework.security.core.AuthenticationException;
  7. import org.springframework.security.core.userdetails.UserDetails;
  8. import org.springframework.security.core.userdetails.UserDetailsService;
  9. import org.springframework.security.crypto.password.PasswordEncoder;
  10. import org.springframework.stereotype.Component;
  11. @Component
  12. public class CustomAuthenticationProvider implements AuthenticationProvider {
  13. @Autowired
  14. private UserDetailsService userDetailsService;
  15. @Autowired
  16. private PasswordEncoder passwordEncoder;
  17. @Override
  18. public Authentication authenticate(Authentication authentication) throws AuthenticationException {
  19. String username = authentication.getName();
  20. String password = (String) authentication.getCredentials();
  21. UserDetails user = userDetailsService.loadUserByUsername(username);
  22. if (user == null || !passwordEncoder.matches(password, user.getPassword())) {
  23. throw new BadCredentialsException("Username or password is incorrect");
  24. }
  25. return new UsernamePasswordAuthenticationToken(user, password, user.getAuthorities());
  26. }
  27. @Override
  28. public boolean supports(Class<?> authentication) {
  29. return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
  30. }
  31. }

配置自定义AuthenticationProvider

在Spring Security配置类中配置自定义的AuthenticationProvider:

  1. import org.springframework.beans.factory.annotation.Autowired;
  2. import org.springframework.context.annotation.Bean;
  3. import org.springframework.context.annotation.Configuration;
  4. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  5. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  6. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  7. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  8. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  9. import org.springframework.security.crypto.password.PasswordEncoder;
  10. @Configuration
  11. @EnableWebSecurity
  12. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  13. @Autowired
  14. private CustomAuthenticationProvider customAuthenticationProvider;
  15. @Override
  16. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  17. auth.authenticationProvider(customAuthenticationProvider);
  18. }
  19. @Override
  20. protected void configure(HttpSecurity http) throws Exception {
  21. http.authorizeRequests()
  22. .antMatchers("/admin/**").hasRole("ADMIN")
  23. .antMatchers("/user/**").hasRole("USER")
  24. .antMatchers("/", "/home").permitAll()
  25. .and()
  26. .formLogin()
  27. .loginPage("/login")
  28. .permitAll()
  29. .and()
  30. .logout()
  31. .permitAll();
  32. }
  33. @Bean
  34. public PasswordEncoder passwordEncoder() {
  35. return new BCryptPasswordEncoder();
  36. }
  37. }

常见身份验证配置

内存身份验证

内存身份验证用于在内存中存储用户信息,适用于开发和测试环境。

  1. @Override
  2. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  3. auth.inMemoryAuthentication()
  4. .withUser("user")
  5. .password(passwordEncoder().encode("password"))
  6. .roles("USER")
  7. .and()
  8. .withUser("admin")
  9. .password(passwordEncoder().encode("admin"))
  10. .roles("ADMIN");
  11. }

JDBC身份验证

JDBC身份验证用于从数据库中加载用户信息,适用于生产环境。

配置数据库连接

application.properties中配置数据库连接:

  1. spring.datasource.url=jdbc:mysql://localhost:3306/mydb
  2. spring.datasource.username=root
  3. spring.datasource.password=root
  4. spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
创建数据库表
  1. CREATE TABLE users (
  2. username VARCHAR(50) NOT NULL PRIMARY KEY,
  3. password VARCHAR(100) NOT NULL,
  4. enabled BOOLEAN NOT NULL
  5. );
  6. CREATE TABLE authorities (
  7. username VARCHAR(50) NOT NULL,
  8. authority VARCHAR(50) NOT NULL,
  9. FOREIGN KEY (username) REFERENCES users(username)
  10. );
配置JDBC身份验证
  1. import javax.sql.DataSource;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  6. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  7. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  8. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  9. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  10. import org.springframework.security.crypto.password.PasswordEncoder;
  11. @Configuration
  12. @EnableWebSecurity
  13. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  14. @Autowired
  15. private DataSource dataSource;
  16. @Override
  17. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  18. auth.jdbcAuthentication()
  19. .dataSource(dataSource)
  20. .usersByUsernameQuery("select username, password, enabled from users where username = ?")
  21. .authoritiesByUsernameQuery("select username, authority from authorities where username = ?")
  22. .passwordEncoder(passwordEncoder());
  23. }
  24. @Override
  25. protected void configure(HttpSecurity http) throws Exception {
  26. http.authorizeRequests()
  27. .antMatchers("/admin/**").hasRole("ADMIN")
  28. .antMatchers("/user/**").hasRole("USER")
  29. .antMatchers("/", "/home").permitAll()
  30. .and()
  31. .formLogin()
  32. .loginPage("/login")
  33. .permitAll()
  34. .and()
  35. .logout()
  36. .permitAll();
  37. }
  38. @Bean
  39. public PasswordEncoder passwordEncoder() {
  40. return new BCryptPasswordEncoder();
  41. }
  42. }

身份验证的最佳实践

使用强哈希算法

使用强哈希算法(如BCrypt、PBKDF2、SCrypt或Argon2)来加密密码,以提高密码的安全性。

添加盐值

为每个密码添加一个唯一的盐值,以防止彩虹表攻击。Spring Security的BCryptPasswordEncoder等实现已经内置了盐值处理。

多因素认证(MFA)

在敏感操作或登录时使用多因素认证,增加额外的安全层。

定期更新密码

要求用户定期更新密码,并在检测到异常活动时强制重置密码。

限制登录尝试次数

限制登录尝试次数,防止暴力破解攻击。

加密传输

通过HTTPS加密传输密码,防止中间人攻击。

存储密码凭证

使用安全存储机制(如Keystore或Vault)存储加密密钥和其他凭证。

综合实例

以下是一个综合实例,展示了如何在Spring Boot应用中使用Spring Security进行身份验证和管理。

项目结构

  1. src/
  2. |-- main/
  3. | |-- java/
  4. | | |-- com/
  5. | | | |-- example/
  6. | | | | |-- demo/
  7. | | | | | |-- DemoApplication.java
  8. | | | | | |-- config/
  9. | | | | | | |-- SecurityConfig.java
  10. | | | | | |-- controller/
  11. | | | | | | |-- UserController.java
  12. | | | | | |-- entity/
  13. | | | | | | |-- UserEntity.java
  14. | | | | | |-- repository/
  15. | | | | | | |-- UserRepository.java
  16. | | | | | |-- service/
  17. | | | | | | |-- UserService.java
  18. |-- resources/
  19. | |-- application.properties
  20. | |-- templates/
  21. | | |-- login.html
  22. | | |-- home.html

配置文件

application.properties

  1. spring.datasource.url=jdbc:mysql://localhost:3306/mydb
  2. spring.datasource.username=root
  3. spring.datasource.password=root
  4. spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
  5. spring.jpa.hibernate.ddl-auto=update
  6. spring.jpa.show-sql=true

实体类

UserEntity.java

  1. package com.example.demo.entity;
  2. import javax.persistence.Entity;
  3. import javax.persistence.GeneratedValue;
  4. import javax.persistence.GenerationType;
  5. import javax.persistence.Id;
  6. @Entity
  7. public class UserEntity {
  8. @Id
  9. @GeneratedValue(strategy = GenerationType.IDENTITY)
  10. private Long id;
  11. private String username;
  12. private String password;
  13. // Getters and setters
  14. public Long getId() {
  15. return id;
  16. }
  17. public void setId(Long id) {
  18. this.id = id;
  19. }
  20. public String getUsername() {
  21. return username;
  22. }
  23. public void setUsername(String username) {
  24. this.username = username;
  25. }
  26. public String getPassword() {
  27. return password;
  28. }
  29. public void setPassword(String password) {
  30. this.password = password;
  31. }
  32. }

仓库接口

UserRepository.java

  1. package com.example.demo.repository;
  2. import org.springframework.data.jpa.repository.JpaRepository;
  3. import com.example.demo.entity.UserEntity;
  4. public interface UserRepository extends JpaRepository<UserEntity, Long> {
  5. UserEntity findByUsername(String username);
  6. }

服务类

UserService.java

  1. package com.example.demo.service;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.security.crypto.password.PasswordEncoder;
  4. import org.springframework.stereotype.Service;
  5. import com.example.demo.entity.UserEntity;
  6. import com.example.demo.repository.UserRepository;
  7. @Service
  8. public class UserService {
  9. @Autowired
  10. private UserRepository userRepository;
  11. @Autowired
  12. private PasswordEncoder passwordEncoder;
  13. public void registerUser(String username, String rawPassword) {
  14. String encodedPassword = passwordEncoder.encode(rawPassword);
  15. UserEntity user = new UserEntity();
  16. user.setUsername(username);
  17. user.setPassword(encodedPassword);
  18. userRepository.save(user);
  19. }
  20. public void updatePassword(String username, String newPassword) {
  21. UserEntity user = userRepository.findByUsername(username);
  22. if (user != null) {
  23. String encodedPassword = passwordEncoder.encode(newPassword);
  24. user.setPassword(encodedPassword);
  25. userRepository.save(user);
  26. }
  27. }
  28. public UserEntity findByUsername(String username) {
  29. return userRepository.findByUsername(username);
  30. }
  31. }

控制器类

UserController.java

  1. package com.example.demo.controller;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.stereotype.Controller;
  4. import org.springframework.ui.Model;
  5. import org.springframework.web.bind.annotation.GetMapping;
  6. import org.springframework.web.bind.annotation.PostMapping;
  7. import com.example.demo.service.UserService;
  8. @Controller
  9. public class UserController {
  10. @Autowired
  11. private UserService userService;
  12. @GetMapping("/login")
  13. public String login() {
  14. return "login";
  15. }
  16. @GetMapping("/home")
  17. public String home() {
  18. return "home";
  19. }
  20. @PostMapping("/register")
  21. public String register(String username, String password) {
  22. userService.registerUser(username, password);
  23. return "redirect:/login";
  24. }
  25. }

配置类

SecurityConfig.java

  1. package com.example.demo.config;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.context.annotation.Bean;
  4. import org.springframework.context.annotation.Configuration;
  5. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  6. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  7. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  8. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  9. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  10. import org.springframework.security.crypto.password.PasswordEncoder;
  11. import com.example.demo.service.UserService;
  12. @Configuration
  13. @EnableWebSecurity
  14. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  15. @Autowired
  16. private UserService userService;
  17. @Override
  18. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  19. auth.userDetailsService(userService::findByUsername).passwordEncoder(passwordEncoder());
  20. }
  21. @Override
  22. protected void configure(HttpSecurity http) throws Exception {
  23. http.authorizeRequests()
  24. .antMatchers("/home").authenticated()
  25. .anyRequest().permitAll()
  26. .and()
  27. .formLogin()
  28. .loginPage("/login")
  29. .defaultSuccessUrl("/home", true)
  30. .permitAll()
  31. .and()
  32. .logout()
  33. .permitAll();
  34. }
  35. @Bean
  36. public PasswordEncoder passwordEncoder() {
  37. return new BCryptPasswordEncoder();
  38. }
  39. }

模板文件

login.html

  1. <!DOCTYPE html>
  2. <html xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <title>Login</title>
  5. </head>
  6. <body>
  7. <h1>Login</h1>
  8. <form th:action="@{/login}" method="post">
  9. <div>
  10. <label>Username:</label>
  11. <input type="text" name="username" />
  12. </div>
  13. <div>
  14. <label>Password:</label>
  15. <input type="password" name="password" />
  16. </div>
  17. <div>
  18. <button type="submit">Login</button>
  19. </div>
  20. </form>
  21. <h2>Register</h2>
  22. <form th:action="@{/register}" method="post">
  23. <div>
  24. <label>Username:</label>
  25. <input type="text" name="username" />
  26. </div>
  27. <div>
  28. <label>Password:</label>
  29. <input type="password" name="password" />
  30. </div>
  31. <div>
  32. <button type="submit">Register</button>
  33. </div>
  34. </form>
  35. </body>
  36. </html>

home.html

  1. <!DOCTYPE html>
  2. <html xmlns:th="http://www.thymeleaf.org">
  3. <head>
  4. <title>Home</title>
  5. </head>
  6. <body>
  7. <h1>Home</h1>
  8. <p>Welcome to the home page!</p>
  9. <a th:href="@{/logout}">Logout</a>
  10. </body>
  11. </html>

总结

通过本文的介绍,我们详细探讨了Spring Security中身份验证的各个方面,包括基本概念、实现机制、常见配置和最佳实践。身份验证是确保系统安全的关键步骤,Spring Security提供了灵活且强大的身份验证机制,可以通过自定义用户信息和身份验证逻辑来满足不同的安全需求。