【问题标题】:Guardian file don't let me generate the JWT tokenGuardian 文件不允许我生成 JWT 令牌
【发布时间】:2019-07-12 09:26:29
【问题描述】:

我正在为我的项目使用 {:guardian, "~> 1.0"} 来生成令牌,但它给了我一个错误。

这是我的监护人文件的代码

defmodule Dailyploy.Guardian do
  use Guardian, otp_app: :dailyploy

  def subject_for_token(user, _claims) do
    sub = to_string(user.id)
    {:ok, sub}
  end

  def subject_for_token(_, _) do
    {:error, :reason_for_error}
  end

  def resource_from_claims(claims) do
    id = claims["sub"]
    resource = Dailyploy.Accounts.get_user!(id)
    {:ok,  resource}
  end

  def resource_from_claims(_claims) do
    {:error, :reason_for_error}
  end
end

它向我显示了一个错误,即 subject_for_token。 该子句无法匹配,因为第 4 行的前一个子句总是匹配Elixir

有人可以解释为什么它不起作用吗?

【问题讨论】:

    标签: elixir token phoenix-framework guardian


    【解决方案1】:

    编译器抱怨是因为你对subject_for_token 的两个定义是相同的,它们都期望完全相同的参数。

    要解决此问题,请明确表明您希望在第一个定义中接收 User 结构:

      def subject_for_token(%User{id: id}, _claims) do
        {:ok, to_string(id)}
      end
    
      def subject_for_token(_, _) do
        {:error, :reason_for_error}
      end
    

    resource_from_claims也可以这样说;这两个函数将匹配完全相同的参数。这也可以修复:

      def resource_from_claims(%{"sub" => sub}) do
        resource = Dailyploy.Accounts.get_user!(sub)
        {:ok, resource}
      end
    
      def resource_from_claims(_claims) do
        {:error, :reason_for_error}
      end
    

    【讨论】:

    • { "resource": "/home/shweta/dailyploy/lib/guardian.ex", , "message": "** (CompileError) lib/guardian.ex:4: User.__struct__ /0 未定义,无法扩展 struct User\n lib/guardian.ex:4: (module)\n", }
    • 我假设您在应用程序的某处有一个 User 架构,您想在此处使用。如果是这样,请将其更改为您正在使用的确切用户模块,例如 Dailyploy.Accounts.User
    • 将其更改为您正在使用的确切用户模块,例如 Dailyploy.Accounts.User-- 或者,包括以下行:alias Dailyploy.Accounts.User,这将使 %User{} 等效到%Dailyploy.Accounts.User{}
    【解决方案2】:

    谁能解释一下为什么这不起作用?

    当您调用函数时,elixir 从定义中的第一个函数子句开始,并尝试将函数调用中指定的参数与函数定义中的参数匹配。如果没有匹配,elixir 然后尝试下一个函数子句。当找到匹配项时,执行相应的函数体。如果没有一个函数子句匹配,那么你会得到一个 function_clause 错误。

    让我们看一个例子。如果你写:

    def go({1, 2}, :cat) do
       IO.puts "I must have matched the function call."
    end
    

    然后你可以像这样调用那个函数:

    iex(2)> A.go({1, 2}, :cat)
    I must have matched the function call.
    :ok
    

    但是,如果你尝试:

    ex(3)> A.go("hello", 10)
    ** (FunctionClauseError) no function clause matching in A.go/2    
    
        The following arguments were given to A.go/2:
    
            # 1
            "hello"
    
            # 2
            10
    
        a.ex:2: A.go/2
    

    你得到一个函数子句错误,因为go()的定义没有函数子句匹配函数调用:

      function call:     A.go("hello", 10)
                                |       |
                {1,2} = "hello  |       | :cat = 10
                                V       V
      function def:    def go({1, 2}, :cat) do
    

    go()函数调用中唯一能匹配函数定义中元组{1, 2}的参数是元组{1, 2},函数调用中唯一能匹配函数定义中原子:cat的参数函数定义是原子:cat

    但是,函数定义中的变量可以匹配任何内容。合法变量名称的一些示例是:xy_x_。所以,如果你这样定义go()

      def go(_x, _y) do
        IO.puts "I must have matched the function call."
      end
    

    那么两个函数调用都会匹配:

    iex(3)> c "a.ex"          
    warning: redefining module A (current version defined in memory)
      a.ex:1
    [A]
    
    iex(4)> A.go("hello", 10)
    I must have matched the function call.
    :ok
    
    iex(5)> A.go({1, 2}, :cat)
    I must have matched the function call.
    :ok
    

    如果在 go() 定义中添加第二个函数子句:

      def go(_x, _y) do
        IO.puts "I must have matched the function call."
      end
      def go(_, _) do
        IO.puts "I will never match"
      end
    

    第一个函数子句仍然会匹配任意两个参数,因为这样,第二个函数子句将永远不会执行——所以编译器会给你一个警告,相当于:

    什么?你为什么在第二个函数子句中乱写所有垃圾 什么时候它永远不会匹配,因此永远不会执行?!抓紧!

    当您在函数定义中进行模式匹配时,事情会变得有些棘手,例如:

    def go(%{a: val}=map, x) do
    

    请参阅 here 了解其工作原理。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-08-29
      • 2021-07-29
      • 2023-04-09
      • 2017-05-13
      • 1970-01-01
      • 2022-01-27
      • 2018-02-01
      • 2019-11-29
      相关资源
      最近更新 更多