无法使用 GET 访问 API 个端点

Unable to hit API endpoints with GET

我正在努力构建一个 API 来处理 .NET Core 中的身份信息,但每次我尝试拨打电话时都会收到 404。

当我四处寻找答案时似乎没有任何明确的地方,因为发布的代码似乎很少。以下是我认为相关的所有内容。

控制者:

using Common.Extensions;
using Identity.Database.Contexts.Models;
using Identity.WebApi.Models;
using Identity.WebApi.Models.Tokens;
using Identity.WebApi.Services.Access;
using Identity.WebApi.Services.Accounts;
using Identity.WebApi.Services.Tokens;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;

using Controller = Microsoft.AspNetCore.Mvc.Controller;
using Get = Microsoft.AspNetCore.Mvc.HttpGetAttribute;
using Post = Microsoft.AspNetCore.Mvc.HttpPostAttribute;
using Route = Microsoft.AspNetCore.Mvc.RouteAttribute;

namespace Identity.WebApi.Controllers
{
    [Route("api/[controller]")]
    public class IdentityController : Controller
    {
        private readonly IApplicationUserService _userService;
        private readonly IAccessService _accessService;
        private readonly ITokenService _tokenService;
        private readonly SignInManager<ApplicationUser> _signInManager;

        public IdentityController(IApplicationUserService userService, IAccessService accessService, ITokenService tokenService, SignInManager<ApplicationUser> signInManager)
        {
            _userService = userService;
            _accessService = accessService;
            _tokenService = tokenService;
            _signInManager = signInManager;
        }

        [Get]
        [AllowAnonymous]
        public string Index()
        {
            return new Dictionary<string,string>
            {
                { "status", "live" }
            }.Serialize();
        }

        [Post]
        [Route("create")]
        [AllowAnonymous]
        public Task<ISet<IdentityResult>> Create(string user)
        {
            var decodedUser = DecodeUser(user);

            var applicationUser = new ApplicationUser(new User
            {
                Id = Guid.NewGuid(),
                Name = decodedUser.Username,
                LastActive = DateTime.UtcNow
            });

            return _userService.Add(applicationUser, decodedUser.Password);
        }       

        private (string Username, string Password) DecodeUser(string encodedUser)
        {
            var decodedUser = encodedUser.DecodeFrom64().Split(':');
            return (Username: decodedUser[0], Password: decodedUser[1]);
        }

        private async Task<bool> CheckPasswordAsync(ApplicationUser user, string password)
            => await _signInManager.UserManager.CheckPasswordAsync(user, password);
    }
}

初创公司:

using Identity.Database.Contexts;
using Identity.Database.Contexts.Access;
using Identity.Database.Contexts.Extensions;
using Identity.Database.Contexts.Models;
using Identity.WebApi.Models;
using Identity.WebApi.Services.Access;
using Identity.WebApi.Services.Accounts;
using Identity.WebApi.Services.Certs;
using Identity.WebApi.Services.Tokens;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.Runtime.CompilerServices;

namespace Identity.WebApi
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton(new CertService(Configuration) as ICertService)
                .AddTransient<IApplicationUserService, ApplicationUserService>()
                .AddTransient<IApplicationRoleService, ApplicationRoleService>()
                .AddTransient<IAccessService, AccessService>()
                .AddTransient<ICertService, CertService>()
                .AddTransient<ITokenService, TokenService>()
                .AddTransient<ICrudDao<AppDbContext, Role>, RoleDao>()
                .AddIdentities<ApplicationUser, ApplicationRole>()
                .AddScoped<UserManager<ApplicationUser>, UserManager<ApplicationUser>>()
                .AddScoped<SignInManager<ApplicationUser>, SignInManager<ApplicationUser>>()
                .AddScoped<RoleManager<ApplicationRole>, RoleManager<ApplicationRole>>()
            .AddMvc();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.Use(async (c, n) =>
            {
                await n();

                if (c.Response.StatusCode == 404)
                {
                    c.Request.Path = "/identity";
                    await n();
                }
            });

            app.UseStaticFiles();
            app.UseAuthentication();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            app.UseMvc(r => { r.MapRoute(name: "default", template: "{controller=identity}/{action=Index}"); });
        }
    }
}

启动设置:

{
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:55048/",
      "sslPort": 0
    }
  },
  "profiles": {
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "api/identity/index",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "WebApplication1": {
      "commandName": "Project",
      "launchBrowser": true,
      "launchUrl": "api/identity/index",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      },
      "applicationUrl": "http://localhost:55048/"
    }
  }
}

如果使用属性路由,则没有 api/identity/index,因为 [HttpGet]Get 在您的示例中带有路由前缀,与

相同
[Get] //<-- Matches GET api/identity
[AllowAnonymous]
public IActionResult Index() {
    var result = new Dictionary<string,string>
        {
            { "status", "live" }
        }.Serialize();
    return Ok(result);
}

并且由于这似乎是一个 Web API,预计不会 return 一个视图,因此带有路由模板的 Http{Verb} 属性将是用于路由的选项

When building a REST API, it's rare that you will want to use [Route(...)] on an action method. It's better to use the more specific Http*Verb*Attributes to be precise about what your API supports. Clients of REST APIs are expected to know what paths and HTTP verbs map to specific logical operations.

[Post("create")]  //<-- Matches POST api/identity/create
[AllowAnonymous]
public async Task<IActionResult> Create(string user) {
    var decodedUser = DecodeUser(user);

    var applicationUser = new ApplicationUser(new User
    {
        Id = Guid.NewGuid(),
        Name = decodedUser.Username,
        LastActive = DateTime.UtcNow
    });

    ISet<IdentityResult> result = await _userService.Add(applicationUser, decodedUser.Password);
    return Ok(result);
}

引用Routing to Controller Actions

在控制器的顶部,您有:

[Route("api/[controller]")]
public class IdentityController : Controller

这意味着如果您的路线以 api/ 开头,那么它将匹配控制器。此外,您的 Index 操作没有任何额外的路由属性,因此它仅查找 api/identity 。但是,您的启动设置与该部分不匹配,并且由于您没有任何其他匹配它的路由,您会收到 404。

由于这个原因,app.UseMvc 中的默认路由将不起作用。

简单修复:在您的启动设置中将 launchUrl 更改为 api/identity...然后按照@Nkosi 的