首页 新闻 会员 周边

ASP.NET Core SPA 应用登录验证问题

0
悬赏园豆:30 [已解决问题] 解决于 2023-08-17 12:27

想实现这样的登录验证,当当前请求是通过 SPA 的 index.html 静态响应的,在服务端验证当前用户是否已登录,未登录跳转到登录页,请问如何实现?

dudu的主页 dudu | 高人七级 | 园豆:30994
提问于:2023-08-16 16:29
< >
分享
最佳答案
0

通过下面的代码实现,准备庆祝成功的时候,被一个问题泼了一盆冷水

public void Configure(IApplicationBuilder app)
{
    app.UseSpa(spa =>
    {
        spa.Options.DefaultPageStaticFileOptions = new StaticFileOptions
        {
            OnPrepareResponse = PrepareResponse
        };
    });
}

private static void PrepareResponse(StaticFileResponseContext fileContext)
{
    if (fileContext == null) return;

    var headers = fileContext.Context.Response.Headers;
    headers.Remove("cache-control");
    headers.Add("cache-control", "no-store, no-cache, must-revalidate");

    var httpContext = fileContext.Context;
    if (!httpContext.User.Identity.IsAuthenticated)
    {
        httpContext.Response.ContentLength = 0;
        httpContext.Response.Body = Stream.Null;
        var signInUrl = SignInUrl + WebUtility.UrlEncode(httpContext.Request.GetDisplayUrl());
        httpContext.Response.Redirect(signInUrl);
    }
}

UseSpa 所使用的 SpaDefaultPageMiddleware 修改了 Request.Path,造成了跳转到登录页时无法提供原始的请求地址,以下是 SpaDefaultPageMiddleware 对应的实现代码

// Rewrite all requests to the default page
app.Use((context, next) =>
{
    // If we have an Endpoint, then this is a deferred match - just noop.
    if (context.GetEndpoint() != null)
    {
        return next(context);
    }

    context.Request.Path = options.DefaultPage;
    return next(context);
});
dudu | 高人七级 |园豆:30994 | 2023-08-17 08:13

通过引入一个 middleware 保存原始请求 url 解决了

public class AdminSpaMiddleware
{
    public const string OriginRequestUrl = nameof(OriginRequestUrl);
    private readonly RequestDelegate _next;

    public AdminSpaMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public Task Invoke(HttpContext httpContext)
    {
        if (httpContext.GetEndpoint() is null)
        {
            httpContext.Items[OriginRequestUrl] = httpContext.Request.GetDisplayUrl();
        }

        return _next(httpContext);
    }
}

app.UseSpa() 之前添加这个中间件

app.UseAdminSpaMiddleware();

PrepareResponse 方法中通 HttpContext.Items 获取原始请求 url

private static void PrepareResponse(StaticFileResponseContext fileContext)
{
    var httpContext = fileContext.Context;
    if (!httpContext.User.Identity.IsAuthenticated)
    {
        httpContext.Response.ContentLength = 0;
        httpContext.Response.Body = Stream.Null;
        var returnUrl = WebUtility.UrlEncode(httpContext.Items[AdminSpaMiddleware.OriginRequestUrl] as string ?? string.Empty);
        var signInUrl = SignInUrl + returnUrl;
        httpContext.Response.Redirect(signInUrl);
    }
}
dudu | 园豆:30994 (高人七级) | 2023-08-17 12:27
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册