Spring Security 是一个用于 Java 应用程序的身份验证和访问控制框架,广泛用于保护 Web 应用、RESTful API、微服务等。它能够处理身份验证(Authentication)和授权(Authorization)功能,同时还提供了防止 CSRF 攻击、会话管理、密码加密等安全功能。
认证是确保用户身份的过程,通常是通过用户名和密码等信息验证用户身份。
Spring Security 提供了多种认证方式,如基于表单的认证、HTTP 基本认证、LDAP、OAuth2 。
授权是根据用户的身份信息授予访问特定资源的权限。
Spring Security 通过角色、权限等来限制资源访问。
常见的做法:通过角色(如管理员、普通用户)来控制访问某些页面或 API。
常用注解:@PreAuthorize、@Secured
3.防止CSRF攻击(Cross-Site Request Forgery)
CSRF(跨站请求伪造)是一种利用受信任用户身份进行恶意操作的攻击方式。
Spring Security 内置了对CSRF攻击的防护机制,可以通过CSRF令牌来防止跨站请求伪造。CSRF 防护默认启用,但可以通过配置禁用它。
提供了丰富的会话管理功能,可以控制会话的生命周期、并发会话限制、会话固定攻击防护等。
支持多种密码加密方案,如BCrypt、PBKDF2等,提供强大的密码加密与存储机制。
支持跨域请求保护,可以防止未授权的跨域请求。
Spring Security 与OAuth 2.0、JWT(JSON Web Tokens)、SAML、LDAP等安全协议的集成能力强,适用于多种场景。
Spring Security 通过拦截所有的HTTP请求,应用安全规则进行认证和授权。
其工作原理大致可以概括为以下几个步骤:
每个HTTP请求都会进入过滤器链,这些过滤器会根据配置的规则执行一系列的安全检查。
在过滤器链中,AuthenticationFilter会接收请求,验证请求中的用户凭证(如用户名和密码)。
通过AuthenticationManager来处理这些凭证并进行认证。
一旦用户通过认证,会将用户的权限信息存储在SecurityContext中。
在后续的请求中,根据用户角色和权限信息,执行访问控制判断,决定是否允许访问指定的资源。
根据配置的http安全规则,判断用户是否有权限访问特定的URL或资源。
如果用户未通过认证或授权,会返回适当的错误信息或重定向到登录页面。
1.依赖
|
Spring Security 5之前,使用 @EnableWebSecurity 启用Spring Security的Web安全功能,继承WebSecurityConfigurerAdapter 类并重写 configure 方法,来实现自定义的安全配置。
@Configuration:
标注该类为Spring配置类。
@EnableWebSecurity:
启用Spring Security的Web安全功能。
WebSecurityConfigurerAdapter:
提供默认的配置,可以继承它并重写一些方法来自定义安全配置。
configure(HttpSecurity http):
用于配置HTTP安全规则,控制访问权限、登录方式、登出功能等。
configure(AuthenticationManagerBuilder auth):
用于配置认证管理器,指定用户的认证方式。
@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"); // 定义一个管理员 } } |
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); |
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匹配时可以调用 } |
Spring Security 允许你配置会话管理策略,例如限制同一时间内的会话数量,或者强制用户注销。
http .sessionManagement() .maximumSessions(1) // 限制同一用户只能有一个会话 .expiredUrl("/session-expired"); // 会话过期时的重定向 URL |
Spring Security 默认启用CSRF保护,如果不需要CSRF保护,可禁用。
http .csrf().disable(); |
在实际应用中,用户信息通常来自数据库、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=?"); } |
基本认证通常使用用户名和密码来进行身份验证。
spring: security: user: name: user # 默认用户名 password: password # 默认密码 # 启用 HTTP Basic Authentication http: basic: enabled: true # 启用基本认证 |
跨站请求伪造(CSRF)攻击防护在 Spring Security 中是默认启用的。可以选择禁用 CSRF。
spring: security: user: name: user # 默认用户名 password: password # 默认密码 # 启用 HTTP Basic Authentication http: basic: enabled: true # 启用基本认证 # CSRF 防护(根据需要禁用) csrf: enabled: false # 如果需要禁用 CSRF 防护 |
表单登录允许用户通过一个自定义的登录页面进行认证。
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 # 允许所有用户访问登录页面 |
支持配置登出行为,允许用户退出登录时进行定制化操作。
spring: security: http: logout: logout-url: /logout # 处理登出的 URL logout-success-url: /login?logout # 登出成功后重定向的 URL invalidate-session: true # 是否使会话无效 delete-cookies: JSESSIONID # 登出时删除的 Cookie 名称 |
配置角色和权限。
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() # 其他路径需要认证后访问 |
spring: security: http: session-management: maximum-sessions: 1 # 限制每个用户的最大会话数量 max-sessions-prevents-login: true # 如果会话已满,禁止新用户登录 session-fixation: none: true # 禁用会话固定攻击保护 |
spring: security: disable: default-login: true # 禁用默认登录页面 |
spring: security: http: unauthorized-url: /403 # 未授权时跳转到的页面 access-denied-page: /403 # 无权限时跳转到的页面 |
spring: security: oauth2: client: registration: google: client-id: YOUR_GOOGLE_CLIENT_ID client-secret: YOUR_GOOGLE_CLIENT_SECRET scope: - profile 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 5.0 以后,WebSecurityConfigurerAdapter已经被标记为废弃(deprecated),不再推荐使用。推荐自定义 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(); } } |
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 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 支持 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 等技术无缝集成。通过灵活的配置和细粒度的权限控制,帮助开发者构建高度安全的应用。