Asp.net core 带有SPA前端的IdentityServer4主机

Asp.net core 带有SPA前端的IdentityServer4主机,asp.net-core,single-page-application,identityserver4,Asp.net Core,Single Page Application,Identityserver4,我试图将identity server 4用作SSO站点,前端编写为SPA(框架不重要) 示例项目使用MVC,当用户登录页面时,MVC将发布到控制器,控制器将浏览器重定向到返回URL 我在修改此流以使其以更AJAX的方式工作时遇到困难。首先,我希望能够将用户名/密码提交给API控制器,以便在不刷新页面的情况下返回验证错误等。如果成功登录,我需要将浏览器重定向到returnUrl,但我无法使其正常工作,回调url会再次将用户返回到登录页面,而不是重定向到已登录的客户端应用 这是我的登录端点的外观:

我试图将identity server 4用作SSO站点,前端编写为SPA(框架不重要)

示例项目使用MVC,当用户登录页面时,MVC将发布到控制器,控制器将浏览器重定向到返回URL

我在修改此流以使其以更AJAX的方式工作时遇到困难。首先,我希望能够将用户名/密码提交给API控制器,以便在不刷新页面的情况下返回验证错误等。如果成功登录,我需要将浏览器重定向到returnUrl,但我无法使其正常工作,回调url会再次将用户返回到登录页面,而不是重定向到已登录的客户端应用

这是我的登录端点的外观:

[HttpPost]
[Route("api/identity/login")]
public async Task<IActionResult> Login(LoginInputModel model)
{
    // check credentials in model etc
    await _eventsService.RaiseAsync(new UserLoginSuccessEvent(model.Email, subjectId, model.Email));
    await HttpContext.SignInAsync(subjectId, model.Email, new AuthenticationProperties());
    return Ok();
}
[HttpPost]
[路由(“api/identity/login”)]
公共异步任务登录(LoginInputModel)
{
//检查模型中的凭据等
wait_eventsService.RaiseAsync(新用户登录成功事件(model.Email,subjectId,model.Email));
等待HttpContext.SignInAsync(subjectId,model.Email,new AuthenticationProperties());
返回Ok();
}
简单表单作为前端,托管在静态html页面上:

<form>
    <label for="email">Email</label>
    <input id="email" type="email" />

    <label for="password">Password</label>
    <input id="password" type="password" />

    <button onclick="login()" type="submit">Log me in</button>
</form>
<script>
    var email = document.querySelector('#email').value;
    var password = document.querySelector('#password').value;
    var returnUrl = unescape(window.location.search.replace('?returnUrl=', ''));
    fetch('/api/identity/login', {
            body: JSON.stringify({ email, password }),
            headers: new Headers({
                'Content-Type': 'application/json'
            }),
            method: 'POST'
    }).then(() => {
        var returnUrl = unescape(window.location.search.replace('?returnUrl=', ''));
        window.location = window.location.origin + returnUrl;
    })
</script>

电子邮件
密码
让我登录
var email=document.querySelector(“#email”).value;
var password=document.querySelector(“#password”).value;
var returnUrl=unescape(window.location.search.replace(“?returnUrl=”,“”));
获取('/api/identity/login'{
正文:JSON.stringify({email,password}),
标题:新标题({
“内容类型”:“应用程序/json”
}),
方法:“发布”
}).然后(()=>{
var returnUrl=unescape(window.location.search.replace(“?returnUrl=”,“”));
window.location=window.location.origin+returnUrl;
})
在200响应中,我使用javascript将浏览器重定向到returnUrl

我不确定我错过了什么才能让它发挥作用。我是否需要在一次呼叫中登录用户并重定向所有呼叫


我正在修改一个现有的示例应用程序,它确实可以像预期的那样使用direct post/redirect方法,因此主机和客户端配置都没有改变:

在调查了一些日志并仔细观察了请求之后,我意识到来自AJAX请求的登录响应并没有在浏览器上设置身份验证cookie

将fetch请求中的
凭证
选项设置为
“同源”
修复了该问题


多亏了这个stackoverflow答案:

您需要提供更多代码。请展示你已经做了什么,而不是你想要实现什么。嗨@Brad,我已经包含了更多的代码。我是否已经足够清楚地解释了这个问题?您是否将路由设置为
路径:“”,组件:LoginComponent
?@k11k2不确定您的意思,因为我正在为站点根目录下的登录ui提供一个静态页面,我已在Startup.cs:
services.AddIdentityServer(options=>{options.UserInteraction.LoginUrl=“/”;})
@dpix,出于兴趣,您将如何处理使用ajax方法部分登录的场景?如2FA、同意、强制密码重置或登录前可能需要的任何操作?