IdentityServer4
IdentityServer4是用于ASP.NET Core的OpenID Connect和OAuth 2.0框架。
具体大家可以自己搜索,网上很多。我不想写的就推荐别人的。
IdentityServer4(一):概念及基本介绍_江浙沪柯蓝的博客-CSDN博客_identityserver4
IdentityServer4学习及简单使用 - Vincent-yuan - 博客园 (cnblogs.com)
开源地址:IdentityServer/IdentityServer4: OpenID Connect and OAuth 2.0 Framework for ASP.NET Core (github.com)
新版升级
前一篇简单提了一下,今天我整理了一下,IdentityServer4开源已经说明,项目迁移升级了。
我使用了网页翻译。如下:
![](https://i-blog.csdnimg.cn/blog_migrate/f91bb5a4c075b927101566ff07eb2d20.png)
Duende IdentityServer
IdentityServer4的新版本,这里按照以前的方式简单介绍一下使用。
认证服务器,创建WebApi项目,nuget引入Duende.IdentityServer
其实Duende.IdentityServer.AspNetIdentity时与web的集成,有兴趣的自己研究,我没有使用。
![](https://i-blog.csdnimg.cn/blog_migrate/cc4e4b826184aa929de1b82d916e9c12.png)
创建配置类,可以照搬IdentityServer4的,
using Duende.IdentityServer.Models;
using Duende.IdentityServer.Test;
namespace OcelotIdentityServer4
{
/// <summary>
/// 路由 /connect/token post方式 body参数client_id,client_secret,grant_type
/// </summary>
public class Config
{
public static IEnumerable<ApiResource> GetApiResources()
{
return new List<ApiResource>()
{
new ApiResource("api", "My Api"){ Scopes ={"api"} }
};
}
public static IEnumerable<Client> GetClients()
{
return new List<Client>()
{
new Client()
{
ClientId = "ro.client",
AllowedGrantTypes = GrantTypes.ResourceOwnerPasswordAndClientCredentials,
// AccessTokenType = AccessTokenType.Reference,
ClientSecrets =
{
new Secret("123456".Sha256())
},
AllowedScopes =
{
"api"
},
Claims =new List<ClientClaim>()
{
new ClientClaim(IdentityModel.JwtClaimTypes.Role,"admin"),
new ClientClaim(IdentityModel.JwtClaimTypes.NickName,"江北"),
new ClientClaim("Email","**********@163.com"),
}
}
};
}
public static IEnumerable<ApiScope> ApiScopes =>
new ApiScope[] { new ApiScope("api") };
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile()
};
}
public static IEnumerable<TestUser> Users()
{
return new[]
{
new TestUser
{
SubjectId = "",
Username = "mail@qq.com",
Password = "password"
}
};
}
}
}
建立测试类
using Duende.IdentityServer.Models;
using Duende.IdentityServer.Validation;
using System.Security.Claims;
namespace OcelotIdentityServer
{
public class ResourceOwnerPasswordValidator : IResourceOwnerPasswordValidator
{
public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
//根据context.UserName和context.Password与数据库的数据做校验,判断是否合法
if (context.UserName == "yzk" && context.Password == "123")
{
context.Result = new GrantValidationResult(
subject: context.UserName,
authenticationMethod: "custom",
claims: new Claim[] { new Claim("Name", context.UserName), new Claim("UserId", "111"), new Claim("RealName", "杨中科"), new Claim("Email", "yzk365@qq.com") });
}
else
{
//验证失败
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant, "invalid custom credential");
}
}
}
}
using Duende.IdentityServer.Models;
using Duende.IdentityServer.Services;
namespace OcelotIdentityServer
{
public class ProfileService : IProfileService
{
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var claims = context.Subject.Claims.ToList();
context.IssuedClaims = claims.ToList();
}
public async Task IsActiveAsync(IsActiveContext context)
{
context.IsActive = true;
}
}
}
最后加入
builder.Services.AddIdentityServer(options =>
{
options.EmitStaticAudienceClaim = true;
})
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddInMemoryApiScopes(Config.ApiScopes)
.AddInMemoryClients(Config.GetClients())
.AddResourceOwnerValidator<ResourceOwnerPasswordValidator>()
.AddProfileService<ProfileService>();
![](https://i-blog.csdnimg.cn/blog_migrate/76b20a9cb99fb4c87df70546289b18ce.png)
设置好项目绑定的IP端口(19138)
WebApi项目中使用
nuget引入上面相同
program.cs加入
//添加鉴权认证
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
//鉴权中心服务地址
options.Authority = "https://localhost:19138";
options.RequireHttpsMetadata = false;
options.Audience = "api";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
};
});
![](https://i-blog.csdnimg.cn/blog_migrate/ff4759070becef590bdb7e4df71694f9.png)
还得继续加入
app.UseAuthentication();
创建一个控制器
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace ConsulForProject.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
[Authorize]
[HttpGet]
public IEnumerable<WeatherForecast> Getm()
{
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
})
.ToArray();
}
}
}
这样就可以用postman工具测试了
启动认证中心和api项目。
访问https://localhost:19138/connect/token 获取token
![](https://i-blog.csdnimg.cn/blog_migrate/8e6146f0d7b7ef21b3d9a0014cc443ab.png)
访问api:
![](https://i-blog.csdnimg.cn/blog_migrate/57c27b89c0035186c74ff3e21688a871.png)
ocelot集成
项目引入
![](https://i-blog.csdnimg.cn/blog_migrate/50aab586e91c582b43e1bc90c1d66781.png)
program.cs加入
//添加鉴权认证
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer("AuthKey", options =>
{
//鉴权中心服务地址
options.Authority = "https://localhost:19138";
options.RequireHttpsMetadata = false;
options.Audience = "api";
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateAudience = false
};
});
配置文件
![](https://i-blog.csdnimg.cn/blog_migrate/152217ac42211c9b7aa237fa76685915.png)
测试ocelot
![](https://i-blog.csdnimg.cn/blog_migrate/75a10bdf9c1ebf83abf1fcdac04418a4.png)
扩展 建立登录项目
创建一个login项目,在其中登录并且获取token.
项目里面我用了EF dbfirst方式查询数据库。
数据库:mysql
我不详细写EF使用了。这里推荐博客。
完成后
![](https://i-blog.csdnimg.cn/blog_migrate/2d60dc76b0efb448e34de2103fe2e15a.png)
创建登录控制器
using LoginService.Repository;
using Microsoft.AspNetCore.Mvc;
namespace LoginService.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class LoginController : ControllerBase
{
private readonly ILogger<LoginController> _logger;
private IConfiguration _IConfiguration;
private readonly MytestContext _context;
public LoginController(ILogger<LoginController> logger, IConfiguration configuration, MytestContext context)
{
_logger = logger;
_IConfiguration = configuration;
_context = context;
}
[HttpPost]
public async Task<ActionResult> RequestToken(RequestTokenParam model)
{
this._logger.LogInformation($"{this._IConfiguration["port"]}- Login Token!");
var usr = _context.Users.FirstOrDefault(user => user.Username == model.username);
Dictionary<string, string> dict = new Dictionary<string, string>();
dict["client_id"] = "ro.client";
dict["client_secret"] = "123456";
dict["grant_type"] = "password";
dict["username"] = usr.Username;
dict["password"] = usr.Password;
//由登录服务器向IdentityServer发请求获取Token
using (HttpClient http = new HttpClient())
using (var content = new FormUrlEncodedContent(dict))
{
var msg = await http.PostAsync("https://localhost:19138/connect/token", content);
string result = await msg.Content.ReadAsStringAsync();
return Content(result, "application/json");
}
}
}
}
namespace LoginService
{
public class RequestTokenParam
{
public string? username { get; set; }
public string? password { get; set; }
}
}
使用postman测试
![](https://i-blog.csdnimg.cn/blog_migrate/5974420256e25765ee9691a54b7ef253.png)
这样通过登录返回token,就可以继续访问了。
今天就补充这么多。