【问题标题】:How to get token expiration with `jsonwebtoken` using typescript如何使用打字稿通过`jsonwebtoken`获取令牌到期
【发布时间】:2018-05-10 13:02:50
【问题描述】:

我正在使用jsonwebtoken 来解码令牌,并且正在尝试获取到期日期。 Typescript 抛出关于 exp 属性的错误,我不太确定如何解决它们:

import jwt from 'jsonwebtoken'

const tokenBase64 = 'ey...' /* some valid token */

const token = jwt.decode(tokenBase64)
const tokenExpirationDate = token.exp
//                                ^^^
// Property 'exp' does not exist on type 'string | object'. Property 'exp' does not exist on type 'string'.

我已经安装了@types/jsonwebtoken,并寻找一个令牌类型来转换token,但没有找到。有什么建议吗?

使用

  • @types/jsonwebtoken@7.2.3
  • jsonwebtoken@8.1.0

.tsconfig:

{
  "compilerOptions": {
    "allowJs": true,
    "baseUrl": ".",
    "jsx": "Preserve",
    "moduleResolution": "Node",
    "module": "ESNext",
    "sourceMap": true,
    "removeComments": true,
    "allowSyntheticDefaultImports": true,
    "target": "ESNext"
  }
}

【问题讨论】:

    标签: typescript jwt json-web-token


    【解决方案1】:

    当我使用import jwt from 'jsonwebtoken' 行时,我收到了相同的错误消息 使用var jwt = require('jsonwebtoken'); [1] 可以正常工作:

    var jwt = require('jsonwebtoken');
    var tokenBase64 = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiZXhwIjoiMTUxMTk1MDcwMyIsImFkbWluIjp0cnVlfQ.wFC-9ZsqA9QuvLkRSkQmVYpUmgH9R-j8M4D0GECuPHY';
    
    const token = jwt.decode(tokenBase64);
    const tokenExpirationDate = token.exp
    console.log(tokenExpirationDate);
    

    [1] 另见https://github.com/auth0/node-jsonwebtoken

    【讨论】:

    • 感谢您更新您的问题。问题是由import jwt from 'jsonwebtoken' 引起的。我相应地更新了我的答案。希望它对你有用。如果您遇到无法找到需要的错误,请执行npm install @types/node --save-dev,请参阅stackoverflow.com/questions/31173738/…
    • 这行得通,但如果有人有一个仍然可以使用 import 而不是 require 的解决方案,那就太好了。也许应该更改类型文件。
    【解决方案2】:

    我发现用户导入的唯一方法是:

    import { sign, verify } from 'jsonwebtoken';
    sign('Hello', 'secret');
    

    但我认为require 方法更好,这样您就不必显式导入每个函数。

    【讨论】:

    • 实现你的答案后这个错误怎么样? Argument of type 'string | undefined' is not assignable to parameter of type 'Secret''有什么想法吗?
    • @chris 我发现摆脱ts Argument of type 'string | undefined' is not assignable to parameter of type 'Secret 的唯一方法是创建自己的类型定义。关于密钥,我必须执行以下操作ts // eslint-disable-next-line no-unused-vars declare namespace NodeJS { export interface ProcessEnv { JWT_SECRET: string, JWT_EXPIRATION: string, TOKEN_ISSUER: string } }
    【解决方案3】:

    从 jsonwebtoken 8.3 开始,jsonwebtoken.decode() 具有以下类型定义:

    export function decode(
        token: string,
        options?: DecodeOptions,
    ): null | { [key: string]: any } | string;
    

    由于 Typescript 无法推断出正确的类型且 exp 未知,因此最简单的方法是将结果强制转换为 any

    import jwt from 'jsonwebtoken'
    
    const tokenBase64 = 'ey...' /* some valid token */
    
    const token: any = jwt.decode(tokenBase64)
    const tokenExpirationDate = token.exp
    

    【讨论】:

    • 我遇到了这个问题:模块 '"./node_modules/@types/jsonwebtoken/index"' 没有默认导出。
    【解决方案4】:

    这就是我使用 TS 解码的方式

    import jwt from 'jsonwebtoken';
    
    export const isTokenExpired = (token: string): boolean => {
        try {
            const { exp } = jwt.decode(token) as {
                exp: number;
            };
            const expirationDatetimeInSeconds = exp * 1000;
    
            return Date.now() >= expirationDatetimeInSeconds;
        } catch {
            return true;
        }
    };
    

    不需要,但你也可以

    import 'jest';
    import jwt from 'jsonwebtoken';
    
    import { isTokenExpired } from 'path-to-isTokenExpired/isTokenExpired';
    
    describe('isTokenExpired', () => {
        it('should return true if jwt token expired', () => {
            const currentTimeInSecondsMinusThirtySeconds = Math.floor(Date.now() / 1000) - 30;
            const expiredToken = jwt.sign({ foo: 'bar', exp: currentTimeInSecondsMinusThirtySeconds }, 'shhhhh');
    
            expect(isTokenExpired(expiredToken)).toEqual(true);
        });
    
        it('should return false if jwt token not expired', () => {
            const currentTimeInSecondsPlusThirtySeconds = Math.floor(Date.now() / 1000) + 30;
            const notExpiredToken = jwt.sign({ foo: 'bar', exp: currentTimeInSecondsPlusThirtySeconds }, 'shhhhh');
    
            expect(isTokenExpired(notExpiredToken)).toEqual(false);
        });
    
        it('should return true if jwt token invalid', () => {
            expect(isTokenExpired('invalidtoken')).toEqual(true);
        });
    });
    

    【讨论】:

      【解决方案5】:

      我认为import * as jwt from 'jsonwebtoken'; 应该可以按预期工作。

      【讨论】:

        【解决方案6】:

        jwt.verify 和 jwt.decode 的返回类型为'string | object'

        在您的情况下,您有一些 Typescript 没有的关于返回类型的附加信息。所以你可以像这样添加它:

        const token = jwt.decode(tokenBase64) as {exp: number}
        const tokenExpirationDate = token.exp
        

        当然,您也可以在对象中添加任何其他值。

        虽然假设exp 存在是合理的,但其他键可能不存在。确保您正在解码的令牌实际上包含它们或将其添加为可选值:({exp: number; random?: string})

        【讨论】:

          【解决方案7】:
          import * as jwt from 'jsonwebtoken'
          
          const { authorization } = ctx.req.headers
          const token = authorization.replace('Bearer ', '')
          const decoded = jwt.verify(token, 'APP_SECRET')
          const userId = (decoded as any).userId
          

          当然你可以输入decoded,而不是any

          【讨论】:

          • 是的,这在所有其他选项中都有效
          【解决方案8】:

          我发现自己为此创建了一个助手(基于类的解决方案 - 当然可以用作单独的功能):

          import { JwtPayload, verify } from "jsonwebtoken";
          
          export class BaseController {
            // ...
            static decodeJWT = <T extends { [key: string]: any }>(token: string) => {
              return verify(token, process.env.JWT_ACCESS_TOKEN!) as JwtPayload & T; 
              // this typing allows us to keep both our encoded data and JWT original properties
            };
          }
          

          用于以下控制器:

          import { BaseController } from "./BaseController";
          
          export class UserController extends BaseController {
            static getUser = async (
              // ...
            ) => {
              // get token
              // username may or may not be here - safer to check before use
              const payload = this.decodeJWT<{ username?: string }>(token); 
              // no error here, we can extract all properties defined by us and original JWT props
              const { username, exp } = payload;
              // do stuff...
            };
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2018-06-13
            • 1970-01-01
            • 2019-06-01
            • 1970-01-01
            • 2016-10-18
            • 1970-01-01
            • 1970-01-01
            • 2021-10-03
            相关资源
            最近更新 更多