1 概述
如今,前后端分离(开发)已经非常常见了。由于任务需要,要在基于 Spring Boot 的 Web 项目中集成 Spring Security 完成用户模块的登录和认证等功能,但是在网上查阅的(中文)资料中,对前后端完全分离如何配置 Spring Security 都描述的不是很清楚,而这篇文章也是自己对前后端分离配置 Spring Security 的探究。
2 实践
2.1 版本
基于 SpringBoot 2.1.8.RELEASE,基于起步依赖 spring-boot-starter-security (Spring Security 5)
2.2 Spring Security 相关配置
用户认证:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception{
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
复制代码
对应的 userDetailsService 实现:
@Component("myUserDetailsService")
public class MyUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// 这里设计为任何密码为 123456 的用户都可以通过验证
String password = new BCryptPasswordEncoder().encode("123456");
User user = new User(username, password,
AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
return user;
}
}
复制代码
HttpSecurity 相关配置:
@Override
protected void configure(HttpSecurity http) throws Exception{
//未登录时访问 Security 保护的接口
http.httpBasic().authenticationEntryPoint(new AuthenticationEntryPoint(){
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.setContentType("application/json;charset=UTF-8");
response.getWriter().append(new ObjectMapper().writeValueAsString(Response.createByError("未登录")));
}
});
http.authorizeRequests()
.antMatchers("/user/login").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginProcessingUrl("/user/login")
.successForwardUrl("/user/login") // 登录成功后的“跳转”接口
.failureForwardUrl("/user/loginfail") //登录失败后的“跳转”接口
.and().csrf().disable();
}
复制代码
这里是有关对 Spring Security 在前后端分离的核心疑问:前后端分离设计下,在 Spring Security 认证成功后跳转到登录接口是否是合理的设计,认证失败时跳转到指定接口是否合理。
下面是相关控制器的实现:
// 能访问到 login 接口都是登录成功,在逻辑功能上是合理的,但是不知道设计上是否合理,是否存在 BUG?
@RequestMapping(value = "/login",method = RequestMethod.POST)
public Response login(){
return Response.createByError("登陆成功");
}
@RequestMapping(value = "/detail",method = RequestMethod.POST)
public Response getDetail(){
Map<String,String> map = new HashMap<>();
map.put("username","chen");
map.put("password","******");
return Response.createBySuccessWithData(map);
}
// 为登录失败设计一个接口是否合理?
@RequestMapping(value = "/loginfail",method = RequestMethod.POST)
public Response loginFail(){
return Response.createByError("用户名或密码错误");
}
复制代码
2.3 测试
完成相关代码,启动程序,使用 postman 进行接口访问的简单测试:
未登录访问 /user/detail 接口
登录认证失败
登录认证成功
登录认证成功后再次访问 /user/detail 接口
3 问题总结
综合全文,目前还存在的疑问和待解决的问题包括:
1)Spring Security 在前后端分离设计下如何设计相关接口?验证成功后“跳转”到指定接口是否合理,验证失败后“跳转”到特定认证失败接口的设计是否合理?不合理该如何设计?合理的话对应接口的设计应该注意些什么?
2)Spring Security 是如何获取提交的表单字段的?本示例代码对于表单中的请求字段不为或不存在 username 和 password 抛出的异常没有进行处理,会“跳转”到上述特定认证失败接口。
如果有对 Spring Security 了解的小伙伴,希望不吝赐教,留言解答我的疑惑,不胜感激!




近期评论