springboot+security相约去吃饭之前后端分离模式

springboot集成security分为前后端分离模式和前后端不分离模式,下面对目前流行的前后端分离模式进行分析。
目前登录有两个方向,传统的通过session来记录用户认证信息的方式是一种有状态登录,而通过JWT的方式则代表了一种无状态登录。
有状态登录,是指服务端记录每次会话的客户端信息,从而识别客户端身份,根据客户端身份进行请求的处理。如tomcat中的session,用户登录后,用户信息保存在服务端的session中,并给用户一个cookie值,记录对应的session,然后下次请求,用户携带cookie值进行请求(浏览器自动完成),服务端识别对应session进行相应处理。
无状态登录,是指服务端对外提供restful风格的接口,返回访问令牌。如用户发送账号密码到服务端进行登录,认证通过后,服务端将用户信息加密且编码成一个token返回给用户,以后用户每次都携带token进行请求,服务端对token进行验证处理。
使用session的优势在于方便,“第一次约会”即是基于session的方式。但是无法应对前端的多元化趋势,包括Android、ios、公众号、小程序等,因为没有cookie。这个时候像JWT这样的无状态登录就大有用武之地了。
不过话说回来,若是前后端分离模式的场景只是网页+服务端,则没必要上无状态登录,基于session来做就可以,有很方便。
本文对基于session的有状态登录+前后端分离模式进行分析。我们知道spring security默认是表单登录,及传统的前后端不分离模式,所以需要对security进行前后端分离模式的配置。
SecurityConfig配置类

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    @Bean
    protected UserDetailsService userDetailsService() {
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("caocao").password(passwordEncoder().encode("123")).roles("admin").build());
        manager.createUser(User.withUsername("liubei").password(passwordEncoder().encode("123")).roles("user").build());
        manager.createUser(User.withUsername("sunquan").password(passwordEncoder().encode("123")).roles("user").build());
        return manager;
    }

    @Bean
    protected PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests()
                .anyRequest()
                .authenticated()
                .and()
                .formLogin()
                .successHandler(((request, response, authentication) -> {
                    Object principal = authentication.getPrincipal();
                    response.setContentType("application/json;charset=utf-8");
                    PrintWriter printWriter = response.getWriter();
                    printWriter.write(new ObjectMapper().writeValueAsString(principal));
                    printWriter.flush();
                    printWriter.close();
                }))
                .failureHandler(((request, response, exception) -> {
                    response.setContentType("application/json;charset=utf-8");
                    PrintWriter printWriter = response.getWriter();
                    String exceptionMessage = exception.getMessage();
                    if (exception instanceof LockedException) {
                        exceptionMessage = "账户被锁定,请联系管理员!";
                    } else if (exception instanceof CredentialsExpiredException) {
                        exceptionMessage = "密码过期,请联系管理员!";
                    } else if (exception instanceof AccountExpiredException) {
                        exceptionMessage = "账户过期,请联系管理员!";
                    } else if (exception instanceof DisabledException) {
                        exceptionMessage = "账户被禁用,请联系管理员!";
                    } else if (exception instanceof BadCredentialsException) {
                        exceptionMessage = "用户名或者密码输入错误,请重新输入!";
                    }
                    printWriter.write(exceptionMessage);
                    printWriter.flush();
                    printWriter.close();
                }))
                .and()
                .logout()
                .logoutSuccessHandler(((request, response, authentication) -> {
                    response.setContentType("application/json;charset=utf-8");
                    PrintWriter printWriter = response.getWriter();
                    printWriter.write("注销成功");
                    printWriter.flush();
                    printWriter.close();
                }))
                .and()
                .exceptionHandling()
                .authenticationEntryPoint(((request, response, authException) -> {
                    response.setContentType("application/json;charset=utf-8");
                    PrintWriter printWriter = response.getWriter();
                    printWriter.write("尚未登录,请先登录");
                    printWriter.flush();
                    printWriter.close();
                }))
                .and()
                .csrf()
                .disable();
    }
}

在前后端分离模式下,所有的交互都是通过JSON进行通信,无论是登录成功还是失败,或者是未登录及异常。
successHandler,登录成功,服务端就返回一段登录成功的json给前端,前端收到json后,该跳转跳转,该展示展示,由前端自行决定。
failureHandler,登录失败,服务端就返回一段登录失败的json给前端,前端还是自行处理。
logoutSuccessHandler,注销成功场景的处理方式同上。
exceptionHandling,异常场景的处理方式同上。
重写启动项目,通过postman进行请求,相应的返回如下



在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Vue是一种流行的JavaScript框架,用于构建单页面应用程序(SPA)。Spring Boot是一种Java框架,用于构建Web应用程序。 Spring Security是Spring框架的安全性模块,用于提供身份验证和授权功能。WebSocket是一种协议,用于在Web应用程序中实现双向通信。Token则是在用户验证过程中传输的一种凭证。 Vue和Spring Boot的流行度,使得它们是构建现代Web应用程序的理想选择。当应用程序需要安全性和实时性时,Spring Security和WebSocket技术是最佳的选择。在Spring Boot中,使用Spring Security模块可以轻松地添加身份验证,并对请求进行基于角色的访问控制。此外,Spring Security还提供了多种身份验证方案,如基础身份验证和JWT身份验证。 对于实时性,WebSocket提供了一种优雅的解决方案。在Web应用程序中,传统的HTTP请求是一种单向通信模式,即客户端发起请求,服务器响应请求。WebSocket协议通过建立持久连接,允许双向通信。这意味着服务器可以在没有客户端请求的情况下向客户端发送数据,从而实现实时更新。这尤其适用于聊天和数据可视化应用程序。 当使用Vue和Spring Boot构建实时应用时,可以使用WebSocket和Vue的vue-socket.io插件轻松地实现数据传输。Vue-socket.io插件允许将socket.io集成到Vue组件中,以便在应用程序中使用。 当应用程序需要安全性时,可以使用Spring Security的JWT身份验证方案。这需要在服务器端创建一个JWT令牌,并将其发送到客户端。客户端在发送后每次请求时都要将这个令牌包含在请求中。服务器将验证这个令牌,并使用已经验证的用户身份对请求进行授权。 总之,Vue,Spring Boot,Spring Security和WebSocket的结合可以为Web应用程序的安全性和实时性提供完美的解决方案。使用JWT身份验证和Vue-socket.io插件,可以轻松地实现这些功能。无论是聊天应用程序还是数据可视化应用程序,这些技术都可以提高应用程序的用户体验。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值