【发布时间】:2021-12-18 08:03:05
【问题描述】:
关于 OAuth。
- 前端 SPA 反应
- MVC OAuth 后端,将用户登录到 3rd 方提供商,运行良好,返回令牌。
从我的 SPA 中,我可以执行 window.open 并将用户重定向到登录页面,注意:必须是一个新窗口,因为 xframeoptions 设置为拒绝。
我如何返回令牌并与 SPA 关联,因为它们位于不同的窗口/会话中?
我正在查看的选项
- 内容安全政策 - 设置调用者的域
- 设置相同的网站 cookie
使用aspnet-contrib/AspNet.Security.OAuth.Providers
Startup.cs
public class Startup
{
private const string policyName = "Cors";
public Startup(IConfiguration configuration, IHostEnvironment hostingEnvironment)
{
Configuration = configuration;
HostingEnvironment = hostingEnvironment;
}
public IConfiguration Configuration { get; }
private IHostEnvironment HostingEnvironment { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddRouting();
services.AddCors(opt =>
{
opt.AddPolicy(name: policyName, builder =>
{
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyOrigin()
.AllowAnyMethod();
});
});
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
options.LoginPath = "/signin";
options.LogoutPath = "/signout";
})
.AddGitHub(options =>
{
options.ClientId = Configuration["GitHub:ClientId"];
options.ClientSecret = Configuration["GitHub:ClientSecret"];
options.Scope.Add("user:email");
options.Scope.Add("read:org");
options.Scope.Add("workflow");
options.SaveTokens=true;
});
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
if (HostingEnvironment.IsDevelopment())
{
// IdentityModelEventSource.ShowPII = true;
}
// Required to serve files with no extension in the .well-known folder
//var options = new StaticFileOptions()
//{
// ServeUnknownFileTypes = true,
//};
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto,
});
app.UseCors(policyName);
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
});
身份验证控制器
public class AuthenticationController : Controller
{
[HttpGet("~/signin")]
public async Task<IActionResult> SignIn() => View("SignIn", await HttpContext.GetExternalProvidersAsync());
[HttpPost("~/signin")]
public async Task<IActionResult> SignIn([FromForm] string provider)
{
// Note: the "provider" parameter corresponds to the external
// authentication provider choosen by the user agent.
if (string.IsNullOrWhiteSpace(provider))
{
return BadRequest();
}
if (!await HttpContext.IsProviderSupportedAsync(provider))
{
return BadRequest();
}
// Instruct the middleware corresponding to the requested external identity
// provider to redirect the user agent to its own authorization endpoint.
// Note: the authenticationScheme parameter must match the value configured in Startup.cs
return Challenge(new AuthenticationProperties { RedirectUri = "/" }, provider);
}
[HttpGet("~/signout")]
[HttpPost("~/signout")]
public IActionResult SignOutCurrentUser()
{
// Instruct the cookies middleware to delete the local cookie created
// when the user agent is redirected from the external identity provider
// after a successful authentication flow (e.g Google or Facebook).
return SignOut(new AuthenticationProperties { RedirectUri = "/" },
CookieAuthenticationDefaults.AuthenticationScheme);
}
}
家庭控制器
public class HomeController : Controller
{
public async Task<IActionResult> IndexAsync()
{
var accessToken = await HttpContext.GetTokenAsync("GitHub", "access_token");
var refreshToken = await HttpContext.GetTokenAsync("GitHub", "refresh_token");
return View();
}
}
主页(Index.cshtml)
<div class="jumbotron">
@if (User?.Identity?.IsAuthenticated ?? false)
{
<h1>Welcome, @User.Identity.Name</h1>
<p>
@foreach (var claim in Context.User.Claims)
{
<div><code>@claim.Type</code>: <strong>@claim.Value</strong></div>
}
</p>
<a class="btn btn-lg btn-danger" href="/signout?returnUrl=%2F">Sign out</a>
}
else
{
<h1>Welcome, anonymous</h1>
<a class="btn btn-lg btn-success" href="/signin?returnUrl=%2F">Sign in</a>
}
</div>
感谢观看
【问题讨论】:
-
#1 您的 oauth 服务器功能是否嵌入在您的微服务中? #2 什么是NB? #3 您是否在严格使用一些 oauth2 流程,例如授权授予? #4 为什么需要打开一个新窗口? Gmail、Microsoft、LinkedIn 等不这样做。
-
@JRichardsz,感谢您的回复,我已经发布了一些代码,一直在使用上面示例链接中的示例,不确定它是什么类型的授权,没有说我能看到的任何地方,我尝试使用 iframe 并获得 X-Frame-Options:DENY ?
-
您附加的示例是针对客户的,而不是针对 oauth 提供者的。用户成功登录后,会发生什么?登录窗口是否关闭?你有重定向路线吗?
-
@JRichardsz,然后它运行一个挑战,登录窗口重定向到主页,我可以获得一个令牌,我添加了身份验证控制器和主页,其中显示了来自令牌的一些声明,谢谢寻找。 )顺便说一句,忽略刷新令牌它只是测试 atm 为空
-
从客户端而不是服务器启动身份验证。当用户点击登录时,表单 React 开始认证,也许第三部分客户端有一个框架,就像微软有 MSAL。身份验证完成后,应用重定向到您的应用,然后您获取 Bearer 令牌。
标签: c# asp.net asp.net-mvc oauth-2.0 single-page-application