使用f#/ fable/asp.net/react为谷歌登录添加一个按钮

sas*_*ang 3 asp.net f# jwt reactjs

我正在使用SAFE堆栈(https://safe-stack.github.io/)并通过示例dojo.到目前为止它很棒.

我想扩展这个示例以包含一个通过Google登录/验证的按钮.所以我查看了Google网站上的一个示例(https://developers.google.com/identity/sign-in/web/build-button).然后我看看如何使用ASP.NET进行身份验证(https://docs.microsoft.com/en-us/aspnet/core/security/authentication/social/google-logins?view=aspnetcore-2.1&tabs= aspnetcore2x)结果我最终对如何将其集成到SAFE项目感到困惑.有人能告诉我他们会做什么吗?我应该尝试使用ASP.NET身份还是应该使用JWT方法?我甚至都不知道它们是否相同,因为我对Web框架很新......

我的另一个问题是如何将原始Javascript注入SAFE项目的客户端.上面的谷歌示例显示了原始的JS/CSS/HTML代码?我应该按原样注入,还是应该在React中查找一些按钮来执行此操作并将该想法反映到寓言中?

rmu*_*unn 5

设置OAuth

使用Google OAuth的最简单方法是等到土星的下一个版本,此时土星将包含use_google_oauth我刚刚添加的功能.:-) 如果您对它的工作方式感兴趣,请查看源代码,但我担心您use_custom_oauth不能自己实现,因为您将遇到类型错误(底层ASP.NET代码有一个GoogleOptions类,并且use_custom_oauth想要一个OAuthOptions类,它们不兼容).

要使用它,请将以下内容添加到applicationCE:

use_google_oauth googleClientId googleClientSecret "/oauth_callback_google" []
Run Code Online (Sandbox Code Playgroud)

最后一个参数应该是string * string表示键和值的对序列:您可以使用元组列表,或传递的Map Map.toSeq,或其他任何内容.该序列的键是JSON结构中的键,Google为"获取有关此人的更多详细信息"API调用返回,而值是这些键应在ASP.NET声明系统中映射到的声明类型.use_google_oauth已经执行的默认映射是:

  • id →ClaimTypes.NameIdentifier
  • displayName →ClaimTypes.Name
  • emails[] (见注释)→ClaimTypes.Email

这三个由ASP.NET自动映射.我添加了第四个映射:

  • avatar.url →``"urn:google:avatar:url"

这个没有标准的ClaimTypes名称,所以我选择了一个任意的URN.注意:此功能尚未发布,并且可能(尽管不太可能)此字符串可能会在现在和在下一版本的土星中释放该功能时发生变化.

通过自动映射这四种声明类型,我发现我不需要指定任何其他声明,因此我将最终参数保留use_google_oauth为演示应用中的空列表.但是如果你想要更多(比如你想要在本地化中使用用户的首选语言),那么只需将它们添加到该列表中,例如:

use_google_oauth googleClientId googleClientSecret "/oauth_callback_google" ["language", "urn:google:language"]
Run Code Online (Sandbox Code Playgroud)

然后,一旦有人登录,请在User.Claimsseq中查找类型声明"urn:google:language".

请注意:emails[]JSON中的列表:我没有使用包含多封电子邮件的Google帐户对此进行测试,因此我不知道ASP.NET如何选择要在ClaimTypes.Email声明中添加的电子邮件.它可能只是挑在列表中的第一封电子邮件,或者它可能会选一个用typeaccount; 我只是不知道.可能需要一些实验.

另请注意,第三方OAuth(包括GitHub和Google)已拆分为新的Saturn.Extensions.Authorization包.它将在土星的下一个版本(可能是0.7.0)发布的同时在NuGet上发布.

制作按钮

一旦您use_google_oauth接到电话,请application创建以下内容:

let googleUserIdForRmunn = "106310971773596475579"
let matchUpUsers : HttpHandler = fun next ctx ->
    // A real implementation would match up user identities with something stored in a database, not hardcoded in Users.fs like this example
    let isRmunn =
        ctx.User.Claims |> Seq.exists (fun claim ->
            claim.Issuer = "Google" && claim.Type = ClaimTypes.NameIdentifier && claim.Value = googleUserIdForRmunn)
    if isRmunn then
        printfn "User rmunn is an admin of this demo app, adding admin role to user claims"
        ctx.User.AddIdentity(new ClaimsIdentity([Claim(ClaimTypes.Role, "Admin", ClaimValueTypes.String, "MyApplication")]))
    next ctx

let loggedIn = pipeline {
    requires_authentication (Giraffe.Auth.challenge "Google")
    plug matchUpUsers
}

let isAdmin = pipeline {
    plug loggedIn
    requires_role "Admin" (RequestErrors.forbidden (text "Must be admin"))
}
Run Code Online (Sandbox Code Playgroud)

现在在您的范围内(注意:"范围"可能会在Saturn 0.7.0中重命名为"router"),执行以下操作:

let loggedInView = scope {
    pipe_through loggedIn

    get "/" (htmlView Index.layout)
    get "/index.html" (redirectTo false "/")
    get "/default.html" (redirectTo false "/")
    get "/admin" (isAdmin >=> htmlView AdminPage.layout)
}
Run Code Online (Sandbox Code Playgroud)

最后,让你的主路由器有一个URL将事物传递给loggedInView路由器:

let browserRouter = scope {
    not_found_handler (htmlView NotFound.layout) //Use the default 404 webpage
    pipe_through browser //Use the default browser pipeline

    forward "" defaultView //Use the default view
    forward "/members-only" loggedInView
}
Run Code Online (Sandbox Code Playgroud)

然后你的登录按钮可以去/members-only路线,你会没事的.

请注意,如果您需要多个OAuth按钮(Google,GitHub,Facebook等),您可能需要稍微调整一下,但这个答案已经足够长了.当你想要多个OAuth按钮时,请继续问另一个问题.