创建一个被授权保护的API

采用 .net cli 创建一个API应用

$ dotnet new webapi -n api1 -o E:\github\dotnet\refine-api1

-n 指明API的名称
-o 输出目录

注意修改Properties/launchSettings.json 中的绑定地址,修改之前的 http://localhost:5001 为 http://0.0.0.0:5001, 也是之前在Docker容器运行出现绑定异常无法处理,才如此处理。

{ 
  "profiles": {
    "api1": {
      "commandName": "Project",
      "launchBrowser": true,
      "applicationUrl": "http://0.0.0.0:5001",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

创建控制器

[Route("identity")]
[Authorize]
public class IdentityController : ControllerBase
{
    [HttpGet]
    public IActionResult Get()
    {
        return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
    }
}

该REST方法会在后面用来测试用户权限验证,验证通过输出用户信息中的所有声明事项。

应用配置

最后一步就是在HTTP管道中添加验证服务和授权中间件,这些主要处理两方面的事情:

  • 校验令牌是颁发自合法的授权服务
  • 校验令牌拥有使用API的权限

更新 Startup.cs 代码

using Microsoft.AspNetCore.Authentication.JwtBearer;

public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {    
                services.AddMvc();
                services.AddAuthentication(options =>
                {
                    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

                }).AddJwtBearer(options =>
                {  
                    options.Authority = IdentityServerBaseUrl; //验证服务地址
                    options.RequireHttpsMetadata = false;
                    options.Audience = "UserAPI"; // API 的名字
                });
        }

        public void Configure(IApplicationBuilder app)
        {
            app.UseAuthentication();

            app.UseMvc();
        }
    }

通过AddAuthentication 依赖注入验证服务,配置Bearer作为默认的验证模式,这样每次调用API时都会进行自动验证。
如果你通过浏览器访问控制器(http://localhost:5001/identity),就是返回401的错误,这表明API的调用需要一个凭证。

这个API就在IdentityServer4的保护下了。

上述代码不支持CORS,但上传Github的源码已经增加CORS支持。
源码地址:https://github.com/daijinming/refine-api1


测试API

第一步请求 access_token

创建一个被授权保护的API_第1张图片
Postman

输入参数

POST /connect/token HTTP/1.1
Host: 114.116.96.150:5000
Cache-Control: no-cache
Postman-Token: d7c7d2dd-1f8e-fb68-5e9c-d811f4cd13ed
Content-Type: application/x-www-form-urlencoded

client_id=pwdClient&client_secret=superSecretPassword&grant_type=password&scope=api1&username=demo%40qq.com&password=!1Demo

这里特别强调的是登录时请求 jwt时,务必在 scope 中输入 api1,也就是API的编码

输出参数

{
  "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjBBODE1Rjg2RENENzJDNjJCOTVDQjkxQkIwNDk1MTY5QTNERTNDQkQiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJDb0ZmaHR6WExHSzVYTGtic0VsUmFhUGVQTDAifQ.eyJuYmYiOjE1NDcwMjc0MjAsImV4cCI6MTU0NzAzMTAyMCwiaXNzIjoiaHR0cDovLzExNC4xMTYuOTYuMTUwOjUwMDAiLCJhdWQiOlsiaHR0cDovLzExNC4xMTYuOTYuMTUwOjUwMDAvcmVzb3VyY2VzIiwiYXBpMSJdLCJjbGllbnRfaWQiOiJwd2RDbGllbnQiLCJzdWIiOiI5OTdkMjc1Yi1lMTZkLTQxOWQtOGUxNS05ZmIwZjg2M2RjMzgiLCJhdXRoX3RpbWUiOjE1NDcwMjc0MjAsImlkcCI6ImxvY2FsIiwic2NvcGUiOlsiYXBpMSJdLCJhbXIiOlsicHdkIl19.gEKY6BTKcuYA3YKalBNAunZNeSTirYP3qrZ7pjYKrN8PRFs5SRjNJ1dHciI4VBcXA9zQgSynF8B2HTqEr8sZ2h2BjxxdqB3AARkctviFKtUGB-tFiYN2YJOZBid-UgBdHolhKcVLnia4LVKW4u8NXnYVO9dKFncIXiMU6c0Le__txfbLsw2lUW2aza1mz-vJAJy3aZ0U8_eUuA0DiglGsZA3eBmx7f05WadSyreyg0dQOBSjqBFfwVKCdO0jm402PLN3r5W-i2EZpszQYQBgLLrVkfT4MN7ns44gHTpSYOGkXec2-hGe1WM0mnCzDZeI58v_OotyYuaS7ebzcpPZJQ",
  "expires_in": 3600,
  "token_type": "Bearer"
}

通过 jwt.io 对 access_token 进行解码

{
  "nbf": 1547027420,
  "exp": 1547031020,
  "iss": "http://114.116.96.150:5000",
  "aud": [
    "http://114.116.96.150:5000/resources",
    "api1"
  ],
  "client_id": "pwdClient",
  "sub": "997d275b-e16d-419d-8e15-9fb0f863dc38",
  "auth_time": 1547027420,
  "idp": "local",
  "scope": [
    "api1"
  ],
  "amr": [
    "pwd"
  ]
}

第二步模拟调用API

创建一个被授权保护的API_第2张图片
Postman

输入参数

GET /identity HTTP/1.1
Host: localhost:5001
Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjBBODE1Rjg2RENENzJDNjJCOTVDQjkxQkIwNDk1MTY5QTNERTNDQkQiLCJ0eXAiOiJKV1QiLCJ4NXQiOiJDb0ZmaHR6WExHSzVYTGtic0VsUmFhUGVQTDAifQ.eyJuYmYiOjE1NDcwMjczMzAsImV4cCI6MTU0NzAzMDkzMCwiaXNzIjoiaHR0cDovLzExNC4xMTYuOTYuMTUwOjUwMDAiLCJhdWQiOlsiaHR0cDovLzExNC4xMTYuOTYuMTUwOjUwMDAvcmVzb3VyY2VzIiwiYXBpMSJdLCJjbGllbnRfaWQiOiJwd2RDbGllbnQiLCJzdWIiOiI5OTdkMjc1Yi1lMTZkLTQxOWQtOGUxNS05ZmIwZjg2M2RjMzgiLCJhdXRoX3RpbWUiOjE1NDcwMjczMzAsImlkcCI6ImxvY2FsIiwic2NvcGUiOlsiYXBpMSJdLCJhbXIiOlsicHdkIl19.mS_tnJcbRwUedObdit1xoceQaGYc3uzTH3w1VnwWe3CdY7saothpIng_z_zTdgelmDSJNsXxkQiH9mDf-tZZjxxO_wCgvhrw3gKhERlVRMrc7jr_OnvSkvoidH5guqo1CBff4Bp7g6HPRAPx2H7eNk26QXJD2vs_1i8GqD3qLVwPd8sclYjLzXyWXRhOLhQ2B9L5vmJT7ztRbzPa_5FAdq_vfLPxbviDXQ6Py0ne_Ll-U6KHPF-Vq5Y7PbhsDFuQ0tWSYMXHh2aREttbjEdIHPAWeW4WYQFdQxPtpbXabZ1VZ6fLgSBB5OTLwmar3E3eobbHlO6_6RgjdH56COF1Fw
Cache-Control: no-cache
Postman-Token: f3a8d84b-1a37-b160-f729-4c1f0dc892d2

输出结果

[
  {
    "type": "nbf",
    "value": "1547027330"
  },
  {
    "type": "exp",
    "value": "1547030930"
  },
  {
    "type": "iss",
    "value": "http://114.116.96.150:5000"
  },
  {
    "type": "aud",
    "value": "http://114.116.96.150:5000/resources"
  },
  {
    "type": "aud",
    "value": "api1"
  },
  {
    "type": "client_id",
    "value": "pwdClient"
  },
  {
    "type": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier",
    "value": "997d275b-e16d-419d-8e15-9fb0f863dc38"
  },
  {
    "type": "auth_time",
    "value": "1547027330"
  },
  {
    "type": "http://schemas.microsoft.com/identity/claims/identityprovider",
    "value": "local"
  },
  {
    "type": "scope",
    "value": "api1"
  },
  {
    "type": "http://schemas.microsoft.com/claims/authnmethodsreferences",
    "value": "pwd"
  }
]

你可能感兴趣的:(创建一个被授权保护的API)