JAVA-TUTORIAL JAVA-TUTORIAL
首页
JavaEE
  • Java 构建
  • Java IDE
  • Java 监控诊断
  • Java IO 工具
  • JavaBean 工具
  • Java 模板引擎
  • Java 测试工具
Java框架
Java中间件
  • Java 教程 📚 (opens new window)
  • JavaCore 教程 📚 (opens new window)
GitHub (opens new window)
首页
JavaEE
  • Java 构建
  • Java IDE
  • Java 监控诊断
  • Java IO 工具
  • JavaBean 工具
  • Java 模板引擎
  • Java 测试工具
Java框架
Java中间件
  • Java 教程 📚 (opens new window)
  • JavaCore 教程 📚 (opens new window)
GitHub (opens new window)
  • JavaEE

  • 软件

  • 工具

  • 框架

    • Spring

    • ORM

    • 安全

      • Shiro 快速入门
      • Spring Security 快速入门
        • 快速开始
        • 核心 API
        • 设计原理
        • 认证
          • 数据模型
          • 认证基本流程
          • 用户名/密码认证
          • 表单认证
          • 基本认证
          • 内存认证
          • JDBC 认证
          • UserDetailsService
          • PasswordEncoder
          • Remember-Me
        • Spring Boot 集成
        • 参考资料
    • IO

  • 中间件

  • Java
  • 框架
  • 安全
dunwu
2022-02-17
目录
快速开始
核心 API
设计原理
认证
数据模型
认证基本流程
用户名/密码认证
表单认证
基本认证
内存认证
JDBC 认证
UserDetailsService
PasswordEncoder
Remember-Me
Spring Boot 集成
参考资料

Spring Security 快速入门

# Spring Security 快速入门

# 快速开始

参考:Securing a Web Application (opens new window)

# 核心 API

# 设计原理

Spring Security 对于 Servlet 的支持基于过滤链(FilterChain)实现。

Spring 提供了一个名为 DelegatingFilterProxy 的 Filter 实现,该实现允许在 Servlet 容器的生命周期和 Spring 的 ApplicationContext 之间进行桥接。 Servlet 容器允许使用其自己的标准注册 Filters,但它不了解 Spring 定义的 Bean。 DelegatingFilterProxy 可以通过标准的 Servlet 容器机制进行注册,但是可以将所有工作委托给实现 Filter 的 Spring Bean。

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) {
    // Lazily get Filter that was registered as a Spring Bean
    // For the example in DelegatingFilterProxy delegate is an instance of Bean Filter0
    Filter delegate = getFilterBean(someBeanName);
    // delegate work to the Spring Bean
    delegate.doFilter(request, response);
}

FilterChainProxy 使用 SecurityFilterChain 确定应对此请求调用哪些 Spring Security 过滤器。

SecurityFilterChain 中的安全过滤器通常是 Bean,但它们是使用 FilterChainProxy 而不是 DelegatingFilterProxy 注册的。

实际上,FilterChainProxy 可用于确定应使用哪个 SecurityFilterChain。如果您的应用程序可以为不同的模块提供完全独立的配置。

multi securityfilterchain

ExceptionTranslationFilter 可以将 AccessDeniedException 和 AuthenticationException 转换为 HTTP 响应。

exceptiontranslationfilter

核心源码:

try {
    filterChain.doFilter(request, response);
} catch (AccessDeniedException | AuthenticationException e) {
    if (!authenticated || e instanceof AuthenticationException) {
        startAuthentication();
    } else {
        accessDenied();
    }
}

# 认证

# 数据模型

Spring Security 框架中的认证数据模型如下:

img

  • Authentication - 认证信息实体。
    • principal - 用户标识。如:用户名、账户名等。通常是 UserDetails 的实例(后面详细讲解)。
    • credentials - 认证凭证。如:密码等。
    • authorities - 授权信息。如:用户的角色、权限等信息。
  • SecurityContext - 安全上下文。包含一个 Authentication 对象。
  • SecurityContextHolder - 安全上下文持有者。用于存储认证信息。

【示例】注册认证信息

SecurityContext context = SecurityContextHolder.createEmptyContext();
Authentication authentication =
    new TestingAuthenticationToken("username", "password", "ROLE_USER");
context.setAuthentication(authentication);
SecurityContextHolder.setContext(context);

【示例】访问认证信息

# 认证基本流程

AbstractAuthenticationProcessingFilter 用作验证用户凭据的基本过滤器。 在对凭证进行身份验证之前,Spring Security 通常使用 AuthenticationEntryPoint 请求凭证。

abstractauthenticationprocessingfilter

  • (1)当用户提交其凭据时,AbstractAuthenticationProcessingFilter 从要验证的 HttpServletRequest 创建一个 Authentication。创建的身份验证类型取决于 AbstractAuthenticationProcessingFilter 的子类。例如,UsernamePasswordAuthenticationFilter 根据在 HttpServletRequest 中提交的用户名和密码来创建 UsernamePasswordAuthenticationToken。
  • (2)接下来,将身份验证传递到 AuthenticationManager 进行身份验证。
  • (3)如果身份验证失败,则认证失败
    • 清除 SecurityContextHolder。
    • 调用 RememberMeServices.loginFail。如果没有配置 remember me,则为空。
    • 调用 AuthenticationFailureHandler。
  • (4)如果身份验证成功,则认证成功。
    • 如果是新的登录,则通知 SessionAuthenticationStrategy。
    • 身份验证是在 SecurityContextHolder 上设置的。之后,SecurityContextPersistenceFilter 将 SecurityContext 保存到 HttpSession 中。
    • 调用 RememberMeServices.loginSuccess。如果没有配置 remember me,则为空。
    • ApplicationEventPublisher 发布一个 InteractiveAuthenticationSuccessEvent。

# 用户名/密码认证

读取用户名和密码的方式:

  • 表单
  • 基本认证
  • 数字认证

存储机制

  • 内存
  • JDBC
  • UserDetailsService (opens new window)
  • LDAP

# 表单认证

spring security 支持通过从 html 表单获取登录时提交的用户名、密码。

loginurlauthenticationentrypoint

一旦,登录信息被提交,UsernamePasswordAuthenticationFilter 就会验证用户名和密码。

usernamepasswordauthenticationfilter

# 基本认证

protected void configure(HttpSecurity http) {
    http
        // ...
        .httpBasic(withDefaults());
}

# 内存认证

InMemoryUserDetailsManager 实现了 UserDetailsService (opens new window) ,提供了基本的用户名、密码认证,其认证数据存储在内存中。

@Bean
public UserDetailsService users() {
    // The builder will ensure the passwords are encoded before saving in memory
    UserBuilder users = User.withDefaultPasswordEncoder();
    UserDetails user = users
        .username("user")
        .password("password")
        .roles("USER")
        .build();
    UserDetails user = users
        .username("admin")
        .password("password")
        .roles("USER", "ADMIN")
        .build();
    return new InMemoryUserDetailsManager(user, admin);
}

# JDBC 认证

JdbcUserDetailsManager 实现了 UserDetailsService (opens new window) ,提供了基本的用户名、密码认证,其认证数据存储在关系型数据库中,通过 JDBC 方式访问。

@Bean
UserDetailsManager users(DataSource dataSource) {
    UserDetails user = User.builder()
        .username("user")
        .password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
        .roles("USER")
        .build();
    UserDetails admin = User.builder()
        .username("admin")
        .password("{bcrypt}$2a$10$GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ.0FxO/BTk76klW")
        .roles("USER", "ADMIN")
        .build();
    JdbcUserDetailsManager users = new JdbcUserDetailsManager(dataSource);
    users.createUser()
}

基本的 scheam:

create table users(
    username varchar_ignorecase(50) not null primary key,
    password varchar_ignorecase(50) not null,
    enabled boolean not null
);

create table authorities (
    username varchar_ignorecase(50) not null,
    authority varchar_ignorecase(50) not null,
    constraint fk_authorities_users foreign key(username) references users(username)
);
create unique index ix_auth_username on authorities (username,authority);

# UserDetailsService

UserDetails 由 UserDetailsService 返回。 DaoAuthenticationProvider 验证 UserDetails,然后返回身份验证,该身份验证的主体是已配置的 UserDetailsService 返回的 UserDetails。

DaoAuthenticationProvider 使用 UserDetailsService 检索用户名,密码和其他用于使用用户名和密码进行身份验证的属性。 Spring Security 提供 UserDetailsService 的内存中和 JDBC 实现。

您可以通过将自定义 UserDetailsService 公开为 bean 来定义自定义身份验证。

# PasswordEncoder

Spring Security 的 servlet 支持通过与 PasswordEncoder 集成来安全地存储密码。 可以通过公开一个 PasswordEncoder Bean 来定制 Spring Security 使用的 PasswordEncoder 实现。

daoauthenticationprovider

# Remember-Me

# Spring Boot 集成

@EnableWebSecurity 和 @Configuration 注解一起使用, 注解 WebSecurityConfigurer 类型的类。

或者利用@EnableWebSecurity注解继承 WebSecurityConfigurerAdapter 的类,这样就构成了 Spring Security 的配置。

  • configure(WebSecurity):通过重载该方法,可配置 Spring Security 的 Filter 链。
  • configure(HttpSecurity):通过重载该方法,可配置如何通过拦截器保护请求。

# 参考资料

  • Spring Security Architecture (opens new window)
  • Securing a Web Application (opens new window)
📝 帮助改善此页面! (opens new window)
#Java#框架#安全#SpringSecurity
上次更新: 2024/12/31, 08:02:35
Shiro 快速入门
Netty 快速入门

← Shiro 快速入门 Netty 快速入门→

最近更新
01
Spring Data 综合
02-08
02
Spring 访问 Redis
01-31
03
Spring EL 表达式
01-12
更多文章>
Theme by Vdoing | Copyright © 2019-2025 钝悟(dunwu) | CC-BY-SA-4.0
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×