一个 MVC Web 应用程序作为 API 和客户端

Posted

技术标签:

【中文标题】一个 MVC Web 应用程序作为 API 和客户端【英文标题】:One MVC web application as API and client 【发布时间】:2018-08-21 13:54:40 【问题描述】:

我有一个 MVC Web 应用程序、一个 WPF 客户端和 Web API 服务器。我非常想将 API 控制器拉入 MVC 应用程序,并且只有一个应用程序/api。我这样做的主要原因是为应用程序用户和 API 客户端等提供一个登录程序。

我想做的是将SignInManager<ApplicationUser 注入Token 控制器并使用

var result = await _signInManager.PasswordSignInAsync(login.Username, login.Password, false, false);

使用与构建到 MVC 项目中相同的密码哈希来验证用户名和密码。我不想复制任何此类功能。我也希望通过这个实现登录,提供 JWT 令牌,以便 WPF 应用程序访问 API 端,以及标准登录 cookie,以便授权正常的 MVC 应用程序请求。

我应该如何以最少的代码重复来解决这个问题?

想法: 也可以使用一个 MVC 应用程序作为 REST 服务器。如果我获得 JWT 的 Login 操作也让我登录,例如使用_signInManager.PasswordSignInAsync,我还应该获取允许我在内部访问受保护操作的cookie,并在外部使用包含JWT 的授权标头。

【问题讨论】:

基本上,您应该将所有通用代码分解到两个项目都可以使用的类库中。这可能意味着移动所有实体、上下文、身份设置等。您不需要单独的帐户;可以在多个不同场景中以多种方式对单个用户进行身份验证/授权。出于某种原因,该部分与实际帐户持久性是分开的。但是,如果你想使用 JWT 之类的东西,你可能需要做一些手动工作。 使用 IdentityServer 之类的东西可能会更好,它可以分散您的身份验证和授权,并开箱即用地处理多个不同的身份验证工作流。 以上cmets是在我完全修改问题之前制作的,以防有人质疑相关性。 @ProfK 这绝对是可行的。只是有很多事情要做。使用身份共享 MVC 和 Web API 的整体 Web 应用程序是可能的。我这么说是因为我以前做过。这就是为什么我说有很多事情要做。范围太广,无法在此介绍。 MVC 应用和 API 是否都在运行 ASP.NET Core? 【参考方案1】:

您可以考虑以下选项

选项 #1:将 MVC 应用程序中使用的逻辑移动到新的类库中,然后 API 项目可以引用该类库。这将允许您遵循 SRP 并在 MVC 和 API 应用程序中使用相同的逻辑。如果您想让 ASP.NET Identity 相关功能对 MVC 和 API 应用程序通用,请查看 Moving ASP.NET Identity Model to Class Library 并按照提供的步骤操作。

选项#2:您可以将所有控制器和模型从 API 移动到 MVC 应用程序。您可以将 API 控制器配置为使用 JWT 身份验证方案,并继续使用 MVC 应用程序控制器的 cookie 身份验证方案。如果您想遵循这种方法,您将需要配置您的身份验证中间件。例如,您的 Startup 类看起来像这样:

public void ConfigureServices(IServiceCollection services)

    ...
    services.AddMvc();

    services.AddAuthentication(o =>
    
        o.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        o.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        o.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    ).AddCookie(options =>
    
        options.AccessDeniedPath = new PathString("/Account/Login/");
        options.LoginPath = new PathString("/Account/Login/");
    ).AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options => 
        options.TokenValidationParameters = new TokenValidationParameters 
               
            ValidateAudience = false,
            ValidateIssuer = false,
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("<put_your_secret_here>")),
            ValidateLifetime = true,
            ClockSkew = TimeSpan.FromMinutes(5)            
        ;
    );


public void Configure(IApplicationBuilder app, IHostingEnvironment env)

    ...
    app.UseAuthentication();
    app.UseMvcWithDefaultRoute();
    ...
    

然后您可以定义BaseApiController,它可用于设置到 API 控制器的路由并使用例如授权它们

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Route("api/[controller]")]
public abstract class BaseApiController 

并使所有 API 控制器都继承此基本控制器。您还可以使用更灵活的基于策略的授权。完成后,您将能够使用 MVC 应用控制器中的 cookie 和 API 控制器中的 JWT 令牌进行身份验证。

选项#3:您可以让 API 和 MVC 应用程序分开运行,并使用 IdentityServer 来实现 OAuth 协议。将其添加到 MVC 应用程序,因为它与 ASP.NET Identity 很好地集成并对其进行配置,以便继续使用 MVC 应用程序的 cookie 身份验证方案。然后配置 OAuth 流之一以设置 WPF 应用程序和 API 之间的授权。 IdentityServer 有据可查,并为不同的流程提供示例in their GitHub。这种方法的优点是,即使您考虑添加更多必须使用相同用户群的 API、SPA 或 MVC 应用程序,您将来也不会遇到此类问题。它还允许实现单点登录 (SSO),因此如果您需要另一个 MVC 应用程序,它可以很容易地集成到现有的基础架构中。

【讨论】:

感谢您提供全面的答案,但是,选项 #2 的一部分,我的首选选项,具有代码 new TokenValidationParameters ...... 是什么? 我已经更新了我的答案,举例说明如何设置TokenValidationParameters

以上是关于一个 MVC Web 应用程序作为 API 和客户端的主要内容,如果未能解决你的问题,请参考以下文章

用于客户端交互的 web api 或控制器

远程 API/Web 服务层 MVC 的域逻辑和数据访问

ASP MVC 5 在不同域上运行 HTML5 客户端和 Web API 服务器

Web APi Vs MVC 和在 ASP.net 核心 Web APi 中提供静态文件

如何在 Asp.net MVC 中编写 OAuth2 Web API 客户端

针对 web api 中间层的 mvc 身份验证