Spring Security 前后端分离实现登录6

Spring Security 前后端分离实现登录

前后端分离的数据交互

在前后端分离这样的开发架构下,前后端的交互都是通过 JSON 来进行,无论登录成功还是失败,后端只返回json,不做页面跳转。页面跳转是前端的事情。

登录成功了,服务端就返回一段登录成功的提示 JSON 给前端,前端收到之后,由前端自己决定页面跳转,和后端没有关系了。

登录失败了,服务端就返回一段登录失败的提示 JSON 给前端,前端收到之后,由前端自己决定页面跳转,和后端没有关系了。

登录成功

之前我们配置登录成功的处理是通过如下两个方法来配置的:

  • defaultSuccessUrl
  • successForwardUrl

这两个都是配置跳转地址的,适用于前后端不分的开发。除了这两个方法之外,还有一个必杀技,那就是 successHandler。

successHandler 的功能十分强大,甚至已经囊括了 defaultSuccessUrl 和 successForwardUrl 的功能。我们来看一下:

 .successHandler(new AuthenticationSuccessHandler() {
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,Authentication authentication) throws IOException,ServletException {
                        response.setContentType("application/json;charset=utf-8");
                        PrintWriter out = response.getWriter();
                        out.write(new ObjectMapper().writeValueAsString(authentication.getPrincipal()));
                        out.flush();
                        out.close();
                    }
                })

successHandler 方法的参数是一个 AuthenticationSuccessHandler 对象,这个对象要我们实现onAuthenticationSuccess方法

onAuthenticationSuccess 方法有三个参数,分别是:

  • HttpServletRequest:利用 HttpServletRequest 我们可以做服务端跳转,
  • HttpServletResponse:利用 HttpServletResponse 我们可以做客户端跳转,当然,也可以返回 JSON 数据。
  • Authentication:Authentication 参数保存了我们刚刚登录成功的用户信息。

配置完成后,我们再去登录,就可以看到登录成功的用户信息通过 JSON 返回到前端了,如下:

from01

登录失败也有一个类似的回调,如下:

                .failureHandler(new AuthenticationFailureHandler() {
                    @Override
                    public void onAuthenticationFailure(HttpServletRequest httpServletRequest,
                                                        HttpServletResponse httpServletResponse,
                                                        AuthenticationException e) throws IOException, ServletException {
                        httpServletResponse.setContentType("application/json;charset=utf-8");
                        PrintWriter out = httpServletResponse.getWriter();
                        out.write(new ObjectMapper().writeValueAsString(e.getMessage()));
                        out.flush();
                        out.close();
                    }
                })

失败的回调也是三个参数,前两个就不用说了,第三个是一个 Exception,对于登录失败,会有不同的原因,Exception 中则保存了登录失败的原因,我们可以将之通过 JSON 返回到前端。

启动项目,用postman访问登录接口,故意输错用户名,或密码。无论是用户名还是密码错误都返回如下结果:

from02

当然大家也可以根据不同的异常类型,我们可以给用户一个更加明确的提示:

resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
RespBean respBean = RespBean.error(e.getMessage());
if (e instanceof LockedException) {
    respBean.setMsg("账户被锁定,请联系管理员!");
} else if (e instanceof CredentialsExpiredException) {
    respBean.setMsg("密码过期,请联系管理员!");
} else if (e instanceof AccountExpiredException) {
    respBean.setMsg("账户过期,请联系管理员!");
} else if (e instanceof DisabledException) {
    respBean.setMsg("账户被禁用,请联系管理员!");
} else if (e instanceof BadCredentialsException) {
    respBean.setMsg("用户名或者密码输入错误,请重新输入!");
}
out.write(new ObjectMapper().writeValueAsString(respBean));
out.flush();
out.close();

这里有一个需要注意的点。当用户登录时,用户名或者密码输入错误,我们一般只给一个模糊的提示,即用户名或者密码输入错误,请重新输入,而不会给一个明确的诸如“用户名输入错误”或“密码输入错误”这样精确的提示,这会给系统带来风险。

3. 未认证处理方案

那未认证又怎么办呢?系统默认的行为是直接重定向到登录页面。

但是在前后端分离中,这个逻辑明显是有问题的,如果用户没有登录就访问一个需要认证后才能访问的页面,这个时候,我们不应该让用户重定向到登录页面,而是给用户一个尚未登录的提示,前端收到提示之后,再自行决定页面跳转。

具体配置如下:

 .exceptionHandling().authenticationEntryPoint(new AuthenticationEntryPoint() {
            @Override
            public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                                 AuthenticationException e) throws IOException, ServletException {
        httpServletResponse.setContentType("application/json;charset=utf-8");
                PrintWriter out = httpServletResponse.getWriter();
                out.write(new ObjectMapper().writeValueAsString("尚未登录,请先登录"));
                out.flush();
                out.close();
            }
        });

在 Spring Security 的配置中加上自定义的 AuthenticationEntryPoint 处理方法,该方法中直接返回相应的 JSON 提示即可。这样,如果用户再去直接访问一个需要认证之后才可以访问的请求,就不会发生重定向操作了,服务端会直接给浏览器一个 JSON 提示,浏览器收到 JSON 之后,该干嘛干嘛。

运行结果:

from03

4. 注销登录

注销登录之后,系统自动跳转到登录页面,这也是不合适的,如果是前后端分离项目,注销登录成功后返回 JSON 即可,配置如下:

                .logout()
                .logoutUrl("/logout")
                .logoutSuccessHandler(new LogoutSuccessHandler() {
                    @Override
                    public void onLogoutSuccess(HttpServletRequest httpServletRequest,
                                                HttpServletResponse httpServletResponse,
                                                Authentication authentication) throws IOException, ServletException {
                        httpServletResponse.setContentType("application/json;charset=utf-8");
                        PrintWriter out = httpServletResponse.getWriter();
                        out.write(new ObjectMapper().writeValueAsString("注销成功"));
                        out.flush();
                        out.close();
                    }
                })
                .permitAll()

这样,注销成功之后,前端收到的也是 JSON 了:

from04

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值