基于内存验证
首先我们来看看最简单的基于内存的配置,也就是说我们直接以代码的形式配置我们网站的用户和密码,配置方式非常简单,只需要在Security配置类中注册一个Bean即可:
```Plain Text @Configuration @EnableWebSecurity public class SecurityConfiguration {
@Bean //UserDetailsService就是获取用户信息的服务
public UserDetailsService userDetailsService() {
//每一个UserDetails就代表一个用户信息,其中包含用户的用户名和密码以及角色
UserDetails user = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER") //角色目前我们不需要关心,随便写就行,后面会专门讲解
.build();
UserDetails admin = User.withDefaultPasswordEncoder()
.username("admin")
.password("password")
.roles("ADMIN", "USER")
.build();
return new InMemoryUserDetailsManager(user, admin);
//创建一个基于内存的用户信息管理器作为UserDetailsService
}
}
在配置用户信息的时候,可以使用官方提供的BCrypt加密工具:
Java @Configuration @EnableWebSecurity public class SecurityConfiguration {
//这里将BCryptPasswordEncoder直接注册为Bean,Security会自动进行选择
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public UserDetailsService userDetailsService(PasswordEncoder encoder) {
UserDetails user = User
.withUsername("user")
.password(encoder.encode("password")) //这里将密码进行加密后存储
.roles("USER")
.build();
System.out.println(encoder.encode("password")); //一会观察一下加密出来之后的密码长啥样
UserDetails admin = User
.withUsername("admin")
.password(encoder.encode("password")) //这里将密码进行加密后存储
.roles("ADMIN", "USER")
.build();
return new InMemoryUserDetailsManager(user, admin);
}
}
此时会报错403,因为SpringSecurity自带了csrf防护,需求我们在POST请求中携带页面中的csrfToken才可以,否则一律进行拦截操作,这里我们可以将其嵌入到页面中,随便找一个地方添加以下内容:
Plain Text
接着在axios发起请求时,携带这个input的value值:
Plain Text function pay() { const account = document.getElementById("account").value const csrf = document.getElementById("_csrf").value axios.post('/mvc/pay', { account: account, _csrf: csrf //携带此信息即可,否则会被拦截 }, { …
---
## 基于数据库验证
官方默认提供了可以直接使用的用户和权限表设计,根本不需要我们来建表,直接在Navicat中执行以下查询:
Plain Text 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 fkauthoritiesusers foreign key(username) references users(username)); create unique index ixauthusername on authorities (username,authority);
配置类中设置数据源和加密:
Java @Configuration @EnableWebSecurity public class SecurityConfiguration {
@Bean PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public DataSource dataSource(){
//数据源配置
return new PooledDataSource("com.mysql.cj.jdbc.Driver",
"jdbc:mysql://localhost:3306/test", "root", "123456");
}
@Bean
public UserDetailsService userDetailsService(DataSource dataSource,
PasswordEncoder encoder) {
JdbcUserDetailsManager manager = new JdbcUserDetailsManager(dataSource);
//仅首次启动时创建一个新的用户用于测试,后续无需创建
manager.createUser(User.withUsername("user")
.password(encoder.encode("password")).roles("USER").build());
return manager;
}
}
---
## 自定义验证
既然需要自定义,那么我们就需要自行实现UserDetailsService或是功能更完善的UserDetailsManager接口,这里为了简单,我们直接选择前者进行实现:
Java @Service public class AuthorizeService implements UserDetailsService {
@Resource
UserMapper mapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Account account = mapper.findUserByName(username);
if(account == null)
throw new UsernameNotFoundException("用户名或密码错误");
return User
.withUsername(username)
.password(account.getPassword())
.build();
}
} ```
其他配置
自定义登陆界面
在编写项目过程中发现有302的情况,一定要先检查是否因为没有放行导致被SpringSecurity给拦截了。
记住我功能
也就是说我们可以在登陆之后的一段时间内,无需再次输入账号和密码进行登陆,相当于服务端已经记住当前用户,再次访问时就可以免登陆进入,这是一个非常常用的功能。