springbootspringsecurity

Spring Security-整合Spring Boot(分布

2022-05-18  本文已影响0人  石头耳东

前言:本文作为Spring Security-整合Spring Boot(分布式)-篇章一,主要是为了后面的具体代码篇章做铺垫。JWT、RSA,以及框架内业务逻辑代码是需要提前了解的,这些内容是合理使用Spring Security的关键。

零、本文纲要

一、 系统安全

  1. JWT
  2. RSA非对称加密
    二、 SpringSecurity + JWT + RSA分布式认证
  3. SpringSecurity的用户认证逻辑
  4. SpringSecurity的身份校验逻辑

一、 系统安全

为了保障系统安全,我们使用Spring Security框架做认证授权。使用JWT和RSA技术,进而确保认证授权信息不被外界修改,进而突破权限管理越界使用。

1. JWT

JWT官方说明文档

JWT: Header.Payload.Signature

Ⅰ 头部Header

主要设置一些规范信息,签名部分的编码格式就在头部中声明;

{
  "alg": "HS256",
  "typ": "JWT"
}

Ⅱ 载荷Payload

token中存放有效信息的部分,比如用户名,用户角色,过期时间等;

{
  "sub": "1234567890",
  "name": "John Doe",
  "admin": true
}

Ⅲ 签名Signature

a、将头部与载荷分别采用【base64编码】后,用“.”相连;
b、再加入【盐】;(生成token与解析token的盐一样,则是对称加密)
c、最后使用头部声明的编码类型进行【编码】,就得到了签名。

HMACSHA256(
  base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret)

JWT =
base64UrlEncode(Header).
base64UrlEncode(Payload).
base64UrlEncode(HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret))

注意:
HS256(采用 SHA-256 的 HMAC 签名)是一种对称算法,Hash-based Message Authentication Code(哈希运算消息认证码)
RS256 (采用 SHA-256 的 RSA 签名) 是一种非对称算法,它使用公共/私钥对: 标识提供方采用私钥生成签名, JWT 的使用方获取公钥以验证签名。

2. RSA非对称加密

私钥加密,持有私钥或公钥才可以解密;
公钥加密,持有私钥才可解密。

这一块内容本人以前很容易绕进去,所以展开来简单讲下。

客户端 → 服务器A(Auth Server:标识提供方) → 客户端 → 服务器B(Source:JWT使用方)

假设:

情形一:服务器A公钥加密,私钥对公

a、客户端登录请求服务器A,认证后Payload只有"ROLE_USER"权限,返回公钥加密token;
b、由于私钥对公,客户端使用私钥解密,给自身添加"ROLE_ADMIN"权限,再加密;
c、客户端请求服务器B(Source:JWT使用方),私钥对公,此时服务器B可以使用私钥解密,授权"ROLE_USER"和"ROLE_ADMIN"给用户。

情形二:服务器A私钥加密,公钥对公

a、客户端登录请求服务器A,认证后Payload只有"ROLE_USER"权限,返回私钥加密token;
b、此时公钥对公,客户端使用公钥解密,给自身添加"ROLE_ADMIN"权限,再加密;
c、客户端请求服务器B(Source:JWT使用方),公钥对公,此时服务器B持有公钥,不能解密公钥加密内容。

所以,标识提供方应采用私钥加密,而公钥则是提供给使用方的。

二、 SpringSecurity + JWT + RSA分布式认证

1. SpringSecurity的用户认证逻辑

可以看到认证业务要求的是POST表单请求提交数据。而分布式前后端分离情形下,我们基本使用AJAX请求,而不是POST表单提交。所以此处的业务逻辑需要我们重写。

public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
    if (this.postOnly && !request.getMethod().equals("POST")) {
        throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
    } else {
        ...
    }
}

doFilter方法会进行具体的认证业务

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
        throws IOException, ServletException {
    ...
    successfulAuthentication(request, response, chain, authResult);
}
protected void successfulAuthentication(HttpServletRequest request,
        HttpServletResponse response, FilterChain chain, Authentication authResult)
        throws IOException, ServletException {
    ...
    //认证通过会把结果存入Spring Security自己的容器中
    SecurityContextHolder.getContext().setAuthentication(authResult);
    ...
}

认证通过的原有逻辑也不是我们需要的,所以此处也需要进行响应的修改。

2. SpringSecurity的身份校验逻辑

@Override
protected void doFilterInternal(HttpServletRequest request,
        HttpServletResponse response, FilterChain chain)
                throws IOException, ServletException {
            final boolean debug = this.logger.isDebugEnabled();

        String header = request.getHeader("Authorization");

        if (header == null || !header.toLowerCase().startsWith("basic ")) {
            chain.doFilter(request, response);
            return;
        }

        try {
            //【断点】对请求头内的信息做解码,可以看一下
            String[] tokens = extractAndDecodeHeader(header, request);
            ...
        }
        ...
}

Spring Security的解码逻辑还是非常清晰的值得学习,此处我们还需要跟据自己的需求坐下调整。

三、结尾

以上即为Spring Security-整合Spring Boot(分布式)-篇章一的全部内容,感谢阅读。

上一篇 下一篇

猜你喜欢

热点阅读