SpringSecurity成功、失败和异常处理

前面文章分别分析了SprignSecurity的执行流程和源码,也分析了一遍我要实现分布式系统使用Security认证的思路和问题。这篇文章主要是说明security认证失败后,要如何处理。
之前说过实现Security安全认证其实方式很多,大家从网络上能看到的例子也很多,实现的方法也各不相同。有重写UsernamePasswordAuthenticationFilter过滤器的,也有不重写的,也有自定义controller登录接口的。但其实万变不离其宗,你终归要用到Security提供的各种过滤器和类。

1.成功和失败处理

1.1.源码分析

我们按照重写UsernamePasswordAuthenticationFilter过滤器的思路看源码就可以把几种方式都看清。
如果你重写,那有一个核心工作你肯定会做,那就是重写attemptAuthentication,获取到前端提交的用户名密码后,封装成UsernamePasswordAuthenticationToken对象,调用AuthenticationManager的‘authenticate’方法。逻辑大概就是这个样子吧。
在这里插入图片描述

代码上半部分是做了一下表单提交和json提交数据的兼容,确保两种方式都可以拿到前端请求来的用户名和密码。
那谁调用的这个方法呢?

那谁调用这个attemptAuthentication呢?
在这里插入图片描述
点进去看只有一个地方AbstractAuthenticationProcessingFilter,看他的源码一眼就能明白。源码有省略,为了看得直白点。

try {
			authResult = attemptAuthentication(request, response);
		}
		catch (InternalAuthenticationServiceException failed) {
			unsuccessfulAuthentication(request, response, failed);
			return;
		}
		catch (AuthenticationException failed) {
			// Authentication failed
			unsuccessfulAuthentication(request, response, failed);
			return;
		}
		// Authentication success
		successfulAuthentication(request, response, chain, authResult);

unsuccessfulAuthenticationsuccessfulAuthentication是不是很显眼,看名字就能看懂,处理失败的和处理成功的。

成功的处理

我们看这个类里面自己的处理逻辑:

  1. 向上下文中保存了用户信息;
  2. 推送了认证成功的事件;
  3. 最后调用了seccessHandler处理。

在这里插入图片描述

失败的处理

也看这个类里里面自己的处理逻辑:

  1. 清除上下文信息;
  2. 最后调用了failureHandler处理。

在这里插入图片描述
所以现在大家知道有哪些方式了吧?不卖关子直接说:

  1. 在你重写的过滤器里面,重写successfulAuthenticationunsuccessfulAuthentication两个方法;
    在这里插入图片描述

  2. 定义一个处理器类实现AuthenticationSuccessHandler,重写onAuthenticationSuccess方法;定义一个处理器类实现AuthenticationFailureHandler,重写onAuthenticationFailure方法,分别处理认证成功和失败的逻辑。
    在这里插入图片描述

1.2.区别

第一种方法,只有在你重写过滤器的时候才能用,因为这两个方法属于这个过滤器,不重写过滤器咋玩嘛。
第二种方法,重写或者没有重写过滤器都可以用,他们是Security的配置类中的属性,你只要在Security配置里面配置了就生效

2. 第三种失败和异常处理

除此之外还有一个方法可以处理失败和异常,那就是自定义实现AuthenticationEntryPoint类,重写commence.方法
AuthenticationEntryPoint类里面我们可以看到调用这个方法的有一个非常熟悉的handler类,名字也是failure,进去看一下。
在这里插入图片描述
这个类实现了AuthenticationFailureHandler,而我自定义的失败处理器EdenLoginFailureHandler,也是实现的这个类。
在这里插入图片描述
失败的处理方法onAuthenticationFailure里面调用了AuthenticationEntryPointcommence方法。
在这里插入图片描述
由此我们得出结论,如果我不使用前两种方式去处理失败的异常,那么自定义实现AuthenticationEntryPoint类,重写commence.方法也是完全可以实现的。而且方法的入参和前面两种都一样,HttpServletRequest , HttpServletResponse , AuthenticationException 都有,我们利用response向前端返回响应就可以了。
大概示例就是这样吧,大家根据自己情况,自由发挥就行。

    @Override
    public void commence(HttpServletRequest httpServletRequest,
                         HttpServletResponse httpServletResponse,
                         AuthenticationException failed) throws IOException, ServletException {
        httpServletResponse.setContentType("application/json;charset=utf-8");
        PrintWriter writer = httpServletResponse.getWriter();
        R r = R.failed();
        if (failed instanceof InsufficientAuthenticationException) {
            r.setMsg("请先登录~~");
        } else if (failed instanceof BadCredentialsException) {
            r.setMsg("用户名或密码错误");
        } else {
            r.setMsg("用户认证失败,请检查后重试");
        }
        writer.write(new ObjectMapper().writeValueAsString(r));
        writer.flush();
        writer.close();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值