修改接口项目
在上次的项目基础上,分别修改两个api项目的startup.cs
public void ConfigureServices(IServiceCollection services)
{
var audienceConfig = Configuration.GetSection("Audience");
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(audienceConfig["Secret"]));
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
ValidateIssuer = true,
ValidIssuer = audienceConfig["Iss"],
ValidateAudience = true,
ValidAudience = audienceConfig["Aud"],
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero,
RequireExpirationTime = true,
};
services.AddAuthentication(o =>
{
o.DefaultAuthenticateScheme = "TestKey";
})
.AddJwtBearer("TestKey", x =>
{
x.RequireHttpsMetadata = false;
x.TokenValidationParameters = tokenValidationParameters;
});
//services.AddConsulConfig(Configuration);
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
修改配置文件
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
//"Consul": {
// "Host": "http://192.168.2.29:8500"
//},
"Service": {
"Name": "ApiService",
"IP": "192.168.2.16",
"Port": "9001"
},
"Consul": {
"IP": "192.168.2.29",
"Port": "8500"
},
"Audience": {
"Secret": "Y2F0Y2hlciUyMHdvbmclMjBsb3ZlJTIwLm5ldA==",
"Iss": "http://www.c-sharpcorner.com/members/catcher-wong",
"Aud": "Catcher Wong"
}
}
在接口的action中加入[Authorize]属性
[Authorize]
[HttpGet]
public string Count()
{
return $"Count {++_count} from ApiServices1";
}
加入IdentityServer4
新建webapi项目 ,nuget安装identityserver。将authapi项目也加入到consul中。所以要新建health控制器,新建一个授权控制器,修改startup.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Test.WebApi.AuthServer.Controllers
{
[Produces("application/json")]
[Route("api/[controller]")]
[ApiController]
public class HealthController : ControllerBase
{
[HttpGet]
public IActionResult Get() => Ok("ok");
}
}
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
namespace Test.WebApi.AuthServer.Controllers
{
[Route("authapi/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
private IOptions<Audience> _settings;
public AuthController(IOptions<Audience> settings)
{
this._settings = settings;
}
[HttpGet]
public ActionResult Get(string name, string pwd)
{
//just hard code here.
if (name == "catcher" && pwd == "123")
{
var now = DateTime.UtcNow;
var claims = new Claim[]
{
new Claim(JwtRegisteredClaimNames.Sub, name),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.Iat, now.ToUniversalTime().ToString(), ClaimValueTypes.Integer64)
};
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_settings.Value.Secret));
var tokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
ValidateIssuer = true,
ValidIssuer = _settings.Value.Iss,
ValidateAudience = true,
ValidAudience = _settings.Value.Aud,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero,
RequireExpirationTime = true,
};
var jwt = new JwtSecurityToken(
issuer: _settings.Value.Iss,
audience: _settings.Value.Aud,
claims: claims,
notBefore: now,
expires: now.Add(TimeSpan.FromMinutes(2)),
signingCredentials: new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256)
);
var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);
var responseJson = new
{
access_token = encodedJwt,
expires_in = (int)TimeSpan.FromMinutes(2).TotalSeconds
};
return new JsonResult(responseJson);
}
else
{
return new JsonResult("");
}
}
}
public class Audience
{
public string Secret { get; set; }
public string Iss { get; set; }
public string Aud { get; set; }
}
}
修改 startup.cs
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddOptions();
services.Configure<Controllers.Audience>(Configuration.GetSection("Audience"));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime lifetime)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
ConsulService consulService = new ConsulService()
{
IP = Configuration["Consul:IP"],
Port = Convert.ToInt32(Configuration["Consul:Port"])
};
HealthService healthService = new HealthService()
{
IP = Configuration["Service:IP"],
Port = Convert.ToInt32(Configuration["Service:Port"]),
Name = Configuration["Service:Name"],
};
app.RegisterConsul(lifetime, healthService, consulService);
app.UseHttpsRedirection();
app.UseMvc();
}
配置文件
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"Service": {
"Name": "AuthService",
"IP": "192.168.2.16",
"Port": "9003"
},
"Consul": {
"IP": "192.168.2.29",
"Port": "8500"
},
"Audience": {
"Secret": "Y2F0Y2hlciUyMHdvbmclMjBsb3ZlJTIwLm5ldA==",
"Iss": "http://www.c-sharpcorner.com/members/catcher-wong",
"Aud": "Catcher Wong"
}
}
发布后,部署到IIS中,端口9003
参考链接:
https://www.cnblogs.com/xlxr45/p/11321134.html
修改网关项目
配置文件configuration.json
{
"ReRoutes": [
{
"UseServiceDiscovery": true,
"DownstreamPathTemplate": "/api/{url}",
"DownstreamScheme": "http",
"ServiceName": "ApiService",
"LoadBalancerOptions": {
"Type": "RoundRobin"
},
"UpstreamPathTemplate": "/api/{url}",
"UpstreamHttpMethod": [ "Get" ],
"ReRoutesCaseSensitive": false
},
{
"UseServiceDiscovery": true,
"DownstreamPathTemplate": "/authapi/{url}",
"DownstreamScheme": "http",
"ServiceName": "AuthService",
"LoadBalancerOptions": {
"Type": "RoundRobin"
},
"UpstreamPathTemplate": "/authapi/{url}",
"UpstreamHttpMethod": [ "Get" ],
"ReRoutesCaseSensitive": false
}
],
"GlobalConfiguration": {
"ServiceDiscoveryProvider": {
"Host": "192.168.2.29",
"Port": 8500,
"Type": "PollConsul",
"PollingInterval": 100
}
}
}
运行效果
新建一个cmd项目,测试下
class Program
{
static void Main(string[] args)
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Clear();
client.BaseAddress = new Uri("http://localhost:9000");
// 1. without access_token will not access the service
// and return 401 .
var resWithoutToken = client.GetAsync("/api/Counter/Count").Result;
Console.WriteLine($"Sending Request to /api/Counter/Count , without token.");
Console.WriteLine($"Result : {resWithoutToken.StatusCode}");
//2. with access_token will access the service
// and return result.
client.DefaultRequestHeaders.Clear();
Console.WriteLine("\nBegin Auth....");
var jwt = GetJwt();
Console.WriteLine("End Auth....");
Console.WriteLine($"\nToken={jwt}");
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {jwt}");
var resWithToken = client.GetAsync("/api/Counter/Count").Result;
Console.WriteLine($"\nSend Request to /api/Counter/Count , with token.");
Console.WriteLine($"Result : {resWithToken.StatusCode}");
Console.WriteLine(resWithToken.Content.ReadAsStringAsync().Result);
//3. visit no auth service
Console.WriteLine("\nNo Auth Service Here ");
client.DefaultRequestHeaders.Clear();
var res = client.GetAsync("/api/Counter/Count").Result;
Console.WriteLine($"Send Request to /api/Counter/Count");
Console.WriteLine($"Result : {res.StatusCode}");
Console.WriteLine(res.Content.ReadAsStringAsync().Result);
Console.Read();
}
private static string GetJwt()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri( "http://localhost:9000");
client.DefaultRequestHeaders.Clear();
var res2 = client.GetAsync("/authapi/auth?name=catcher&pwd=123").Result;
dynamic jwt = JsonConvert.DeserializeObject(res2.Content.ReadAsStringAsync().Result);
return jwt.access_token;
}
}

postman测试下。
先获取access_token

将access_token放到header中

如果不加入header中,则会报500错误
