自学内容网 自学内容网

Spring Security 认证

Spring Security 是一个功能强大的安全框架,广泛用于保护 Java 应用程序。它提供了多种认证和授权机制,以确保应用程序的安全性。以下是认证过程的详细概述以及几种常见的认证方式。

认证过程概述

  1. 用户凭证提交

    • 用户通过登录表单提交用户名和密码。通常,这可以通过一个 HTML 表单实现,表单中的 action 属性指向一个处理登录请求的 URL。
  2. 认证令牌创建

    • Spring Security 接收到用户的凭证后,会创建一个 Authentication 对象。这个对象包含了用户的凭证信息(如用户名和密码)以及其他可能的属性。
  3. 认证管理器

    • AuthenticationManager 负责验证 Authentication 对象。它通常会委托给一个或多个 AuthenticationProvider 来执行具体的验证逻辑。每个 AuthenticationProvider 负责特定类型的认证,例如基于数据库的认证或基于 LDAP 的认证。
  4. 安全上下文

    • 如果认证成功,AuthenticationManager 会将 Authentication 对象存储在 SecurityContextHolder 中。SecurityContextHolder 是一个线程局部变量,用于存储当前用户的认证信息,使用户详情在整个请求过程中全局可访问。
  5. 认证结果处理

    • 认证成功后,用户会被重定向到一个成功页面或继续访问受保护的资源。如果认证失败,用户会被重定向到一个错误页面或显示错误消息。

常见认证方式

1. 内存认证

内存认证是最简单的认证方式,适用于测试和开发环境。它将用户详细信息存储在内存中。

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests((authorize) -> authorize
                .anyRequest().authenticated()
            )
            .httpBasic(withDefaults())
            .formLogin(withDefaults());

        return http.build();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails userDetails = User.withDefaultPasswordEncoder()
            .username("user")
            .password("password")
            .roles("USER")
            .build();

        return new InMemoryUserDetailsManager(userDetails);
    }
}
2. 数据库认证

数据库认证从自定义数据源(如数据库)加载用户详细信息。你需要实现 UserDetailsService 接口来加载用户信息。

@Service
@AllArgsConstructor
public class CustomUserDetailsService implements UserDetailsService {

    private UserRepository userRepository;

    @Override
    public UserDetails loadUserByUsername(String usernameOrEmail) throws UsernameNotFoundException {
        User user = userRepository.findByUsernameOrEmail(usernameOrEmail, usernameOrEmail)
            .orElseThrow(() -> new UsernameNotFoundException("User not found by Username or Email: " + usernameOrEmail));

        Set<GrantedAuthority> authorities = user.getRoles().stream()
            .map((role) -> new SimpleGrantedAuthority(role.getName()))
            .collect(Collectors.toSet());

        return new org.springframework.security.core.userdetails.User(
            usernameOrEmail,
            user.getPassword(),
            authorities
        );
    }
}
3. 表单认证

表单认证是最常见的认证方式,用户通过表单提交用户名和密码。Spring Security 提供了默认的表单登录页面和处理逻辑。

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests((authorize) -> authorize
                .anyRequest().authenticated()
            )
            .formLogin(formLogin -> formLogin
                .loginPage("/login")
                .permitAll()
                .defaultSuccessUrl("/home", true)
                .failureUrl("/login?error=true")
            )
            .logout(logout -> logout
                .logoutUrl("/logout")
                .logoutSuccessUrl("/login")
                .invalidateHttpSession(true)
                .deleteCookies("JSESSIONID")
            );

        return http.build();
    }
}
4. 基本认证

基本认证是一种简单的 HTTP 认证方案,常用于 API 认证。它通过在 HTTP 请求头中添加 Authorization 头来传递用户名和密码。

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests((authorize) -> authorize
                .anyRequest().authenticated()
            )
            .httpBasic(Customizer.withDefaults());

        return http.build();
    }
}
5. JWT 认证

JWT 认证适用于 RESTful API 和微服务,提供了一种无状态的认证方式。JWT 令牌包含用户信息和签名,可以在每次请求时传递。

@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    private final JwtTokenProvider jwtTokenProvider;
    private final UserDetailsService userDetailsService;

    public JwtAuthenticationFilter(JwtTokenProvider jwtTokenProvider, UserDetailsService userDetailsService) {
        this.jwtTokenProvider = jwtTokenProvider;
        this.userDetailsService = userDetailsService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = getTokenFromRequest(request);

        if (StringUtils.hasText(token) && jwtTokenProvider.validateToken(token)) {
            String username = jwtTokenProvider.getUsername(token);
            UserDetails userDetails = userDetailsService.loadUserByUsername(username);

            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
                userDetails, null, userDetails.getAuthorities()
            );

            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        }

        filterChain.doFilter(request, response);
    }

    private String getTokenFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return null;
    }
}
6. OAuth2 认证

OAuth2 是一种授权框架,允许第三方服务代表用户交换资源。Spring Security 提供了对 OAuth2 的全面支持。

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests((authorize) -> authorize
                .anyRequest().authenticated()
            )
            .oauth2Login(oauth2 -> oauth2
                .loginPage("/login")
                .permitAll()
                .defaultSuccessUrl("/home", true)
                .failureUrl("/login?error=true")
            );

        return http.build();
    }

    @Bean
    public ClientRegistrationRepository clientRegistrationRepository() {
        // 配置客户端注册信息
        return new InMemoryClientRegistrationRepository(this.googleClientRegistration());
    }

    private ClientRegistration googleClientRegistration() {
        return ClientRegistration.withRegistrationId("google")
            .clientId("your-client-id")
            .clientSecret("your-client-secret")
            .clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
            .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
            .redirectUri("{baseUrl}/login/oauth2/code/{registrationId}")
            .scope("openid", "profile", "email")
            .authorizationUri("https://accounts.google.com/o/oauth2/auth")
            .tokenUri("https://accounts.google.com/o/oauth2/token")
            .userInfoUri("https://www.googleapis.com/oauth2/v3/userinfo")
            .userNameAttributeName("sub")
            .jwkSetUri("https://www.googleapis.com/oauth2/v3/certs")
            .clientName("Google")
            .build();
    }
}

结论

Spring Security 提供了强大的认证机制,支持多种认证方式,包括内存认证、数据库认证、表单认证、基本认证、JWT 认证和 OAuth2 认证。通过理解和应用这些认证机制,你可以确保应用程序的安全性,提供一个安全可靠的数字环境。每种认证方式都有其适用场景,选择合适的认证方式可以更好地满足你的应用需求。


原文地址:https://blog.csdn.net/woshichenpi/article/details/143868161

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!