在 IdentityServer4入門一 咱們準備好了一個認證的服務端,這裏作一個須要保護的API服務html
首先,向解決方案新增一個項目。咱們一樣使用入門一的方式新增一個asp.net core Web程序(模型視圖控制器)ios
一樣的將端口修改一下,API的端口咱們使用44301。打開Properties\launchSettings.json文件web
利用nuget安裝引用json
Microsoft.AspNetCore.Authentication.JwtBearerapi
新增控制器瀏覽器
在controlers目錄下新增「API控制器-空」,名爲:IdentityController安全
[Route("api/[controller]")] [ApiController]
[Authorize] public class IdentityController : ControllerBase { [HttpGet] public IActionResult Get() { return new JsonResult(from c in User.Claims select new { c.Type, c.Value }); } }
修改startup.cs服務器
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.HttpsPolicy; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; namespace API { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); //增長這一段 services.AddAuthentication("Bearer") .AddJwtBearer("Bearer", options => { options.Authority = "https://localhost:44300"; //options.RequireHttpsMetadata = false; options.Audience = "api1"; }); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Home/Error"); // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } app.UseAuthentication();//增長這一句 app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); }); } } }
以上代碼聲明要使用JWTBearer認證做爲安全方式。Bearer認證(也叫作令牌認證)是一種HTTP認證方案,其中包含的安全令牌的叫作Bearer Token。所以Bearer認證的核心是Token。那如何確保Token的安全是重中之重。一種方式是使用Https,另外一種方式就是對Token進行加密簽名。而JWT就是一種比較流行的Token編碼方式。網絡
Json web token (JWT), 是爲了在網絡應用環境間傳遞聲明而執行的一種基於JSON的開放標準(RFC 7519)。該token被設計爲緊湊且安全的,特別適用於分佈式站點的單點登陸(SSO)場景。JWT的聲明通常被用來在身份提供者和服務提供者間傳遞被認證的用戶身份信息,以便於從資源服務器獲取資源,也能夠增長一些額外的其它業務邏輯所必須的聲明信息,該token也可直接被用於認證,也可被加密。app
JWT有三部分組成:
<header>.<payload>.<signature>
alg
和typ
組成,alg
是algorithm的縮寫,typ
是type的縮寫,指定token的類型。該部分使用Base64Url
編碼。BaseURL
編碼。好了,如今試試調試運行,並在地址欄錄入 https://localhost:44301/api/identity ,固然你在IE看的話,什麼都看不到,空白的一頁,其實瀏覽器收到服務器的錯誤碼401。
爲了進一步驗證,下面寫一個console的程序調用一下這個API
新增項目:控制檯應用(.NET core),名爲:ClientConsole
利用nuget安裝如下引用
IdentityServer4
修改主方法以下
static async Task Main(string[] args) { //Console.WriteLine("Hello World!"); var client = new HttpClient(); string token = "empty token"; client.SetBearerToken(token); var response = await client.GetAsync("https://localhost:44301/api/identity"); if (!response.IsSuccessStatusCode) { Console.WriteLine(response.StatusCode); } else { var content = await response.Content.ReadAsStringAsync(); Console.WriteLine(JArray.Parse(content)); } }
以上程序結果是response.IsSuccessStatusCode==false,因此直接打印respone.StatusCode
如下代碼是完整的過程:向44300受權訪問"api1",獲得token後,訪問44301的api/identity
using IdentityModel.Client; using Newtonsoft.Json.Linq; using System; using System.Net.Http; using System.Threading.Tasks; namespace ClientConsole { class Program { static async Task Main(string[] args) { //Console.WriteLine("Hello World!"); var client = new HttpClient(); // discover endpoints from metadata var disco = await client.GetDiscoveryDocumentAsync("https://localhost:44300"); if (disco.IsError) { Console.WriteLine(disco.Error); return; } // request token var tokenResponse = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest { Address = disco.TokenEndpoint, ClientId = "client", ClientSecret = "secret", Scope = "api1" }); if (tokenResponse.IsError) { Console.WriteLine(tokenResponse.Error); return; } // call api string tokenStr = tokenResponse.AccessToken; //string tokenStr = "test"; var apiClient = new HttpClient(); apiClient.SetBearerToken(tokenStr); var response = await apiClient.GetAsync("https://localhost:44301/api/identity"); if (!response.IsSuccessStatusCode) { Console.WriteLine(response.StatusCode); } else { var content = await response.Content.ReadAsStringAsync(); Console.WriteLine(JArray.Parse(content)); } } } }
正常的話,應能看到相似內容