一:前言
(1)Spring Security概念:
Spring Security 是属于 Spring 生态下一个功能强大且高度可定制的认证和授权框架,它不仅限于 Web 应用程序的安全性,也可以用于保护任何类型的应用程序。
(2)场景描述:
当前端请求 /login 接口,后端并没有对登录接口有@PostMapping("/login")的注解,且框架中有使用Spring Security当做权限校验框架。原因是Spring Security有自动处理解析 /login 接口功能
二:思路整理分析
(1)官方文档
在Spring Security默认帮我们处理了登录、登出等接口
文档地址:表单登录 :: Spring Security
(2)主要思路:
①前端请求 POST /login,浏览器将请求重定向到登录页面
②Spring Security 的 UsernamePasswordAuthenticationFilter 拦截,然后提取username 和 password
③调用配置的 UserDetailsService 实例的 loadUserByUsername(username)
④如果返回 UserDetails,继续密码比对(PasswordEncoder)
⑤成功 → 认证成功,生成 SecurityContext,失败 → 抛出异常(如 UsernameNotFoundException)
三:步骤实现
(1)关键配置
代码参考如下:
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/login").permitAll()
.anyRequest().authenticated()
)
.formLogin(Customizer.withDefaults()) // 使用默认表单登录
.csrf().disable(); // 为了测试方便关掉 CSRF(生产不建议)
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
return new CustomUserDetailsService(); // 自定义实现
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
(2)继承实现UserDetailsService 接口,重写loadUserByUsername(String username)方法
代码如下:(在此方法中可以执行需要的逻辑)
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 查询数据库...
if (user == null) throw new UsernameNotFoundException("用户不存在");
return new User(user.getUsername(), user.getPassword(), getAuthorities());
}
}
(3)登录完成之后处理(成功、失败、异常)
以上是我配置的参数
官网文档:身份验证事件 :: Spring Security
根据返回的信息,分别处理不同的事件
四:总结
使用Spring Security 框架,可以不需要写 Controller层的 /login,Spring Security 自动帮我们处理了很多的安全校验,希望能够帮助其他小伙伴看懂这个逻辑