Rom*_*ros 6 c# oauth-2.0 single-page-application asp.net-core asp.net-core-webapi
我已经发现几天ASP.NET Core,并想尝试通过LinkedIn实现身份验证。
我在网上找到的大多数教程都是使用MVC的,这是一个无缝的过程,但是我想做一个纯API。
我有一些有效的方法,但是我不确定这是安全的(我遇到了一些我以不安全的方式“解决”的问题)。
配置身份时,我使用,services.AddIdentityCore<ApplicationUser>()而不是AddIdentity<>避免添加cookie身份验证方案,然后使用service.AddAuthentication(...).AddJwtBearer(...)。
我使用电子邮件/密码进行了注册/登录,返回了JWT令牌,并使用它们来保护对API方法的访问,并且效果很好。
到目前为止,一切都很好。
我遇到的问题是当我.AddLinkedIn()(来自aspnet-contrib提供程序)出现的。
我添加了/login/external?provider=LinkedIn仅(?)作用是的路线
public IActionResult ExternalLogin(string provider)
{
return Challenge(provider);
}
Run Code Online (Sandbox Code Playgroud)
将用户重定向到提供程序登录页面。这是我所做的第一件事,我认为这可能是一个肮脏/不安全的修复程序,但是它可以起作用:我在LinkedIn登录页面上重定向,然后在我的回调页面上重定向(在本例中为/login/linkedin?code=)。
那是我不了解的事情发生的地方:AspNet.Security.OAuth.LinkedIn.LinkedInAuthenticationHandler可能基于回调路径被调用了,并验证了所有内容。它还尝试登录,但是由于我没有配置SignIn方案(JWT Bearer仅允许Authenticate和Challenge方案),所以该方法不起作用。
更糟糕的是,当AddIdentity<>我第一次尝试使用时,我得到了一个如下所示的回调循环:
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET https://localhost:5001/login/external?provider=LinkedIn
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Route matched with {action = "ExternalLogin", controller = "Login"}. Executing action RestAPI.Controllers.LoginController.ExternalLogin (RestAPI)
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Executing action method RestAPI.Controllers.LoginController.ExternalLogin (RestAPI) with arguments (LinkedIn) - Validation state: Valid
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action method RestAPI.Controllers.LoginController.ExternalLogin (RestAPI), returned result Microsoft.AspNetCore.Mvc.ChallengeResult in 0.2266ms.
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
Executing ChallengeResult with authentication schemes (LinkedIn).
info: AspNet.Security.OAuth.LinkedIn.LinkedInAuthenticationHandler[12]
AuthenticationScheme: LinkedIn was challenged.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action RestAPI.Controllers.LoginController.ExternalLogin (RestAPI) in 248.7148ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 805.406ms 302
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET https://localhost:5001/login/linkedin?code=xxx&state=xxx
info: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[10]
AuthenticationScheme: Identity.External signed in.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 1142.4957ms 302
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET https://localhost:5001/login/external?provider=LinkedIn
...
...
...
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET https://localhost:5001/login/external?provider=LinkedIn
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Route matched with {action = "ExternalLogin", controller = "Login"}. Executing action RestAPI.Controllers.LoginController.ExternalLogin (RestAPI)
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Executing action method RestAPI.Controllers.LoginController.ExternalLogin (RestAPI) with arguments (LinkedIn) - Validation state: Valid
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action method RestAPI.Controllers.LoginController.ExternalLogin (RestAPI), returned result Microsoft.AspNetCore.Mvc.ChallengeResult in 0.0104ms.
info: Microsoft.AspNetCore.Mvc.ChallengeResult[1]
Executing ChallengeResult with authentication schemes (LinkedIn).
info: AspNet.Security.OAuth.LinkedIn.LinkedInAuthenticationHandler[12]
AuthenticationScheme: LinkedIn was challenged.
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[2]
Executed action RestAPI.Controllers.LoginController.ExternalLogin (RestAPI) in 2.5893ms
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 4.3076ms 302
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET https://localhost:5001/login/linkedin?code=xxx&state=xxx
info: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[10]
AuthenticationScheme: Identity.External signed in.
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 716.1161ms 302
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1]
Request starting HTTP/1.1 GET https://localhost:5001/login/linkedin?code=xxx&state=xxx
warn: AspNet.Security.OAuth.LinkedIn.LinkedInAuthenticationHandler[15]
'.AspNetCore.Correlation.LinkedIn.OH3a8tiReVSVrkJ9eEUA0eA-W6UDfSJRoO7GyoLLNCo' cookie not found.
info: AspNet.Security.OAuth.LinkedIn.LinkedInAuthenticationHandler[4]
Error from RemoteAuthentication: Correlation failed..
fail: Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware[1]
An unhandled exception has occurred while executing the request.
System.Exception: An error was encountered while handling the remote login. ---> System.Exception: Correlation failed.
--- End of inner exception stack trace ---
at Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler`1.HandleRequestAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.DatabaseErrorPageMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2]
Request finished in 245.3085ms 500 text/html; charset=utf-8
Run Code Online (Sandbox Code Playgroud)
将CookieAuthenticationHandler用户重定向到用户原来的URI,在那里他得到由挑战(我认为,还不能确定重定向为什么不过,我也尝试过检查,如果用户是在认证ExternalLogin行动,以避免当他去上挑战用户此页面,但事实并非如此)。
为了“解决”这两个问题,最终SkipHandler我在收到新票证时通过在上下文中请求来禁用AuthenticationHandler中的SignIn阶段(当AuthenticationHandler验证通过LinkedIn进行的身份验证成功时便完成了此操作):
.AddLinkedIn(options =>
{
options.ClientId = Configuration["authentication:linked-in:client-id"];
options.ClientSecret = Configuration["authentication:linked-in:client-secret"];
options.CallbackPath = new Microsoft.AspNetCore.Http.PathString("/login/linkedin");
options.Events.OnTicketReceived = context =>
{
context.HttpContext.User = context.Principal;
context.SkipHandler();
return Task.CompletedTask;
};
});
Run Code Online (Sandbox Code Playgroud)
我还将Principal上下文中的声明附加到上,HttpContext.User因为在其他情况下我无权访问声明/login/linkedin,并且我需要在那里访问用户LinkedIn ID。
然后,/login/linkedin操作就是通过使用该UserManager.FindByLoginAsync方法的登录提供者查找用户,如果我找不到用户,则创建该用户,最后像我为标准(带密码)用户那样生成JWT。
我最终将用户重定向到SPA的URI(类似:)/external-login-callback#auth_token=XXX&refresh_token=XXX,以便SPA可以将令牌存储在本地存储中,并使用它来认证后续请求。
与该方法有关的第二个问题是,我似乎无法访问LinkedIn为用户提供的令牌(它们似乎没有存储在任何地方,或者也许我不知道在哪里看),所以我无法IdentityUserToken为此外部登录提供程序创建(尽管这似乎不是问题)。
所以最后,我确实有一些工作要做,但是我没有看到任何问题。
但是,我是Web API的新手,我真的不确定这是否是有效/安全的方法。
我的问题是:
access_token从LinkedIn 获得与用户相关的信息?LinkedInAuthenticationHandler已经向LinkedIn API发出了获取用户ID /电子邮件的请求,此令牌的用途是什么?希望这很清楚,我可以得到一些答案,但是如果没有,请不要犹豫,要求精确。
如果您有勇气阅读所有内容(即使您没有阅读!),谢谢!
| 归档时间: |
|
| 查看次数: |
4284 次 |
| 最近记录: |