(十二)Spring Security

Spring Security 是一个用于 Java 应用程序的身份验证和访问控制框架,广泛用于保护 Web 应用、RESTful API、微服务等。它能够处理身份验证(Authentication)和授权(Authorization)功能,同时还提供了防止 CSRF 攻击、会话管理、密码加密等安全功能。

一、Spring Security 核心功能

1.认证(Authentication)

认证是确保用户身份的过程,通常是通过用户名和密码等信息验证用户身份。

Spring Security 提供了多种认证方式,如基于表单的认证、HTTP 基本认证、LDAP、OAuth2 。

2.授权(Authorization)

授权是根据用户的身份信息授予访问特定资源的权限。

Spring Security 通过角色、权限等来限制资源访问。

常见的做法:通过角色(如管理员、普通用户)来控制访问某些页面或 API。

常用注解:@PreAuthorize、@Secured

3.防止CSRF攻击(Cross-Site Request Forgery)

CSRF(跨站请求伪造)是一种利用受信任用户身份进行恶意操作的攻击方式。

Spring Security 内置了对CSRF攻击的防护机制,可以通过CSRF令牌来防止跨站请求伪造。CSRF 防护默认启用,但可以通过配置禁用它。

4.会话管理(Session Management)

提供了丰富的会话管理功能,可以控制会话的生命周期、并发会话限制、会话固定攻击防护等。

5.密码加密(Password Encoding)

支持多种密码加密方案,如BCrypt、PBKDF2等,提供强大的密码加密与存储机制。

6.跨域资源共享(CORS)支持

支持跨域请求保护,可以防止未授权的跨域请求。

7.集成其他安全机制

Spring Security 与OAuth 2.0、JWT(JSON Web Tokens)、SAML、LDAP等安全协议的集成能力强,适用于多种场景。

二、Spring Security工作原理

Spring Security 通过拦截所有的HTTP请求,应用安全规则进行认证和授权。

其工作原理大致可以概括为以下几个步骤:

1.请求进入Spring Security 过滤器链

每个HTTP请求都会进入过滤器链,这些过滤器会根据配置的规则执行一系列的安全检查。

2.认证过程

在过滤器链中,AuthenticationFilter会接收请求,验证请求中的用户凭证(如用户名和密码)。

通过AuthenticationManager来处理这些凭证并进行认证。

3.授权过程

一旦用户通过认证,会将用户的权限信息存储在SecurityContext中。

在后续的请求中,根据用户角色和权限信息,执行访问控制判断,决定是否允许访问指定的资源。

4.安全拦截

根据配置的http安全规则,判断用户是否有权限访问特定的URL或资源。

如果用户未通过认证或授权,会返回适当的错误信息或重定向到登录页面。

三、Spring Security 依赖

1.依赖

    org.springframework.boot

    spring-boot-starter-security

四、Spring Security 5 之前配置

Spring Security 5之前,使用 @EnableWebSecurity 启用Spring Security的Web安全功能,继承WebSecurityConfigurerAdapter 类重写 configure 方法,来实现自定义的安全配置。

1.Java配置(SecurityConfig)

(1)注解

@Configuration:

标注该类为Spring配置类。

@EnableWebSecurity:

启用Spring Security的Web安全功能。

WebSecurityConfigurerAdapter:

提供默认的配置,可以继承它并重写一些方法来自定义安全配置。

configure(HttpSecurity http):

用于配置HTTP安全规则,控制访问权限、登录方式、登出功能等。

configure(AuthenticationManagerBuilder auth):

用于配置认证管理器,指定用户的认证方式。

(2)配置示例

@Configuration

@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter {

    // 配置 HTTP 安全设置

    @Override

    protected void configure(HttpSecurity http) throws Exception {

        http

            .authorizeRequests()

                .antMatchers("/admin/**").hasRole("ADMIN")  // 只有 ADMIN 角色的用户能访问

                .antMatchers("/user/**").hasRole("USER")  // 只有 USER 角色的用户能访问

                .anyRequest().authenticated()  // 其他请求需要认证

            .and()

            .formLogin()  // 启用表单登录

                .loginPage("/login")  // 自定义登录页面

                .permitAll()  // 允许所有用户访问登录页面

            .and()

                .logout()  // 启用注销功能

                .permitAll();

    }

    // 配置认证方式

    @Override

    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth.inMemoryAuthentication()  // 使用内存中的用户存储

            .withUser("user").password("{noop}password").roles("USER")  // 定义一个用户

            .and()

            .withUser("admin").password("{noop}admin").roles("ADMIN");  // 定义一个管理员

    }

}

(3)认证机制

Spring Security支持多种认证方式,常见的包括表单认证、LDAP认证、OAuth2认证等。

HTTP 基本认证:

http.httpBasic();  // 启用基本认证

表单认证配置:

http

    .formLogin()

    .loginPage("/login")  // 自定义登录页面

    .loginProcessingUrl("/authenticate")  // 提交登录请求的URL

    .defaultSuccessUrl("/home", true)  // 登录成功后跳转到的页面

    .failureUrl("/login?error=true");  // 登录失败后的页面

JWT 认证:

public class JWTAuthenticationFilter extends OncePerRequestFilter {

    @Override

    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,

                                                     FilterChain filterChain) throws ServletException, IOException {

        String token = request.getHeader("Authorization");

        if (token != null && token.startsWith("Bearer ")) {

            // 处理 JWT 认证

        }

        filterChain.doFilter(request, response);

    }

}

自定义认证登录:

通过 UsernamePasswordAuthenticationFilter 可以自定义登录的认证过程,

例如:修改表单字段的名字。

http

    .addFilterBefore(new CustomAuthenticationFilter() , UsernamePasswordAuthenticationFilter.class);

(2)授权机制

Spring Security 提供了细粒度的授权控制。支持基于角色或权限的访问控制。

可以通过 antMatchers() mvcMatchers() 来配置特定URL的访问控制规则。

基于角色的访问控制:

http

    .authorizeRequests()

    .antMatchers("/admin/**").hasRole("ADMIN")  

     // 只有ADMIN角色才能访问/admin/*路径

    .antMatchers("/user/**").hasAnyRole("USER", "ADMIN")  

     // USER或ADMIN角色都可以访问/user/*路径

    .anyRequest().authenticated();  // 其他请求需要认证

方法级别的授权控制:

使用 @Secured @PreAuthorize 注解来限制方法的访问

@Secured("ROLE_ADMIN")

public void deleteUser(Long userId) {

    // 只有管理员可以调用此方法

}

@PreAuthorize("hasRole('ROLE_ADMIN') and #userId == authentication.principal.id")

public void updateUser(Long userId) {

    // 只有管理员并且用户ID匹配时可以调用

}

(3)会话管理

Spring Security 允许你配置会话管理策略,例如限制同一时间内的会话数量,或者强制用户注销。

http

    .sessionManagement()

    .maximumSessions(1)  // 限制同一用户只能有一个会话

    .expiredUrl("/session-expired");  // 会话过期时的重定向 URL

(4)CSRF保护

Spring Security 默认启用CSRF保护,如果不需要CSRF保护,可禁用。

http

    .csrf().disable();

(5)配置用户服务

在实际应用中,用户信息通常来自数据库、LDAP 或其他身份验证源。

可以使用 JdbcUserDetailsManager 来连接数据库进行认证。

@Override

protected void configure(AuthenticationManagerBuilder auth) throws Exception {

    auth

      .jdbcAuthentication()

      .dataSource(dataSource)  // 配置数据源

      .usersByUsernameQuery("SELECT username, password, enabled FROM users WHERE username=?")

      .authoritiesByUsernameQuery("SELECT username, authority FROM authorities WHERE username=?");

}

3.YML配置

(1)基本认证配置(Basic Authentication)

基本认证通常使用用户名和密码来进行身份验证。

spring:

  security:

    user:

      name: user       # 默认用户名

      password: password # 默认密码

    # 启用 HTTP Basic Authentication

    http:

      basic:

        enabled: true   # 启用基本认证

(2)CSRF 配置

跨站请求伪造(CSRF)攻击防护在 Spring Security 中是默认启用的。可以选择禁用 CSRF。

spring:

  security:

    user:

      name: user       # 默认用户名

      password: password # 默认密码

    # 启用 HTTP Basic Authentication

    http:

      basic:

        enabled: true   # 启用基本认证

      # CSRF 防护(根据需要禁用)

      csrf:

        enabled: false  # 如果需要禁用 CSRF 防护

(3)表单登录配置(Form-based Authentication)

表单登录允许用户通过一个自定义的登录页面进行认证。

spring:

  security:

    # 启用表单登录

    http:

      form-login:

        login-page: /login    # 自定义登录页面的路径

        login-processing-url: /login    # 处理登录请求的 URL

        default-success-url: /home   # 登录成功后跳转的 URL

        failure-url: /login?error   # 登录失败后跳转的 URL

        username-parameter: username   # 登录表单中用户名的字段名

        password-parameter: password   # 登录表单中密码的字段名

        permit-all: true   # 允许所有用户访问登录页面

(4)登出配置(Logout)

支持配置登出行为,允许用户退出登录时进行定制化操作。

spring:

  security:

    http:

      logout:

        logout-url: /logout   # 处理登出的 URL

        logout-success-url: /login?logout   # 登出成功后重定向的 URL

        invalidate-session: true   # 是否使会话无效

        delete-cookies: JSESSIONID   # 登出时删除的 Cookie 名称

(5)角色和权限配置

配置角色和权限。

spring:

  security:

    http:

      authorize-requests:

        - antMatchers("/admin/**").hasRole("ADMIN")  

        # 只有 ADMIN 角色的用户才能访问 /admin/**

        - antMatchers("/user/**").hasAnyRole("USER", "ADMIN")  

        # 用户或管理员可以访问 /user/**

        - antMatchers("/public/**").permitAll()  

        # 所有人都可以访问 /public/**

        - antMatchers("/login").permitAll()  

        # 允许所有用户访问登录页面

        - antMatchers("/**").authenticated()  

        # 其他路径需要认证后访问

(6)会话管理

spring:

  security:

    http:

      session-management:

        maximum-sessions: 1  

        # 限制每个用户的最大会话数量

        max-sessions-prevents-login: true  

        # 如果会话已满,禁止新用户登录

        session-fixation:

          none: true   # 禁用会话固定攻击保护

(7)禁用默认的 HTTP 端点

spring:

  security:

    disable:

      default-login: true  # 禁用默认登录页面

(8)自定义错误页面

spring:

  security:

    http:

      unauthorized-url: /403  # 未授权时跳转到的页面

      access-denied-page: /403  # 无权限时跳转到的页面

(9)OAuth2 登录配置

spring:

  security:

    oauth2:

      client:

        registration:

          google:

            client-id: YOUR_GOOGLE_CLIENT_ID

            client-secret: YOUR_GOOGLE_CLIENT_SECRET

            scope:

              - profile

              - email

            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"

            authorization-grant-type: authorization_code

            client-name: Google

            login-page: /login/oauth2

        provider:

          google:

            authorization-uri: https://accounts.google.com/o/oauth2/auth

            token-uri: https://oauth2.googleapis.com/token

            user-info-uri: https://www.googleapis.com/oauth2/v3/userinfo

            user-name-attribute: id

五、Spring Security 6 之后配置

1.Java配置(SecurityConfig)

Spring Security 5.0 以后,WebSecurityConfigurerAdapter已经被标记为废弃(deprecated),不再推荐使用。推荐自定义 SecurityConfig 配置。

(1)SecurityConfig

SecurityFilterChain:

SecurityFilterChain 配置 HTTP 安全设置。

InMemoryUserDetailsManager:

配置内存中的用户,通过 User.builder() 方式配置用户名、密码和角色。

BCryptPasswordEncoder :

默认的密码加密方式。

@Configuration

@EnableWebSecurity

public class SecurityConfig {

    // 使用 SecurityFilterChain 来配置 HTTP 安全设置

    @Bean

    public SecurityFilterChain securityFilterChain(HttpSecurity http) hrows Exception {

        http

            .authorizeRequests()

                .antMatchers("/login", "/signup").permitAll()  // 公开页面

                .anyRequest().authenticated()  // 其他页面需要认证

            .and()

            .formLogin()

                .loginPage("/login")  // 自定义登录页面

                .permitAll()

            .and()

            .logout()

                .permitAll();  // 允许登出

        return http.build();

    }

    // 配置 InMemory 用户存储,通常生产环境会使用数据库等持久化存储

    @Bean

    public InMemoryUserDetailsManager userDetailsService() {

        return new InMemoryUserDetailsManager(

            User.builder()

                .username("user")

                .password(passwordEncoder().encode("password"))

                .roles("USER")

                .build(),

            User.builder()

                .username("admin")

                .password(passwordEncoder().encode("admin"))

                .roles("ADMIN")

                .build()

        );

    }

    // 配置密码加密器

    @Bean

    public PasswordEncoder passwordEncoder() {

        return new BCryptPasswordEncoder();

    }

}

2.YML配置

spring:

  security:

    user:

      name: user       # 默认用户名

      password: password # 默认密码

    # 启用 HTTP Basic Authentication

    http:

      basic:

        enabled: true   # 启用基本认证

      # CSRF 防护

      csrf:

        enabled: false  # 如果需要禁用 CSRF 防护

      # 启用表单登录

      form-login:

        login-page: /login    # 自定义登录页面的路径

        login-processing-url: /login    # 处理登录请求的 URL

        default-success-url: /home   # 登录成功后跳转的 URL

        failure-url: /login?error   # 登录失败后跳转的 URL

        username-parameter: username   # 登录表单中用户名的字段名

        password-parameter: password   # 登录表单中密码的字段名

        permit-all: true   # 允许所有用户访问登录页面

      # 退出

      logout:

        logout-url: /logout   # 处理登出的 URL

        logout-success-url: /login?logout   # 登出成功后重定向的 URL

        invalidate-session: true   # 是否使会话无效

        delete-cookies: JSESSIONID   # 登出时删除的 Cookie 名称

      # 角色和权限

      authorize-requests:

        - antMatchers("/admin/**").hasRole("ADMIN")          

        - antMatchers("/user/**").hasAnyRole("USER", "ADMIN")          

        - antMatchers("/public/**").permitAll()  

        - antMatchers("/login").permitAll()          

        - antMatchers("/**").authenticated()  

        # 会话管理

      session-management:

        maximum-sessions: 1  #限制每个用户的最大会话数量

        max-sessions-prevents-login: true#如果会话已满,禁止新用户登录

        session-fixation:

          none: true   # 禁用会话固定攻击保护

        # 自定义错误页面

      unauthorized-url: /403  # 未授权时跳转到的页面

      access-denied-page: /403  # 无权限时跳转到的页面

        # 禁用默认的 HTTP 端点

      disable:

          default-login: true  # 禁用默认登录页面

# 启用 HTTP Basic 或 OAuth2 支持

    oauth2:

      login:

        client-id: YOUR_CLIENT_ID

        client-secret: YOUR_CLIENT_SECRET

      # OAuth2 登录配置

      client:

        registration:

          google:

            client-id: YOUR_GOOGLE_CLIENT_ID

            client-secret: YOUR_GOOGLE_CLIENT_SECRET

            scope:

              - profile

              - email

            redirect-uri: "{baseUrl}/login/oauth2/code/{registrationId}"

            authorization-grant-type: authorization_code

            client-name: Google

            login-page: /login/oauth2

        provider:

          google:

            authorization-uri: https://accounts.google.com/o/oauth2/auth

            token-uri: https://oauth2.googleapis.com/token

            user-info-uri: https://www.googleapis.com/oauth2/v3/userinfo

            user-name-attribute: id

      #JWT 配置

      resourceserver:

        jwt:

          issuer-uri: https://your-issuer-uri.com

          jwk-set-uri: https://your-issuer-uri.com/.well-known/jwks.json

#Session Timeout 配置

server:

  session:

    timeout: 15m  # 设置会话的最大过期时间为 15 分钟

六、Spring Security 集成与扩展

Spring Security 还可以与其他技术进行集成,支持多种认证协议和扩展功能。

1.与 LDAP 集成

Spring Security 支持 LDAP 认证,可以用 LDAP 服务器进行身份验证和授权。

http.ldapAuthentication()

    .userSearchBase("ou=people")

    .userSearchFilter("(uid={0})")

    .contextSource()

        .url("ldap://localhost:8389/dc=springframework,dc=org");

七、总结

Spring Security 是一个强大且灵活的框架,支持多种认证和授权方式,能够满足各种应用场景的安全需求。它不仅为 Web 应用提供认证和授权功能,还可以与 OAuth2、JWT、LDAP 等技术无缝集成。通过灵活的配置和细粒度的权限控制,帮助开发者构建高度安全的应用。

你可能感兴趣的:(Spring,spring,java,后端)