在Ruby on Rails上使JWT过期令牌失效

4
我正在尝试像这样设置jwt令牌的过期时间:
class JsonWebToken
  def self.encode(payload)
    payload[:exp] = (2).minutes.from_now.to_i #expire in 2 minutes
    JWT.encode(payload, Rails.application.secrets.secret_key_base)
  end

  def self.decode(token)
    return HashWithIndifferentAccess.new(JWT.decode(token, Rails.application.secrets.secret_key_base)[0])
  rescue
    nil
  end
end

但是,当我尝试访问URL时,令牌始终有效。并且如果我解码令牌,我从哈希中永远不会得到exp键值对。有什么建议吗?
更新
我正在使用jwt gem
这就是我如何验证用户身份的。
def authenticate_user
    user = User.find_for_database_authentication(email: params[:email])
    if user.valid_password?(params[:password])
      render json: payload(user)
    else
      render json: {errors: ['Invalid Username/Password']}, status: :unauthorized
    end
  end

  private

  def payload(user)
    return nil unless user and user.id
    {
      auth_token: JsonWebToken.encode({user_id: user.id}),
      user: {id: user.id, email: user.email}
    }
  end

使用curl的示例:

curl -X POST -d email="a@a.com" -d password="changeme" http://localhost:3000/auth_user

这个curl返回:

{"auth_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxfQ.wPPX7T6WJ5K8ucjZF_l8-9mG7IzabcusLeWw1UOhhTM","user":{"id":1,"email":"a@a.com"}}

然后在我的 Rails 控制台上:

JWT.decode("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxfQ.wPPX7T6WJ5K8ucjZF_l8-9mG7IzabcusLeWw1UOhhTM", Rails.application.secrets.secret_key_base)

并获取:

[{"user_id"=>1}, {"typ"=>"JWT", "alg"=>"HS256"}]

正如您所看到的,令牌始终有效,即使我在这一行设置了过期时间:

def self.encode(payload)
    payload[:exp] = (2).minutes.from_now.to_i #expire in 2 minutes <<--- This one
    JWT.encode(payload, Rails.application.secrets.secret_key_base)
  end

你使用的JWT gem是什么?你能分享一个最简单的例子来创建token,然后解码它并且过期时间没有影响吗?(例如,你可以使用上面的类。) - user94559
@smarx刚刚为您更新了我的问题。提前致谢。 - Jean
你还没有分享一个最小化的例子来展示这个问题。比如说,在某个地方有一段代码解析了 Authorization 头部,(可能)解码了 JWT 并且应该拒绝带有无效令牌的请求,但是我在你分享的代码中没有看到任何类似的内容。我只能说 JWT gem 似乎没有问题,所以你代码中的问题出现在其他地方。 - user94559
@smarx,请查看我的curl示例。您的代码可行,但我不明白为什么我的代码不行。 - Jean
我的假设是:那不是你正在运行以创建令牌的代码。尝试添加一些日志记录? - user94559
1个回答

9

下面是一个简单的测试,展示了JWT gem(Ruby的JSON Web Token库)正常工作:

require 'JWT'

class JsonWebToken
  def self.encode(payload, expiration)
    payload[:exp] = expiration
    JWT.encode(payload, 'SECRET')
  end

  def self.decode(token)
    return JWT.decode(token, 'SECRET')[0]
  rescue
    'FAILED'
  end
end

# expire 2 minutes from now
token = JsonWebToken.encode({ :hello => 'world' }, Time.now.to_i + 120)
puts token # eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiZXhwIjoxNDY4Njg3OTc1fQ.NhIsdEa0Q7Wl5Dx6kyJvSZY6E8ViJ5Kooo7rKr2OBPg
puts JsonWebToken.decode(token) # {"hello"=>"world", "exp"=>1468687975}

# expire 2 minutes ago
token = JsonWebToken.encode({ :hello => 'world' }, Time.now.to_i - 120)
puts token # eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJoZWxsbyI6IndvcmxkIiwiZXhwIjoxNDY4Njg3NzM1fQ.kDD_WWN3ZTTdFXQvYEgm1CgDaE1mEZxjMvQkQEq4HX8
puts JsonWebToken.decode(token) # FAILED

谢谢你的帮助,但我忘记重启服务器了,这就是我的问题。 - Jean
1
如预料的一样。 :-) “我的假设是:那不是你正在运行以创建令牌的实际代码。” - user94559
3
@smarx,当用户注销时,我该如何重置令牌? - uzaif

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接