Rails 5 和 Devise:如何在不更改默认策略的情况下禁用基于令牌的策略上的会话

2024-04-22

我有一个 Rails 5 应用程序,使用两种身份验证策略,一种使用基于令牌的身份验证,另一种使用基于默认会话的身份验证。

当我触发令牌身份验证时,我试图禁用会话保存。因为当我使用 JWT 对用户进行身份验证时,它会保存会话,并且该会话应该是无状态的。我仍然需要使用默认的用户名/电子邮件设备用例。

配置/初始化器/devise.rb

# Use this hook to configure devise mailer, warden hooks and so forth.
# Many of these configuration options can be set straight in your model.
Devise.setup do |config|
  # The secret key used by Devise. Devise uses this key to generate
  # random tokens. Changing this key will render invalid all existing
  # confirmation, reset password and unlock tokens in the database.
  # Devise will use the `secret_key_base` as its `secret_key`
  # by default. You can change it below and use your own secret key.
  config.secret_key = '036d134b82b5a6cbc6590d815d703a523d9a01cef4d37ff50b5b0d7b8558afcc415f98dd3d6e6404ec6c95c18958a4d69e60a7c3937a74e145da4b8789e454b0'

  # ==> Mailer Configuration
  # Configure the e-mail address which will be shown in Devise::Mailer,
  # note that it will be overwritten if you use your own mailer class
  # with default "from" parameter.
  config.mailer_sender = '[email protected] /cdn-cgi/l/email-protection'

  # Configure the class responsible to send e-mails.
  # config.mailer = 'Devise::Mailer'

  # Configure the parent class responsible to send e-mails.
  # config.parent_mailer = 'ActionMailer::Base'

  # ==> ORM configuration
  # Load and configure the ORM. Supports :active_record (default) and
  # :mongoid (bson_ext recommended) by default. Other ORMs may be
  # available as additional gems.
  require 'devise/orm/active_record'

  # ==> Configuration for any authentication mechanism
  # Configure which keys are used when authenticating a user. The default is
  # just :email. You can configure it to use [:username, :subdomain], so for
  # authenticating a user, both parameters are required. Remember that those
  # parameters are used only when authenticating and not when retrieving from
  # session. If you need permissions, you should implement that in a before filter.
  # You can also supply a hash where the value is a boolean determining whether
  # or not authentication should be aborted when the value is not present.
  # config.authentication_keys = [:email]

  # Configure parameters from the request object used for authentication. Each entry
  # given should be a request method and it will automatically be passed to the
  # find_for_authentication method and considered in your model lookup. For instance,
  # if you set :request_keys to [:subdomain], :subdomain will be used on authentication.
  # The same considerations mentioned for authentication_keys also apply to request_keys.
  # config.request_keys = []

  # Configure which authentication keys should be case-insensitive.
  # These keys will be downcased upon creating or modifying a user and when used
  # to authenticate or find a user. Default is :email.
  config.case_insensitive_keys = [:email]

  # Configure which authentication keys should have whitespace stripped.
  # These keys will have whitespace before and after removed upon creating or
  # modifying a user and when used to authenticate or find a user. Default is :email.
  config.strip_whitespace_keys = [:email]

  # Tell if authentication through request.params is enabled. True by default.
  # It can be set to an array that will enable params authentication only for the
  # given strategies, for example, `config.params_authenticatable = [:database]` will
  # enable it only for database (email + password) authentication.
  # config.params_authenticatable = true

  # Tell if authentication through HTTP Auth is enabled. False by default.
  # It can be set to an array that will enable http authentication only for the
  # given strategies, for example, `config.http_authenticatable = [:database]` will
  # enable it only for database authentication. The supported strategies are:
  # :database      = Support basic authentication with authentication key + password
  # config.http_authenticatable = false

  # If 401 status code should be returned for AJAX requests. True by default.
  # config.http_authenticatable_on_xhr = true

  # The realm used in Http Basic Authentication. 'Application' by default.
  # config.http_authentication_realm = 'Application'

  # It will change confirmation, password recovery and other workflows
  # to behave the same regardless if the e-mail provided was right or wrong.
  # Does not affect registerable.
  # config.paranoid = true

  # By default Devise will store the user in session. You can skip storage for
  # particular strategies by setting this option.
  # Notice that if you are skipping storage for all authentication paths, you
  # may want to disable generating routes to Devise's sessions controller by
  # passing skip: :sessions to `devise_for` in your config/routes.rb
  config.skip_session_storage = [:http_auth, :jwt]

  # By default, Devise cleans up the CSRF token on authentication to
  # avoid CSRF token fixation attacks. This means that, when using AJAX
  # requests for sign in and sign up, you need to get a new CSRF token
  # from the server. You can disable this option at your own risk.
  # config.clean_up_csrf_token_on_authentication = true

  # When false, Devise will not attempt to reload routes on eager load.
  # This can reduce the time taken to boot the app but if your application
  # requires the Devise mappings to be loaded during boot time the application
  # won't boot properly.
  # config.reload_routes = true

  # ==> Configuration for :database_authenticatable
  # For bcrypt, this is the cost for hashing the password and defaults to 11. If
  # using other algorithms, it sets how many times you want the password to be hashed.
  #
  # Limiting the stretches to just one in testing will increase the performance of
  # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use
  # a value less than 10 in other environments. Note that, for bcrypt (the default
  # algorithm), the cost increases exponentially with the number of stretches (e.g.
  # a value of 20 is already extremely slow: approx. 60 seconds for 1 calculation).
  config.stretches = Rails.env.test? ? 1 : 11

  # Set up a pepper to generate the hashed password.
  # config.pepper = 'e175017c1146ba28221804d56b560ea9c90aed5e00b8b57b99825f20677ae20fa0685101a6c024ac0041332f7621b85da134dcda32a53d7ff8254e433feee213'

  # Send a notification email when the user's password is changed
  config.send_password_change_notification = true

  # ==> Configuration for :confirmable
  # A period that the user is allowed to access the website even without
  # confirming their account. For instance, if set to 2.days, the user will be
  # able to access the website for two days without confirming their account,
  # access will be blocked just in the third day. Default is 0.days, meaning
  # the user cannot access the website without confirming their account.
  # config.allow_unconfirmed_access_for = 2.days

  # A period that the user is allowed to confirm their account before their
  # token becomes invalid. For example, if set to 3.days, the user can confirm
  # their account within 3 days after the mail was sent, but on the fourth day
  # their account can't be confirmed with the token any more.
  # Default is nil, meaning there is no restriction on how long a user can take
  # before confirming their account.
  # config.confirm_within = 3.days

  # If true, requires any email changes to be confirmed (exactly the same way as
  # initial account confirmation) to be applied. Requires additional unconfirmed_email
  # db field (see migrations). Until confirmed, new email is stored in
  # unconfirmed_email column, and copied to email column on successful confirmation.
  config.reconfirmable = true

  # Defines which key will be used when confirming an account
  # config.confirmation_keys = [:email]

  # ==> Configuration for :rememberable
  # The time the user will be remembered without asking for credentials again.
  # config.remember_for = 2.weeks

  # Invalidates all the remember me tokens when the user signs out.
  config.expire_all_remember_me_on_sign_out = true

  # If true, extends the user's remember period when remembered via cookie.
  # config.extend_remember_period = false

  # Options to be passed to the created cookie. For instance, you can set
  # secure: true in order to force SSL only cookies.
  # config.rememberable_options = {}

  # ==> Configuration for :validatable
  # Range for password length.
  config.password_length = 6..128

  # Email regex used to validate email formats. It simply asserts that
  # one (and only one) @ exists in the given string. This is mainly
  # to give user feedback and not to assert the e-mail validity.
  config.email_regexp = /\A[^@\s]+@[^@\s]+\z/

  # ==> Configuration for :timeoutable
  # The time you want to timeout the user session without activity. After this
  # time the user will be asked for credentials again. Default is 30 minutes.
  # config.timeout_in = 30.minutes

  # ==> Configuration for :lockable
  # Defines which strategy will be used to lock an account.
  # :failed_attempts = Locks an account after a number of failed attempts to sign in.
  # :none            = No lock strategy. You should handle locking by yourself.
  # config.lock_strategy = :failed_attempts

  # Defines which key will be used when locking and unlocking an account
  # config.unlock_keys = [:email]

  # Defines which strategy will be used to unlock an account.
  # :email = Sends an unlock link to the user email
  # :time  = Re-enables login after a certain amount of time (see :unlock_in below)
  # :both  = Enables both strategies
  # :none  = No unlock strategy. You should handle unlocking by yourself.
  # config.unlock_strategy = :both

  # Number of authentication tries before locking an account if lock_strategy
  # is failed attempts.
  # config.maximum_attempts = 20

  # Time interval to unlock the account if :time is enabled as unlock_strategy.
  # config.unlock_in = 1.hour

  # Warn on the last attempt before the account is locked.
  # config.last_attempt_warning = true

  # ==> Configuration for :recoverable
  #
  # Defines which key will be used when recovering the password for an account
  # config.reset_password_keys = [:email]

  # Time interval you can reset your password with a reset password key.
  # Don't put a too small interval or your users won't have the time to
  # change their passwords.
  config.reset_password_within = 6.hours

  # When set to false, does not sign a user in automatically after their password is
  # reset. Defaults to true, so a user is signed in automatically after a reset.
  # config.sign_in_after_reset_password = true

  # ==> Configuration for :encryptable
  # Allow you to use another hashing or encryption algorithm besides bcrypt (default).
  # You can use :sha1, :sha512 or algorithms from others authentication tools as
  # :clearance_sha1, :authlogic_sha512 (then you should set stretches above to 20
  # for default behavior) and :restful_authentication_sha1 (then you should set
  # stretches to 10, and copy REST_AUTH_SITE_KEY to pepper).
  #
  # Require the `devise-encryptable` gem when using anything other than bcrypt
  # config.encryptor = :sha512

  # ==> Scopes configuration
  # Turn scoped views on. Before rendering "sessions/new", it will first check for
  # "users/sessions/new". It's turned off by default because it's slower if you
  # are using only default views.
  # config.scoped_views = false

  # Configure the default scope given to Warden. By default it's the first
  # devise role declared in your routes (usually :user).
  # config.default_scope = :user

  # Set this configuration to false if you want /users/sign_out to sign out
  # only the current scope. By default, Devise signs out all scopes.
  # config.sign_out_all_scopes = true

  # ==> Navigation configuration
  # Lists the formats that should be treated as navigational. Formats like
  # :html, should redirect to the sign in page when the user does not have
  # access, but formats like :xml or :json, should return 401.
  #
  # If you have any extra navigational formats, like :iphone or :mobile, you
  # should add them to the navigational formats lists.
  #
  # The "*/*" below is required to match Internet Explorer requests.
  # config.navigational_formats = ['*/*', :html]

  # The default HTTP method used to sign out a resource. Default is :delete.
  config.sign_out_via = :get

  # ==> OmniAuth
  # Add a new OmniAuth provider. Check the wiki for more information on setting
  # up on your models and hooks.
  # config.omniauth :github, 'APP_ID', 'APP_SECRET', scope: 'user,public_repo'

  # ==> Warden configuration
  # If you want to use other strategies, that are not supported by Devise, or
  # change the failure app, you can configure them inside the config.warden block.
  #
  # config.warden do |manager|
  #   manager.intercept_401 = false
  #   manager.default_strategies(scope: :user).unshift :some_external_strategy
  # end

  # ==> Mountable engine configurations
  # When using Devise inside an engine, let's call it `MyEngine`, and this engine
  # is mountable, there are some extra configurations to be taken into account.
  # The following options are available, assuming the engine is mounted as:
  #
  #     mount MyEngine, at: '/my_engine'
  #
  # The router that invoked `devise_for`, in the example above, would be:
  # config.router_name = :my_engine
  #
  # When using OmniAuth, Devise cannot automatically set OmniAuth path,
  # so you need to do it manually. For the users scope, it would be:
  # config.omniauth_path_prefix = '/my_engine/users/auth'

   config.warden do |manager|
    # Registering your new Strategy
    manager.strategies.add(:jwt, Devise::Strategies::JsonWebToken)

    # Adding the new JWT Strategy to the top of Warden's list,
    # Scoped by what Devise would scope (typically :user)
    manager.default_strategies(scope: :user).unshift :jwt
   end
end

配置/初始化/core_extensions/devise/strategies/json_web_token.rb

module Devise
  module Strategies
    class JsonWebToken < Base
      def valid?
        request.headers['Authorization'].present?
      end

      def authenticate!
        return fail! unless claims
        return fail! unless claims.has_key?('id')

        success! User.find_by_id claims['id']
      end

      protected ######################## PROTECTED #############################

      def claims
        strategy, token = request.headers['Authorization'].split(' ')

        return nil if (strategy || '').downcase != 'bearer'

        JWTWrapper.decode(token) rescue nil
      end
    end
  end
end

我解决了我自己的问题,因为 Devise 提供的是一系列策略config.skip_session_storage = [:http_auth, :jwt]不起作用我需要做的是添加一个store?策略中的方法如下:

module Devise
  module Strategies
    class JsonWebToken < Base
      def valid?
        request.headers['Authorization'].present?
      end

      def authenticate!
        return fail! unless claims
        return fail! unless claims.has_key?('id')

        success! User.find_by_id claims['id']
      end

      def store?
        false
      end

      protected ######################## PROTECTED #############################

      def claims
        strategy, token = request.headers['Authorization'].split(' ')

        return nil if (strategy || '').downcase != 'bearer'

        JWTWrapper.decode(token) rescue fail!
      end
    end
  end
end

什么时候开店?方法返回 false 用户未保存在会话存储中。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Rails 5 和 Devise:如何在不更改默认策略的情况下禁用基于令牌的策略上的会话 的相关文章

  • AJAX Rails 验证

    我的表单和验证可以很好地处理常规的 http 请求 我希望它使用 AJAX 我知道我可以在客户端进行验证 但这似乎是多余的 因为我已经在模型中定义了验证 当用户填写表单时 我想就他们的条目向他们提供反馈 在 AJAX 表单中使用 Rails
  • 新手:我的例子中的文本替换

    In my 红宝石 on Rails应用程序中 我的助手中有一个方法 它通过以下方式打开文件 content File open myfile txt The 文件内容就好像 my car my seat my age my son my
  • Ruby on Rails:simple_form + Twitter Bootstrap 未显示

    我正在为我的网站上的新用户创建一个简单的注册表单 我已经运行了 simple form bootstrap 的安装 rails g simple form install bootstrap 但是 它仍然没有显示并呈现为正常的 simple
  • .NET 中的 Cookie 和会话过期

    我有一个 MVC4 单一应用程序页面 登录页面有 3 个字段 用户 密码和 记住我 复选框 C 登录代码是这样的 if WebSecurity Login model UserName model Password persistCooki
  • 如何对 mongodb/mongoid 脚本进行基准测试,以比较两种不同的查询技术

    您对如何测试两种不同的 mongoid mongodb 查询实现的性能有什么建议吗 要比较的实现与以前的相关 问答 https stackoverflow com questions 10121977 extracting modellin
  • 如何在 RoR 中实施成就系统

    我正在尝试在我的 Ruby on Rails 应用程序中实现一个成就系统 但效果很差 我有一长串想要检查的成就 所有这些都是由各种控制器中的某些创建操作触发的 我的想法是我将拥有一个成就模型 其中包括控制器及其响应的操作 然后对创建进行之前
  • 如何将 Devise 的“超时”模块添加到现有的 Devise 安装中? - 轨道 3.1

    这些是将模块添加到现有 Devise 安装的说明 https github com plataformatec devise wiki How To change an already existing table to add devis
  • 思考狮身人面像和控制台

    我在 webfaction 上思考 sphinx 时遇到问题 当我在 osx 上本地执行时没有问题 I search gt gt ThinkingSphinx 搜索 雷蒙德 我的回应是这样的 gt 有任何想法吗 thx sg 如果你还没有
  • 如何找到查询结果的大小

    我在 Rails 中有以下查询 records Record select y id source where source gt source y id gt y id group y id source having count 1 如
  • 无法验证 CSRF 令牌的真实性 Rails/React

    我的 Rails 应用程序中有一个 React 组件 我正在尝试使用它fetch 发送一个POST对于我在本地主机上托管的 Rails 应用程序 这给了我错误 ActionController InvalidAuthenticityToke
  • 我在 apache 中使用乘客 for Rails 时收到 403 错误

    我已经安装了所需的工具 并遵循了几个教程 试图让乘客做出回应 我可以访问公共文件夹 public 500 html 或 422 hml 中的静态文件 昨天我通过虚拟主机进入 发现一些乘客错误 但一段时间后 托管重新启动了服务 从那时起我就无
  • NoMethodError 未定义方法“名称” for nil:NilClass

    我有两个模型帖子和类别 我试图在我的索引和帖子显示视图中显示每个帖子的类别名称 我正在使用表连接 但问题是 虽然在我的显示视图中类别显示正确 但它在索引视图中给出了 NoMethodError undefined method name f
  • Rails 3.1 和 Asset Pipeline:使用 Capistrano 进行部署时遇到的问题

    我刚刚从 Ruby on Rails 3 0 10 切换到 3 1 0 我想使用 Capistrano gem 部署我的资产文件 我的本地计算机是运行 Snow Leopard 的 MacO 我的远程计算机运行的是 Ubuntu 10 04
  • 尝试使用适用于 Windows XP 的 Heroku 时未找到 msvcrt-ruby18.dll

    我有一个学生在 Windows XP 上进行开发 他在尝试运行时遇到了一个奇怪的错误heroku keys add 错误是 This application has failed to start because msvcrt ruby18
  • 使用 Ruby on Rails 进行设计 - 强制用户在首次登录时更改密码

    我有一个运行 Devise 的 RoR 应用程序 Rails 4 2 Ruby 2 2 0 我已经进行了设置 以便管理员用户 标识了我添加到用户模型中的 is admin 布尔值 能够创建新的用户帐户 为他们提供生成的密码和确认电子邮件 这
  • PassportJS - 自定义回调并将 Session 设置为 false

    是否可以使用自定义回调并禁用会话 在文档中 它显示了如何禁用会话和自定义回调 但如何组合它们 app get login function req res next passport authenticate local function
  • 如何在控制器内部使用 auto_link

    在我的控制器中 我需要构建一个 JSON 对象 如何在控制器内使用 auto link 现在它错误 NoMethodError undefined method mail to for
  • 如何在不加载关联模型的情况下检查 has_one 是否存在

    我有一个简单的 has one 关系 class User lt ApplicationRecord has one detail has many courses end class Detail lt ApplicationRecord
  • 强参数不起作用

    使用 Ruby 1 9 3 Rails 3 2 13 Strong parameters 0 2 1 我遵循了教程和railscasts中的每一个指示 但我无法让strong parameters工作 这应该是非常简单的事情 但我看不出错误
  • Ruby on Rails 中的三重连接

    我对 Ruby on Rails 中的关联有疑问 应用程序中有项目 用户 角色和组 项目属于一个有用户的组 一个用户可以属于多个不同的组 但只能在该组中拥有一个特定的角色 例如 在一个组中 用户是项目所有者 但在另一个组中 他是作家 使用

随机推荐

  • /var/run/docker.sock:在 Python CGI 脚本中运行 docker 时权限被拒绝

    我正在尝试运行 Python CGI 脚本 在其中需要运行 docker 镜像 我使用的是 Docker 版本 1 6 2 用户是 www data 添加到docker组中 www data www data sudo docker 在机器
  • 模型响应包含 swagger 中不同对象类型的数组

    我想建模一个响应对象 其中包含 swagger 中不同类型对象的数组 如下所示 table user customer employee 我尝试了下面的解决方案 但它将所有属性包装在单个对象 user customer 中 response
  • 使用 SSE/AVX 获取 __m256d 中存储的值的总和

    有没有办法获得存储在 m256d 变量中的值的总和 我有这个代码 acc mm256 add pd acc mm256 mul pd row vec acc in this point contains 2 0 8 0 18 0 32 0
  • Rvest XML 网络抓取

    我是一个初学者 我在抓取方面遇到了问题 我需要获取有关一些客户的活动 非活动 VEIS 号码的数据 目前 我只尝试一个 在网站上 我必须 设置值并发送表单 然后浏览器重定向到下一页 我可以在其中找到有趣的日期 下面我发送了我的代码 也许有人
  • Excel动态图表标题(前n个)

    是否可以创建包含 前 n 的动态 Excel 数据透视图标题 其中 n 用户选择的值过滤器行限制 我知道图表标题可以设置为单元格的内容 但不确定如何确定用户选择的前 n 个限制或如何将其添加到单元格公式中 如果可能的话 我们将不胜感激任何帮
  • 如何评估kafka流应用程序的消耗时间

    我有 1 0 0 kafka 流应用程序 有两个类 如下所示 class FilterByPolicyStreamsApp 和 class FilterByPolicyTransformerSupplier 在我的应用程序中 我读取事件 执
  • Django 模型:设置相对于另一个字段的默认值

    我正在使用 Django 1 10 作为后端构建一个应用程序 是否可以设置模型字段相对于同一实例中另一个模型的默认值 我特别需要设置second visit s默认为 3 周后first visit class SomeModel mode
  • 映射列类型 Slick 3.1.1

    我是 Slick 的新手 很难将 java sql date time timestamp 映射到 jodatime trait ColumnTypeMappings val profile JdbcProfile import profi
  • 如何将索引从一个索引节点移动到 couchbase 中的另一个索引节点

    我在 couchbase 集群中有 6 个索引节点 我想替换一次索引节点并将索引从旧索引节点移动到新索引节点 将索引从一个节点移动到另一个节点的最佳实践是什么 在 Couchbase 5 5 中 您可以使用 ALTER INDEX 语句将索
  • WooCommerce 根据用户角色更改 BACS 订单状态

    我收到几个订单 其中客户选择 直接银行转账 然后他们改变主意并希望通过信用卡付款 这非常烦人 因为我必须手动将订单从 暂停 更改为 待付款 以便他们可以通过 订单 下 我的帐户 中的 订单支付 端点通过卡付款 我一直在使用WooCommer
  • 错误:命令失败,rc=65536 python 和 mod_wsgi

    我遇到这个问题 我正在运行 pythonbrew 来获取 python2 7 因此我重新编译了 mod wsgi 以使用 2 7 python 为此 我遵循了本教程 code google com p modwsgi wiki QuickI
  • python 中的跨平台代码

    如何在 python 中编写一些 Windows 代码 仅当我在 widnows 中运行脚本时才执行 如果我应该在 linux 中运行它 则应该忽略这部分 windows 代码 与此类似 在 C 中 ifdef windows code e
  • C++ 如何将“this”传递给指针引用

    我有一个主类 我喜欢将其指针引用传递给我创建的对象 但它给了我错误 错误 1 错误 C2664 GameController GameController GameLayer 无法将参数 1 从 GameLayer const 转换为 Ga
  • ListView 的转换视图类型 BaseAdapter 错误

    我有一个使用不同类型的视图行的列表视图适配器 大多数时候它工作得很好 但是当我从列表中删除一个元素时它会崩溃 它将错误类型的convertView发送到getView public View getView int position Vie
  • @csrf_exempt 在 Django 1.4 中停止工作

    我有以下代码 在 Django 1 2 5 中运行良好 from django views decorators csrf import csrf exempt class ApiView object def call self requ
  • 在新窗口中使用 jquery 显示从控制器返回的 PDF 流

    我有一个控制器操作 它读取 pdf从 azure blob 存储中读取文件并将流对象返回到 ajax method 控制器返回 var stream blobStorage OpenRead filepath await FileAsync
  • x86 Assembly:很难找到无限循环挑战的想法

    我打算和我的朋友们进行一场类似于 corewars 的比赛 我们使用与原始游戏相同的内存网格 在游戏中 我们每个人都应该写一个 保险箱 它是一个不超过 25 行的无限循环 每个 安全 都有一个技巧或代码可以停止循环 从而破坏 安全 例如 S
  • Jqgrid 模态 Colspan

    我想将 colspan 属性应用于 JQgrid 模式窗口内的 td 它呈现具有以下结构的模态形式
  • 如何从 trie 构造 DAWG?

    我只是构建一个trie http en wikipedia org wiki Trie对于一个词汇表 然后我发现有很多分支共享相同的结构 我想将它们组合在一起 结果是DAWG http en wikipedia org wiki Deter
  • Rails 5 和 Devise:如何在不更改默认策略的情况下禁用基于令牌的策略上的会话

    我有一个 Rails 5 应用程序 使用两种身份验证策略 一种使用基于令牌的身份验证 另一种使用基于默认会话的身份验证 当我触发令牌身份验证时 我试图禁用会话保存 因为当我使用 JWT 对用户进行身份验证时 它会保存会话 并且该会话应该是无