👉 请投票支持这款 全新设计的脚手架 ,让 Java 再次伟大!
前言
既然 Spring securtiy 的核心是 Filter chains,那我们只需要定义一个符合 security 标准的 filter ,再把自己的 chain 加入到 VirtualFilterChain 里面,就可以自定义身份验证的认证逻辑了。
之前提到过,大部分身份认证相关的过滤器都继承了 AbstractAuthenticationProcessingFilter。但是这一次我们让接下来的自定义过滤器不选择继承它,而是继承 OncePerRequestFilter。
这个类之前我们没有见过,其实它也是 security 框架提供的一个 VirtualFilter 父类。继承一个陌生的类听起来有点吓人,不过很快你就知道 AbstractAuthenticationProcessingFilter 也好,OncePerRequestFilter 也罢,都是 filter 而已。
自定义一个 Filter
我们参照 security 的基础身份认证过滤器 UsernamePasswordAuthenticationFilter 来编写我们的过滤器。这是不是意味着我们也必须使用模板设计模式来编写自定义过滤器的父类,然后聚合 providerManager 再自定义 provider 实现一整套 security 范式的身份认证代码?
不是的,你完全可以把 provider 的逻辑全部抽离出来加入到你的自定义过滤器里面。实际上我的过滤器一共就三个逻辑。非常简单并且可以工作的很好!
- 通过确认 token 的有效性来验证请求的身份。类似于 DaoAuthenticationProvider.additionalAuthenticationChecks。
- 从数据库检索出用户的详情,方便后续取用。类似于 DaoAuthenticationProvider. retrieveUser()。
- 将验证通过的身份资产(principal)封装到 UsernamePasswordAuthenticationToken,并设置到 security context。类似于 AbstractAuthenticationProcessingFilter.successfulAuthentication。
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain)
throws ServletException, IOException {
String header = request.getHeader(HttpHeaders.AUTHORIZATION);
if (StringUtils.isEmpty(header) || !header.startsWith(BEARER_SPACE)) {
globalExceptionHandler.commence(request, response, new AuthenticationException("非法的 token 请求参数") {
});
return;
}
String token = header.split(" ")[1].trim();
try {
TokenUtil.verifyToken(token, base64Secret);
} catch (FoundationAppException e) {
globalExceptionHandler.commence(request, response, new AuthenticationException("非法的 token"