在代码里,我们没有认证或者授权的filter。认证和授权的工作现在基本上完全由Spring Security的过滤器接管了。
本节就来看下 如何在Spring Security的过滤器链上加入我们自己的逻辑,因为现在这个过滤器链上只处理了认证和授权。我们还有其他的一些安全机制,比如说限流、日志。我们看下怎么把这些机制加到Spring的默认实现里面去,最后总结一下,到底都做了哪些事情,然后整个它的处理流程是什么样子的
日志
首先来写处理日志的过滤器。和我们之前的处理是类似的。
继承OncePerRequestFilter
这里一定注意不要用@Component注解把这个Filter声明成Spring 的Bean原因下面再讲。
日志的这个过滤器应该是在认证的过滤器前面,在授权的过滤器前面。所以在这个过滤器里面,我应该知道当前用户是谁了。如果你的认证成功的话。
前面认证的过滤器会把jwt的令牌转换成一个Authentication,然后把它放到SpringSecurityContext安全的上下文里面。
通过下面的代码就可以把它从安全上下文里面再拿出来。principal就是我们申请令牌的时候的用户名。
调用后面的过滤器处理完之后,还要再加一句日志更新,日志的成功还是失败,更新到数据库里面。这里我简单的用一个sysout来处理。把日志更新成处理成功。
过滤器加到SpringSecurity配置中
http的安全配置这里加一行。第一个addFilter一般不会去用.
addFilterAfter、addFilterAt、addFilterBefore 就是你自己写的过滤器加到SpringSecurity的过滤器链上,指定一个位置。SpringSecurity过滤器链的顺序是固定的。所以你只要把你的过滤器加到spring的某一个过滤器的前面before或 后面after,at就是直接加入到这个过滤器的位置上。替换掉原来的过滤器。
我们加的是一个日志过滤器,要加载授权的前面。用addFilterBefore
前面是自己定义的过滤器,后面那个过滤器ExceptionTranslationFilter是Spring 用来转换异常的一个过滤器。我们最后会在授权的过滤器里面抛出异常。要不然是401需要身份认证,要不然是403需要权限。就这两种异常。两个异常抛出来以后,都会由这个过滤器来处理。
刚才我们说不要把自己定义的GatewayAuditLogFilter声明称一个spring的Bean。SprintBoot默认情况下(如果声明成了Spring的Bean) ,会把这个过滤器直接加到web程序的过滤器链上。因为这个类继承了OncePreRequestFilter
后面这里还有一个addFilter的操作。也就是说SpringBoot加了一次,自己这里写代码又加了一次。这个过滤器加入到过滤器的链上,加了两次。所以我们这里不声明称Spring成的Bean。这里只用代码加到链上一次。
启动测试
首先是 认证服务器
网关
订单。
申请令牌
复制令牌
去调用创建订单的服务。
看一下 网关上的日志。说明进入了日志的过滤器里面。jojo是jwt内解析的用户名, 这说明日志是在认证的过滤器后面的。所以才会解析出当前的用户。
第二句是在验证权限的服务,这里打印出来的。这就说明了日志过滤器在认证的过滤器之后,权限的过滤器之前生效的。
在权限的过滤器判断完成后,最终还会回到日志的过滤器里面,把它的处理结果更新成处理成功。这个是我们想要的执行的顺序。
异常处理
多发几次创建订单的请求,因为是50%的成功率
403访问被拒绝。
这里并没有体现出来,请求是被拒绝掉的、现在的处理代码并没有处理这种情况,仍然是回到了日志Filter里面,把我的日志更新成功了。
这个就是访问被拒绝 ,它的处理器
默认的处理器就是返回下面这样的json
我们可以自己定义自己的访问拒绝的处理器。在这个处理器里面我们可以记录日志,也可以自定义返回去的这个错误。这里只是针对没有权限403这种情况的一个处理。
还有另外一种情况401,一会再说。
我们要写的就是AccessDeniedHandler这个接口的实现。
自定义错误处理handler
直接继承一个父类。
OAuth2AccessDeniedHandler是个默认的实现,如果不在网关的这里配置accessDeniedHandler这个配置的话。
默认用的就是这个 OAuth2AccessDeniedHandler。在这里处理器里面,它会把异常 转换成一个简单的json也就是我们看到页面返回的403的json
声明称Spring的Bean。然后覆盖handler方法。
在这里能拿到request、response、抛出的exception。
可以通过操作response,写你想写的错误信息。
这里我们就加一句输出
注入我们自己写的错误处理器
这样在抛出403的错误异常的时候,我的控制台就会输出。
重启网关服务。测试
日志的过滤器里面又update了一次。更新为成功了。我们想要的是 如果报错了 就不再更新日志为成功
最简单的做法是在request里面设置一个attributes。value值随便定义。
attribute的值为空 就走更新成功。也就是没有抛出403的错误。
重启网关服务