SpringSecurity在前后端分离项目中的实践(1

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 接口

001.png

登录认证失败

002.png

登录认证成功

003.png

登录认证成功后再次访问 /user/detail 接口

004.png

3 问题总结

综合全文,目前还存在的疑问和待解决的问题包括:
1)Spring Security 在前后端分离设计下如何设计相关接口?验证成功后“跳转”到指定接口是否合理,验证失败后“跳转”到特定认证失败接口的设计是否合理?不合理该如何设计?合理的话对应接口的设计应该注意些什么?
2)Spring Security 是如何获取提交的表单字段的?本示例代码对于表单中的请求字段不为或不存在 username 和 password 抛出的异常没有进行处理,会“跳转”到上述特定认证失败接口。

如果有对 Spring Security 了解的小伙伴,希望不吝赐教,留言解答我的疑惑,不胜感激!

4 Demo 地址

gitee.com/itschenxian…