.NET Core OAuth IdentityServer4 AllowAnonymous Policy 白名单 .NET 5 IdentityServer4 4.X版本
jwt.io
最小 API 概述
使用 ASP.NET Core 创建最小 Web API
IdentityServer4 1.0.0 documentation 官网
Token Endpoint
Requesting a token
Requesting a token using the client_credentials Grant Type
Requesting a token using the password Grant Type
Requesting a token using the authorization_code Grant Type
Requesting a token using the refresh_token Grant Type
Requesting a Device Token
Token Introspection Endpoint
Token Revocation Endpoint
UserInfo Endpoint
1、Program.cs
using AuthService;
using AuthService.CoreLibrary;
using AuthService.Filters;
using System.Data;
using System.Data.SqlClient;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
string[] address = builder.Configuration["AppSettings:CorsAddress"].Split(',');
string[] port = builder.Configuration["AppSettings:CorsPort"].Split(',');
builder.Services.Configure<RedisOptions>(builder.Configuration.GetSection("RedisOptions"));
RedisOptions redisOptions = new RedisOptions();
builder.Configuration.Bind("RedisOptions", redisOptions);
string host = redisOptions.Host;
string port = redisOptions.Port;
//加载自定义配置文件
var config = builder.Host.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddJsonFile("CustomConfig.json", optional: true, reloadOnChange: true);
});
//读取 CustomConfig.json 文件 SmtpServer 配置项
var smtp = builder.Configuration["SmtpServer"];
#region 数据库 EF Core
builder.Services.AddDbContext<AssetDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
#endregion
#region 数据库 Dapper
string dbType = builder.Configuration["DbSql:DbType"];
switch (dbType)
{
case "SqlServer":
//builder.Services.AddSingleton(builder.Configuration.GetConnectionString("DefaultConnection"));
builder.Services.AddSingleton(builder.Configuration["DbSql:SqlServerConnection"]);
break;
default:
break;
}
builder.Services.AddSingleton<IDbConnection, SqlConnection>();
builder.Services.AddSingleton<IUserRepository, UserRepository>();
builder.Services.AddSingleton<IUserLogRepository, UserLogRepository>();
builder.Services.AddSingleton<ILogUserLoginRepository, LogUserLoginRepository>();
#endregion
#region
builder.Services.AddIdentityServer(options => { })
.AddDeveloperSigningCredential()
.AddInMemoryClients(AuthService.Security.Clients.GetClients())
.AddInMemoryIdentityResources(AuthService.Security.IdentityConfig.GetIdentityResources())
.AddInMemoryApiResources(AuthService.Security.IdentityConfig.GetResources())
#region ids4 4.X 新特性
.AddInMemoryApiScopes(AuthService.Security.IdentityConfig.GetScopes())
//.AddInMemoryApiScopes(Security.IdentityConfig.ApiScopes)
#endregion
.AddProfileService<AuthService.Security.ProfileService>()
.AddResourceOwnerValidator<AuthService.Security.ResourceOwnerPasswordValidator>();
#endregion
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
#region 跨域访问
string AllowSpecificOrigins = "AllowSpecificOrigins";
var urls = StringPlus.GetCors(address, port);
builder.Services.AddCors(options =>
{
options.AddPolicy(AllowSpecificOrigins, builder =>
{
builder.WithOrigins(urls).AllowAnyMethod().AllowAnyHeader().AllowCredentials();
});
});
#endregion
builder.Services.AddControllers(options =>
{
options.Filters.Add(typeof(CustomExceptionFilter));
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
var summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
app.MapGet("/", () => "Hello World!");
app.MapGet("/api/users/{text}", (string text) => $"{text}");
app.MapGet("/GetData", (IUserRepository userRep) =>
{
return userRep.GetList();
})
.WithName("GetData");
app.MapGet("/api/users/{userId}/books/{bookId}", (int userId, int bookId) => new
{
code = 200,
data = new
{
user = userId,
book = bookId
},
message = ""
});
app.MapGet("/api/weatherforecast", () =>
{
var forecast = Enumerable.Range(1, 5).Select(index => new WeatherForecast
(
DateTime.Now.AddDays(index),
Random.Shared.Next(-20, 55),
summaries[Random.Shared.Next(summaries.Length)]
)).ToArray();
return forecast;
})
.WithName("GetWeatherForecast");
app.UseHttpsRedirection();
app.UseIdentityServer();
app.UseRouting();
app.UseCors(AllowSpecificOrigins);
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.Run();
internal record WeatherForecast(DateTime Date, int TemperatureC, string? Summary)
{
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
}
2、StringPlus.cs
using System.Text;
namespace AuthService.CoreLibrary
{
public class StringPlus
{
public static string[] StringToStrArray(string str)
{
string[] strArray = null;
if (!string.IsNullOrEmpty(str))
{
strArray = str.Split(',');
}
return strArray;
}
public static string[] GetCors(string[] address, string[] port)
{
string[] array = null;
if (address != null && port != null)
{
StringBuilder cors = new StringBuilder();
for (int i = 0; i <= address.Length - 1; i++)
{
for (int j = 0; j <= port.Length - 1; j++)
cors.Append($"{address[i]}:{port[j]},");
}
string url = cors.ToString();
if (!string.IsNullOrEmpty(url))
array = StringToStrArray(url.Substring(0, url.LastIndexOf(",")));
}
return array;
}
}
}
3、RedisOptions.cs
public class RedisOptions
{
public string Host { get; set; }
public string Port { get; set; }
}
4、appsettings.json【注意:TrustServerCertificate=true】
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"Default": "data source=192.168.159.130;initial catalog=dbTest;user id=sa;password=000000;TrustServerCertificate=true;"
}
}
5、.NET 5 IdentityServer4 4.X版本配置【\AuthService\Security\IdentityConfig.cs】
using AuthService.CoreLibrary;
using IdentityServer4.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace AuthService.Security
{
public class IdentityConfig
{
public static IEnumerable<ApiResource> GetResources()
{
return new List<ApiResource>
{
new ApiResource(ConfigManager.Configuration["IdentityAuthentication:Scope"],ConfigManager.Configuration["IdentityAuthentication:ClientName"])
{
#region ids4 4.X 新特性
Scopes = { "Asset",ConfigManager.Configuration["IdentityAuthentication:Scope"]},
#endregion
ApiSecrets = { new Secret(ConfigManager.Configuration["IdentityAuthentication:Secret"].Sha256()) }
}
};
}
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new IdentityResource[]
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
};
}
/// <summary>
/// ids4 4.X 新特性
/// </summary>
/// <returns></returns>
public static IEnumerable<ApiScope> GetScopes()
{
return new ApiScope[]
{
new ApiScope("Asset"),
new ApiScope(ConfigManager.Configuration["IdentityAuthentication:Scope"]),
};
}
/// <summary>
/// ids4 4.X 新特性
/// </summary>
public static IEnumerable<ApiScope> ApiScopes =>
new ApiScope[]
{
new ApiScope("Asset"),
new ApiScope(ConfigManager.Configuration["IdentityAuthentication:Scope"]),
};
}
}
6、Controller
RequestPasswordTokenAsync:创建Token
RequestRefreshTokenAsync:刷新Token
RevokeTokenAsync:撤销Token
using AutoMapper;
using Azure.Core;
using IdentityModel.Client;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApplicationModels;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Net.Http;
using System.Security.Claims;
using System.Text;
using static IdentityModel.OidcConstants;
namespace WebAPI.Controllers
{
/// <summary>
///
/// </summary>
[Route("api/passport/[action]")]
public class PassportController : ControllerBase
{
private readonly string url = string.Empty;
private readonly IUserRepository _userRepo;
private readonly IConfiguration _configuration;
private readonly IHttpClientHelper _client;
private readonly MsgResult _msgResult;
private readonly IMapper _mapper;
private readonly ILogger _logger;
/// <summary>
///
/// </summary>
/// <param name="userRepo"></param>
/// <param name="configuration"></param>
/// <param name="client"></param>
/// <param name="msgResult"></param>
/// <param name="mapper"></param>
/// <param name="logger"></param>
public PassportController(IUserRepository userRepo, IConfiguration configuration, IHttpClientHelper client, MsgResult msgResult, IMapper mapper, ILogger<PassportController> logger)
{
_userRepo = userRepo;
_configuration = configuration;
_client = client;
_msgResult = msgResult;
_mapper = mapper;
_logger = logger;
url = _configuration["IdentityAuthentication:Authority"]!;
}
/// <summary>
/// 登录
/// </summary>
/// <param name="request"></param>
/// <returns></returns>
[HttpPost]
[AllowAnonymous]
public async Task<MsgResult> Login([FromBody] LoginRequest request)
{
#region token
//Dictionary<string, string> parm = new Dictionary<string, string>();
//parm.Add("grant_type", "password");
//parm.Add("client_Id", _configuration["IdentityAuthentication:ApiName"]!);
//parm.Add("client_secret", _configuration["IdentityAuthentication:ApiSecret"]!);
//parm.Add("username", request.user_name);
//parm.Add("password", request.password);
//parm.Add("user_type", "Admin");
//parm.Add("scope", $"{_configuration["IdentityAuthentication:ApiName"]} openid offline_access");
//string tokenJson = await _client.PostAsync($"{url}/connect/token", StringPlus.DictionaryToString(parm), "application/x-www-form-urlencoded");
//TokenDto token = JsonConvert.DeserializeObject<TokenDto>(tokenJson);
//if (token != null)
//{
// _msgResult.code = token.code;
// _msgResult.data = token;
// _msgResult.message = token.message;
//}
#endregion
#region
IdentityModel.Client.TokenResponse tokenRes = await new HttpClient().RequestPasswordTokenAsync(new PasswordTokenRequest
{
Address = $"{url}/connect/token",
GrantType = "password",
ClientId = _configuration["IdentityAuthentication:ApiName"]!,
ClientSecret = _configuration["IdentityAuthentication:ApiSecret"]!,
UserName = request.user_name,
Password = request.password,
Scope = $"{_configuration["IdentityAuthentication:ApiName"]} openid offline_access",
Parameters = new Dictionary<string, string>()
{
{ "user_type","Admin"}
}
});
if (tokenRes != null)
{
_msgResult.code = 1;
_msgResult.data = tokenRes.Json;
_msgResult.message = "";
}
#endregion
return _msgResult;
}
/// <summary>
/// 刷新token
/// </summary>
/// <returns></returns>
[AllowAnonymous]
[HttpPost]
public async Task<MsgResult> RefreshToken([FromBody] QualityControl.Models.RefreshTokenRequest request)
{
#region
//Dictionary<string, string> parm = new Dictionary<string, string>();
//parm.Add("grant_type", "refresh_token");
//parm.Add("client_Id", _configuration["IdentityAuthentication:ApiName"]!);
//parm.Add("client_secret", _configuration["IdentityAuthentication:ApiSecret"]!);
//parm.Add("refresh_token", request.refresh_token);
//string tokenJson = await _client.PostAsync($"{url}/connect/token", StringPlus.DictionaryToString(parm), "application/x-www-form-urlencoded");
//TokenDto token = JsonConvert.DeserializeObject<TokenDto>(tokenJson);
//if (token != null)
//{
// _msgResult.code = token.code;
// _msgResult.data = token;
// _msgResult.message = token.message;
//}
#endregion
#region
IdentityModel.Client.TokenResponse tokenRes = await new HttpClient().RequestRefreshTokenAsync(new IdentityModel.Client.RefreshTokenRequest
{
Address = $"{url}/connect/token",
RefreshToken = request.refresh_token,
GrantType = "refresh_token",
ClientId = _configuration["IdentityAuthentication:ApiName"]!,
ClientSecret = _configuration["IdentityAuthentication:ApiSecret"]!,
});
if (tokenRes != null)
{
_msgResult.code = 1;
_msgResult.data = tokenRes.Json;
_msgResult.message = "";
}
#endregion
return _msgResult;
}
/// <summary>
/// 退出
/// </summary>
/// <returns></returns>
[AllowAnonymous]
[HttpPost()]
public async Task<MsgResult> Logout()
{
string token = HttpContext.Request.Headers["Authorization"].ToString().Replace("bearer ", "").Replace("Bearer ", "");
HttpClient client = new HttpClient();
await client.RevokeTokenAsync(new TokenRevocationRequest
{
Address = $"{url}/connect/revocation",
ClientId = _configuration["IdentityAuthentication:ApiName"]!,
ClientSecret = _configuration["IdentityAuthentication:ApiSecret"]!,
Token = token,
});
_msgResult.code = 1;
_msgResult.message = "退出成功";
return _msgResult;
}
}
}
*
*
*