JWT (JSON Web Token) аутентификация на основе токенов

Java

Встреча это судьба, пройди мимо и поставь лайк ^.^


Исходный код: https://github.com/yulc-coding/java-note/tree/master/jwt

вводить

JWT — это краткая, безопасная для URL-адреса спецификация репрезентативных утверждений для передачи информации о безопасности между двумя взаимодействующими сторонами, которая часто используется при междоменной аутентификации. Из-за существования цифровой подписи она может играть роль защиты от изменений.

Традиционный режим сеанса

По сравнению с традиционной сеансовой аутентификацией сеанс обычно хранится на стороне сервера, что требует поддержки сервера. А в случае кластеров серверов или служб междоменных запросов необходимо совместно использовать сеанс, чтобы каждый сервер мог прочитать сеанс, например сохранить сеанс, что увеличивает накладные расходы.

режим токена jwt

После входа пользователя сервер генерирует токен для соответствующих данных и возвращает его клиенту.
Клиент приносит токен каждый раз, когда он инициирует запрос
После того, как сервер получает токен, он проверяет правильность проверки токена.

Формат

  • Информация заголовка заголовка
{
  "alg": "Algorithm  加密方法:HS256",
  "cty": "Content Type ",
  "typ": "Type" ,
  "kid": "Key Id"
 }
  • Информация о носителе полезной нагрузки: сюда помещаются пакеты данных
{
  "iss": "Issuer JWT的签发者",
  "aud": "Audience 接收JWT的一方",
  "sub": "Subject JWT的主题",
  "exp": "Expiration Time JWT的过期时间",
  "nbf": "Not Before 在xxx之间,该JWT都是可用的",
  "iat": "Issued At 该JWT签发的时间",
  "jti": "JWT ID JWT的唯一身份标识",
  "xxx": "自定义属性"
}
  • Информация о подписи подписи = алгоритм шифрования (заголовок + «.» + полезная нагрузка, ключ)

  • TOKEN

base64(Header).base64(Payload).Signature

код

pom

    <!-- JWT 支持-->
    <dependency>
        <groupId>com.auth0</groupId>
        <artifactId>java-jwt</artifactId>
        <version>3.8.3</version>
    </dependency>

    <!-- 很好用的一个工具类包 这里用来处理json和AES加密-->
    <dependency>
        <groupId>cn.hutool</groupId>
        <artifactId>hutool-all</artifactId>
        <version>5.0.3</version>
    </dependency>

создать токен

Вы можете передавать в общедоступных полях или в настраиваемых полях

   /**
     * 创建token
     *
     * @param json 需要放入token的参数,多个参数可以封装成json或者map
     * @return token
     */
    public static String createToken(JSONObject json) {
        try {
            // 加密方式
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            return JWT.create()
                    .withSubject(json.toString())
                    .withIssuer("ylc")
                    // 设置过期时间为1分钟后
                    .withExpiresAt(DateUtil.offsetMinute(new Date(), 1))
                    .withClaim("customString", "自定义参数")
                    .withArrayClaim("customArray", new Integer[]{1, 2, 3})
                    .sign(algorithm);
        } catch (JWTCreationException exception) {
            //Invalid Signing configuration / Couldn't convert Claims.
            System.out.println(exception.getMessage());
            return null;
        }
    }

проверка токена

Включают:
Проверка формата: header.payload.signature
Проверка шифрования: значение alg в заголовке
Проверка подписи информации о подписи для предотвращения подделки данных
Проверка полей публичного объявления в полезной нагрузке носителя, например, проверка времени истечения срока действия iss, jti и exp.

    /**
     * 校验token 合法性
     *
     * @param token to verify.
     */
    public static boolean verifyToke(String token) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(SECRET);
            JWTVerifier verifier = JWT.require(algorithm)
                    // 验证签发人是否相同
                    .withIssuer("ylc")
                    .build();
            /*
             * 校验:
             * 格式校验:header.payload.signature
             * 加密方式校验 Header中的alg
             * 签名信息校验,防串改
             * 载体Payload 中公有声明字段校验
             */
            verifier.verify(token);
            return true;
        } catch (JWTVerificationException exception) {
            //Invalid signature/claims
            System.out.println(exception.getMessage());
            return false;
        }
    }

Разобрать токен

Все поля претензий можно получить через jwt.getClaims().
Вы также можете получить поле претензии с указанным именем через jwt.getClaim(name)

/**
 * 解析token
 *
 * @param token to decode.
 */
public static void decodeToken(String token) {
    try {
        DecodedJWT jwt = JWT.decode(token);
        Map<String, Claim> claims = jwt.getClaims();
        Claim customStringClaim = claims.get("customString");
        Claim customArrayClaim = claims.get("customArray");

        String issuer = jwt.getIssuer();
        String subject = jwt.getSubject();

        System.out.println(customStringClaim.asString());
        System.out.println(Arrays.toString(customArrayClaim.asArray(Integer.class)));
        System.out.println(issuer);
        System.out.println(JSONUtil.parseObj(subject));

    } catch (JWTDecodeException exception) {
        //Invalid token
        System.out.println(exception.getMessage());
    }
}

недостаток

  • Токен, сгенерированный по умолчанию, не зашифрован. Другие могут проанализировать токен, чтобы получить содержащиеся в нем данные. Если вы хотите передать конфиденциальную информацию, вы можете сначала зашифровать информацию, а затем поместить ее в токен или зашифровать сгенерированный токен.
  • Каждый раз, когда срок действия токена продлевается, будет генерироваться новый токен, и интерфейс должен заменить исходный токен.
  • Поскольку сервер не сохраняет состояние сеанса, невозможно отозвать токен во время использования или изменить разрешения токена. Другими словами, после выпуска JWT он всегда будет действителен до истечения срока его действия, и для его обработки на сервере необходимо установить соответствующую бизнес-логику.

Поиск внимания