0
点赞
收藏
分享

微信扫一扫

Password 存储机制

In-Memory Authentication

Spring Security 的 InMemoryUserDetailsManager 实现了 UserDetailsService,以支持存储在内存中的基于用户名/密码的身份验证。InMemoryUserDetailsManager 通过实现 UserDetailsManager 接口提供对 UserDetails 的管理。当 Spring Security 配置为接受用户名/密码进行身份验证时,它使用基于 UserDetails 的身份验证。

在这个示例中,我们使用 Spring Boot CLI 对 password 密码进行编码,并获得编码密码{ bcrypt } $2a $GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ. 0 FxO/BTk76klW。

@Bean
public UserDetailsService users() {
	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();
	return new InMemoryUserDetailsManager(user, admin);
}

上面的示例以安全的格式存储密码,但是在入门体验方面还有很多需要改进的地方

在下面的示例中,我们使用 User.withDefaultPasswordEncoder 来确保存储在内存中的密码受到保护。但是,它不能通过反编译源代码来防止获得密码。因此,User.withDefaultPasswordEncoder 只能用于“入门”,不能用于生产。

@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 admin = users
		.username("admin")
		.password("password")
		.roles("USER", "ADMIN")
		.build();
	return new InMemoryUserDetailsManager(user, admin);
}

在基于 XML 的配置中使用 User.withDefaultPasswordEncoder 没有简单的方法。对于演示或刚刚开始使用,您可以选择在密码前面加上{ noop }的前缀,以表明不应该使用编码。

<user-service>
	<user name="user"
		password="{noop}password"
		authorities="ROLE_USER" />
	<user name="admin"
		password="{noop}password"
		authorities="ROLE_USER,ROLE_ADMIN" />
</user-service>

JDBC Authentication

Spring Security 的 JdbcDaoImpl 实现了 UserDetailsService,以支持使用 JDBC 检索的基于用户名/密码的身份验证。JdbcUserDetailsManager 扩展了 JdbcDaoImpl,通过 UserDetailsManager 接口提供对 UserDetails 的管理。当 Spring Security 配置为接受用户名/密码进行身份验证时,它使用基于 UserDetails 的身份验证。

Default Schema

Spring Security 为基于 JDBC 的身份验证提供默认查询。本节提供与默认查询一起使用的相应默认模式。您将需要调整模式以匹配所使用的查询和数据库方言的任何自定义。

User Schema

JdbcDaoImpl 需要表来为用户加载密码、帐户状态(启用或禁用)和权限(角色)列表。下面可以找到所需的默认模式。

create table users(
	username varchar_ignorecase(50) not null primary key,
	password varchar_ignorecase(500) 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);

Oracle 是一个流行的数据库选择,但是需要稍微不同的模式。您可以在下面找到用户的默认 Oracle Schema。

CREATE TABLE USERS (
    USERNAME NVARCHAR2(128) PRIMARY KEY,
    PASSWORD NVARCHAR2(128) NOT NULL,
    ENABLED CHAR(1) CHECK (ENABLED IN ('Y','N') ) NOT NULL
);

CREATE TABLE AUTHORITIES (
    USERNAME NVARCHAR2(128) NOT NULL,
    AUTHORITY NVARCHAR2(128) NOT NULL
);
ALTER TABLE AUTHORITIES ADD CONSTRAINT AUTHORITIES_UNIQUE UNIQUE (USERNAME, AUTHORITY);
ALTER TABLE AUTHORITIES ADD CONSTRAINT AUTHORITIES_FK1 FOREIGN KEY (USERNAME) REFERENCES USERS (USERNAME) ENABLE;

Group Schema

如果您的应用程序正在利用组,则需要提供组模式。组的默认模式可以在下面找到。

create table groups (
	id bigint generated by default as identity(start with 0) primary key,
	group_name varchar_ignorecase(50) not null
);

create table group_authorities (
	group_id bigint not null,
	authority varchar(50) not null,
	constraint fk_group_authorities_group foreign key(group_id) references groups(id)
);

create table group_members (
	id bigint generated by default as identity(start with 0) primary key,
	username varchar(50) not null,
	group_id bigint not null,
	constraint fk_group_members_group foreign key(group_id) references groups(id)
);

Setting up a DataSource

在配置 JdbcUserDetailsManager 之前,我们必须创建一个 DataSource。在我们的示例中,我们将设置一个使用默认用户模式初始化的嵌入式 DataSource。

@Bean
DataSource dataSource() {
	return new EmbeddedDatabaseBuilder()
		.setType(H2)
		.addScript("classpath:org/springframework/security/core/userdetails/jdbc/users.ddl")
		.build();
}

在生产环境中,您需要确保建立到外部数据库的连接。

JdbcUserDetailsManager Bean

在这个示例中,我们使用 Spring Boot CLI 对 password 密码进行编码,并获得编码密码{ bcrypt } $2a $GRLdNijSQMUvl/au9ofL.eDwmoohzzS7.rmNSJZ. 0 FxO/BTk76klW。有关如何存储密码的详细信息,请参阅 PasswordEncoder 部分。

@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(user);
	users.createUser(admin);
	return users;
}

UserDetails

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

UserDetailsService

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

可以通过将自定义 UserDetailsService 公开为 bean 来定义自定义身份验证。例如,假设 CustomUserDetailsService 实现 UserDetailsService,下面将自定义身份验证:

@Bean
CustomUserDetailsService customUserDetailsService() {
	return new CustomUserDetailsService();
}

PasswordEncoder

Spring Security的 Servlet 通过与 PasswordEncode 集成,支持安全地存储密码。定制Spring Security使用的PasswordEncode 实现可以通过公开 PasswordEncoderBean 来完成。

DaoAuthenticationProvider

DaoAuthenticationProvider 是一个 AuthenticationProvider 实现,它利用 UserDetailsService 和 PasswordEncoder 来对用户名和密码进行身份验证。
让我们来看看在 Spring Security 中 DaoAuthenticationProvider 是如何工作的。这个图解释了身份验证管理器如何工作的详细信息,见 用户名/密码认证。
在这里插入图片描述

  1. 通过读取 Username & Password 的身份验证过滤器将一个 UsernamePasswordAuthenticationToken 传递给 AuthenticationManager,后者由 ProviderManager 实现。
  2. ProviderManager 被配置为使用 DaoAuthenticationProvider 类型的 AuthenticationProvider。
  3. DaoAuthenticationProvider 从 UserDetailsService 查找 UserDetails。
  4. 然后,DaoAuthenticationProvider 使用 PasswordEncoder 验证前一步中返回的 UserDetails 上的密码。
  5. 身份验证成功后,返回的身份验证类型为 UsernamePasswordAuthenticationToken,其主体为已配置的 UserDetailsService 返回的 UserDetails。最终,身份验证筛选器将在 SecurityContextHolder 上设置返回的 UsernamePasswordAuthenticationToken。

参考 SpringSecurity 官方文档

举报

相关推荐

0 条评论