1. Spring Security快速入门

Filter是由Servlet容器加上FilterChain进行管理的,然后SpringSecurity是通过在FilterChain中注册一个Filter的代理对象,然后,再到Spring容器中定义SpringSecurity的FilterChain, 这些spring容器中的FilterChain是通过再Servlet中定义的Filter代理对象进行管理的。
1.1 DefaultSecurityFilterChain
SpringSecurity默认的SecurityFilterChain
1.2 SecurityProperties
定义默认配置
2. Spring Security自定义配置
2.1 创建自定义配置
UserDetailsService 用来管理用户信息, InMemoryUserDetailManager是UserDetailsService的一个实现,用来管理内存的用户信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Configuration
public class SecurityConfig {
@Bean public UserDetailsService userDetailsService() {
InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); manager.createUser(User.withDefaultPasswordEncoder().username("user").password("password").roles("USER").build()); return manager; }
}
|
基于内存的用户认证流程
- 程序启动时
- 创建
InMemoryUserDetailsManager对象
- 创建User对象,封装用户名和密码
- 使用
InMemoryUserDetailsManager将User对象存入内存
- 校验用户时
- SpringSecurity自动使用
InMemoryUserDetailsManager的loadUserByUserName方法从内存中获取User对象
- 在
UsernamePasswordAuthenticationFilter过滤器中的attemptAuthentication方法中将用户输入的用户密码和从内存中获取到的用户信息进行比较,进行用户认证
2.2 基于数据库数据源的用户认证
- 程序启动时
- 创建
DBUserDetailsManager对象, 实现 UserDetailsManager, UserDetailsPasswordService
- 校验用户时
- SpringSecurity自动使用
DBUserDetailsManager的loadUserByUserName方法从数据库中获取User对象
- 在UsernamePasswordAuthenticationFilter过滤器中的attemptAuthentication方法中将用户输入的用户密码和从数据库中获取到的用户信息进行比较,进行用户认证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
| @Component public class DBUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService {
@Resource private UserDao userDao;
@Override public UserDetails updatePassword(UserDetails user, String newPassword) { return null; }
@Override public void createUser(UserDetails user) { User newUser = new User(); newUser.setUsername(user.getUsername()); newUser.setPassword(user.getPassword()); newUser.setEnabled(true);
userDao.insert(newUser);
}
@Override public void updateUser(UserDetails user) {
}
@Override public void deleteUser(String username) {
}
@Override public void changePassword(String oldPassword, String newPassword) {
}
@Override public boolean userExists(String username) { return false; }
@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { QueryWrapper<User> userQueryWrapper = new QueryWrapper<>(); userQueryWrapper.eq("username",username); User user = userDao.selectOne(userQueryWrapper); if(user == null) { throw new UsernameNotFoundException(username); }else { Collection<GrantedAuthority> grantedAuthorities = new ArrayList<>(); return new org.springframework.security.core.userdetails.User( user.getUsername(), user.getPassword(), user.getEnabled(), true, true, true, grantedAuthorities); } } }
|
3. 前后端分离
3.2 跨域问题解决
需要对开启一些接口的跨域访问
通过实现 WebMvcConfigurer接口统一配置,避免在每个Controller重复注解
1 2 3 4 5 6 7 8 9 10 11 12
| @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("https://prod.example.com") .allowedMethods("GET", "POST", "PUT") .allowedHeaders("Content-Type", "Authorization") .allowCredentials(true) .maxAge(3600); } }
|
4. 身份认证
5. 授权
6. OAuth2