源于官方最新5.7.2文档,若你觉得官方文档阅读起来很枯燥,内容复杂,我提供了解析概括在每个部分的结尾,我对官方文档的内容做了一些改变,实例代码我会在后续进行更新,请查看如:SpringSecurity系列——认证架构实例代码的文章
但是如果你有能力,还是推荐直接阅读官方文档
简单自定义登录
前面是对官文的翻译以及修改
最后一个解释概括则是对整个自定义密码策略的解释,若你感觉前面的内容难以理解,可以直接看最后一个解释概括
提交用户名和密码后,UsernamePasswordAuthenticationFilter 会验证用户名和密码。 UsernamePasswordAuthenticationFilter 扩展了 AbstractAuthenticationProcessingFilter
当用户提交他们的用户名和密码时,UsernamePasswordAuthenticationFilter 通过从 HttpServletRequest 中提取用户名和密码来创建一个 UsernamePasswordAuthenticationToken,这是一种身份验证。
接下来,将 UsernamePasswordAuthenticationToken 传递给 AuthenticationManager 进行身份验证。 AuthenticationManager 的详细信息取决于用户信息的存储方式。
如果认证失败,则失败
如果认证成功,则为 Success。
默认情况下启用 Spring Security 表单登录。 但是,一旦提供了任何基于 servlet 的配置,就必须明确提供基于表单的登录。 可以在下面找到最小的显式 Java 配置:
public SecurityFilterChain filterChain(HttpSecurity http) {
http
.formLogin(withDefaults());
// ...
}
在此配置中,Spring Security 将呈现默认登录页面。 大多数生产应用程序都需要自定义登录表单。
public SecurityFilterChain filterChain(HttpSecurity http) {
http
.formLogin(form -> form
.loginPage("/login")
.permitAll()
);
// ...
}
Spring Security 的 InMemoryUserDetailsManager 实现 UserDetailsService 以支持存储在内存中的基于用户名/密码的身份验证。 InMemoryUserDetailsManager 通过实现 UserDetailsManager 接口提供对 UserDetails 的管理。 当 Spring Security 配置为接受用户名/密码进行身份验证时,使用基于 UserDetails 的身份验证。
@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 应该只用于“入门”,而不是用于生产
UserBuilder users = 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);
}
.role()
方法Spring Security 的 JdbcDaoImpl 实现 UserDetailsService 以支持使用 JDBC 检索的基于用户名/密码的身份验证。 JdbcUserDetailsManager 扩展了 JdbcDaoImpl 以通过 UserDetailsManager 接口提供对 UserDetails 的管理。当 Spring Security 配置为接受用户名/密码进行身份验证时,使用基于 UserDetails 的身份验证。
在以下部分中,我们将讨论:
看到这里,大家只需要在数据库中使用如下sql生产默认的两张表即可,这里我对官网给出的sql做了一点修改,官网的sql语句是会报错的
create table users(
username varchar(50) not null primary key,
password varchar(500) not null,
enabled boolean not null
);
create table authorities (
username varchar(50) not null,
authority varchar(50) not null,
constraint fk_authorities_users foreign key(username) references users(username)
);
create unique index ix_auth_username on authorities (username,authority);
在我们配置 JdbcUserDetailsManager 之前,我们必须创建一个 DataSource。 在我们的示例中,我们将设置一个使用默认用户模式初始化的嵌入式 DataSource。实际生产环境中不会这样干,而是会使用外部数据源
@Bean
DataSource dataSource() {
return new EmbeddedDatabaseBuilder()
.setType(H2)
.addScript(JdbcDaoImpl.DEFAULT_USER_SCHEMA_DDL_LOCATION)
.build();
}
如下为JdbcUserDetailsManager
@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 返回。 DaoAuthenticationProvider 验证 UserDetails,然后返回一个 Authentication,该 Authentication 的主体是配置的 UserDetailsService 返回的 UserDetails。
DaoAuthenticationProvider 使用 UserDetailsService 来检索用户名、密码和其他属性,以使用用户名和密码进行身份验证。 Spring Security 提供了 UserDetailsService 的内存和 JDBC 实现。
您可以通过将自定义 UserDetailsService 公开为 bean 来定义自定义身份验证。 例如,假设 CustomUserDetailsService 实现 UserDetailsService,以下将自定义身份验证:
这仅在尚未填充 AuthenticationManagerBuilder 且未定义 AuthenticationProviderBean 时使用。
@Bean
CustomUserDetailsService customUserDetailsService() {
return new CustomUserDetailsService();
}
Spring Security 的 servlet 支持通过与 PasswordEncoder 集成来安全地存储密码。 可以通过公开 PasswordEncoder Bean 来自定义 Spring Security 使用的 PasswordEncoder 实现。
DaoAuthenticationProvider是一个 AuthenticationProvider 实现,它利用 UserDetailsService 和 PasswordEncoder 来验证用户名和密码
UsernamePasswordAuthenticationToken
传递给由 ProviderManager 实现的 AuthenticationManager。UsernamePasswordAuthenticationToken
类型,并且具有一个主体,即配置的 UserDetailsService 返回的 UserDetails。 最终,返回的 UsernamePasswordAuthenticationToken
将由身份验证过滤器在 SecurityContextHolder 上设置。/login
地址的默认登录界面UsernamePasswordAuthenticationToken