@ -0,0 +1,7 @@ |
|||||
|
FROM mcr.microsoft.com/dotnet/aspnet:5.0 |
||||
|
WORKDIR /app |
||||
|
EXPOSE 80 |
||||
|
COPY . . |
||||
|
ENTRYPOINT ["dotnet", "CompanyName.ProjectName.HttpApi.Host.dll"] |
||||
|
|
||||
|
|
||||
@ -0,0 +1,164 @@ |
|||||
|
using Newtonsoft.Json; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Net.Http; |
||||
|
using System.Net.Http.Headers; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace CompanyName.ProjectName.Extensions.Customs.Http |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 基于IHttpClientFactory二次封装httpclient
|
||||
|
/// </summary>
|
||||
|
public static class HttpClientHelper |
||||
|
{ |
||||
|
|
||||
|
public static async Task<TResult> GetAsync<TResult>(this IHttpClientFactory _httpClientFactory, string clientName, string url, Dictionary<string, string> headers = null) where TResult : class |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var client = _httpClientFactory.CreateClient(clientName); |
||||
|
if (headers != null && headers.Count > 0) |
||||
|
{ |
||||
|
foreach (var item in headers) |
||||
|
{ |
||||
|
client.DefaultRequestHeaders.Add(item.Key, item.Value); |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
client.DefaultRequestHeaders.CacheControl = CacheControlHeaderValue.Parse("no-cache"); |
||||
|
|
||||
|
//执行请求
|
||||
|
var response = await client.GetAsync(url); |
||||
|
var result = await response.Content.ReadAsStringAsync(); |
||||
|
if (response.IsSuccessStatusCode) |
||||
|
{ |
||||
|
if (result != null && !string.IsNullOrEmpty(result)) |
||||
|
return JsonConvert.DeserializeObject<TResult>(result); |
||||
|
else |
||||
|
return default(TResult); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (string.IsNullOrEmpty(result)) |
||||
|
result = response.ReasonPhrase; |
||||
|
throw new Exception(result); |
||||
|
} |
||||
|
} |
||||
|
catch (Exception e) |
||||
|
{ |
||||
|
throw new Exception(e.Message); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static async Task<TResult> PostAsync<T, TResult>(this IHttpClientFactory _httpClientFactory, string clientName, string url, T obj, Dictionary<string, string> headers = null) where T : class where TResult : class |
||||
|
{ |
||||
|
var data = typeof(T).Name.ToLower() == "string" ? obj.ToString() : JsonConvert.SerializeObject(obj); |
||||
|
var client = _httpClientFactory.CreateClient(clientName); |
||||
|
if (headers != null && headers.Count > 0) |
||||
|
{ |
||||
|
foreach (var item in headers) |
||||
|
{ |
||||
|
client.DefaultRequestHeaders.Add(item.Key, item.Value); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
client.DefaultRequestHeaders.CacheControl = CacheControlHeaderValue.Parse("no-cache"); |
||||
|
//post 参数
|
||||
|
var content = new StringContent(data, Encoding.UTF8, "application/json"); |
||||
|
//执行请求
|
||||
|
var response = await client.PostAsync(url, content); |
||||
|
|
||||
|
var result = await response.Content.ReadAsStringAsync(); |
||||
|
if (response.IsSuccessStatusCode) |
||||
|
{ |
||||
|
if (result != null && !string.IsNullOrEmpty(result)) |
||||
|
return JsonConvert.DeserializeObject<TResult>(result); |
||||
|
else |
||||
|
return default(TResult); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (string.IsNullOrEmpty(result)) |
||||
|
result = response.ReasonPhrase; |
||||
|
|
||||
|
throw new Exception(result); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static async Task<TResult> PutAsync<T, TResult>(this IHttpClientFactory _httpClientFactory, string clientName, string url, T obj, Dictionary<string, string> headers = null) where T : class where TResult : class |
||||
|
{ |
||||
|
var data = typeof(T).Name.ToLower() == "string" ? obj.ToString() : JsonConvert.SerializeObject(obj); |
||||
|
var client = _httpClientFactory.CreateClient(clientName); |
||||
|
if (headers != null && headers.Count > 0) |
||||
|
{ |
||||
|
foreach (var item in headers) |
||||
|
{ |
||||
|
client.DefaultRequestHeaders.Add(item.Key, item.Value); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
client.DefaultRequestHeaders.CacheControl = CacheControlHeaderValue.Parse("no-cache"); |
||||
|
//post 参数
|
||||
|
var content = new StringContent(data, Encoding.UTF8, "application/json"); |
||||
|
//执行请求
|
||||
|
var response = await client.PutAsync(url, content); |
||||
|
|
||||
|
var result = await response.Content.ReadAsStringAsync(); |
||||
|
if (response.IsSuccessStatusCode) |
||||
|
{ |
||||
|
if (result != null && !string.IsNullOrEmpty(result)) |
||||
|
return JsonConvert.DeserializeObject<TResult>(result); |
||||
|
else |
||||
|
return default(TResult); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (string.IsNullOrEmpty(result)) |
||||
|
result = response.ReasonPhrase; |
||||
|
|
||||
|
throw new Exception(result); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static async Task<TResult> DeleteAsync<TResult>(this IHttpClientFactory _httpClientFactory, string clientName, string url, Dictionary<string, string> headers = null) where TResult : class |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
var client = _httpClientFactory.CreateClient(clientName); |
||||
|
if (headers != null && headers.Count > 0) |
||||
|
{ |
||||
|
foreach (var item in headers) |
||||
|
{ |
||||
|
client.DefaultRequestHeaders.Add(item.Key, item.Value); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
client.DefaultRequestHeaders.CacheControl = CacheControlHeaderValue.Parse("no-cache"); |
||||
|
|
||||
|
//执行请求
|
||||
|
var response = await client.DeleteAsync(url); |
||||
|
var result = await response.Content.ReadAsStringAsync(); |
||||
|
if (response.IsSuccessStatusCode) |
||||
|
{ |
||||
|
if (result != null && !string.IsNullOrEmpty(result)) |
||||
|
return JsonConvert.DeserializeObject<TResult>(result); |
||||
|
else |
||||
|
return default(TResult); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
if (string.IsNullOrEmpty(result)) |
||||
|
result = response.ReasonPhrase; |
||||
|
throw new Exception(result); |
||||
|
} |
||||
|
} |
||||
|
catch (Exception e) |
||||
|
{ |
||||
|
throw new Exception(e.Message); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,13 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace CompanyName.ProjectName.Extensions.Customs.Http |
||||
|
{ |
||||
|
public static class HttpClientNameConsts |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 身份验证中心
|
||||
|
/// </summary>
|
||||
|
public static string Sts = "Sts"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,81 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk.Web"> |
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net5.0</TargetFramework> |
||||
|
<RootNamespace>CompanyName.ProjectName</RootNamespace> |
||||
|
<PreserveCompilationReferences>true</PreserveCompilationReferences> |
||||
|
<UserSecretsId>CompanyName.ProjectName-4681b4fd-151f-4221-84a4-929d86723e4c</UserSecretsId> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Hangfire.MySqlStorage" Version="2.0.3" /> |
||||
|
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" /> |
||||
|
<PackageReference Include="Serilog.Sinks.Async" Version="1.4.0" /> |
||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="5.0.*" /> |
||||
|
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="5.0.*" /> |
||||
|
<PackageReference Include="Volo.Abp.Account.Web" Version="$(AbpPackageVersion)" /> |
||||
|
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy" Version="$(AbpPackageVersion)" /> |
||||
|
<PackageReference Include="Volo.Abp.Autofac" Version="$(AbpPackageVersion)" /> |
||||
|
<PackageReference Include="Volo.Abp.BackgroundJobs.HangFire" Version="4.4.0" /> |
||||
|
<PackageReference Include="Volo.Abp.Caching.StackExchangeRedis" Version="$(AbpPackageVersion)" /> |
||||
|
<PackageReference Include="Volo.Abp.AspNetCore.Serilog" Version="$(AbpPackageVersion)" /> |
||||
|
<PackageReference Include="Volo.Abp.Swashbuckle" Version="$(AbpPackageVersion)" /> |
||||
|
<PackageReference Include="Volo.Abp.AspNetCore.Authentication.JwtBearer" Version="$(AbpPackageVersion)" /> |
||||
|
|
||||
|
<PackageReference Include="Serilog" Version="2.10.0" /> |
||||
|
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" /> |
||||
|
<PackageReference Include="Serilog.Exceptions" Version="7.0.0" /> |
||||
|
<PackageReference Include="Serilog.Extensions.Logging" Version="3.0.1" /> |
||||
|
<PackageReference Include="Serilog.Settings.Configuration" Version="3.1.0" /> |
||||
|
<PackageReference Include="Serilog.Sinks.Console" Version="3.1.1" /> |
||||
|
<PackageReference Include="Serilog.Sinks.Elasticsearch" Version="8.4.1" /> |
||||
|
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> |
||||
|
|
||||
|
|
||||
|
<PackageReference Include="AspNetCore.HealthChecks.MySql" Version="5.0.1" /> |
||||
|
<PackageReference Include="AspNetCore.HealthChecks.Redis" Version="5.0.2" /> |
||||
|
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" Version="5.0.7" /> |
||||
|
<PackageReference Include="DotNetCore.CAP.MySql" Version="5.1.1" /> |
||||
|
<PackageReference Include="DotNetCore.CAP.RabbitMQ" Version="5.1.1" /> |
||||
|
<PackageReference Include="DotNetCore.CAP.Dashboard" Version="5.1.1" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\..\frameworks\CAP\src\CompanyName.ProjectName.CAP\CompanyName.ProjectName.CAP.csproj" /> |
||||
|
<ProjectReference Include="..\..\src\CompanyName.ProjectName.Application\CompanyName.ProjectName.Application.csproj" /> |
||||
|
<ProjectReference Include="..\..\src\CompanyName.ProjectName.EntityFrameworkCore.DbMigrations\CompanyName.ProjectName.EntityFrameworkCore.DbMigrations.csproj" /> |
||||
|
<ProjectReference Include="..\..\src\CompanyName.ProjectName.HttpApi\CompanyName.ProjectName.HttpApi.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<Compile Remove="Logs\**" /> |
||||
|
<Content Remove="Logs\**" /> |
||||
|
<EmbeddedResource Remove="Logs\**" /> |
||||
|
<None Remove="Logs\**" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<_ContentIncludedByDefault Remove="publish\publish\publish\web.config" /> |
||||
|
<_ContentIncludedByDefault Remove="publish\publish\web.config" /> |
||||
|
<_ContentIncludedByDefault Remove="publish\web.config" /> |
||||
|
<_ContentIncludedByDefault Remove="publish\appsettings.Development.json" /> |
||||
|
<_ContentIncludedByDefault Remove="publish\appsettings.json" /> |
||||
|
<_ContentIncludedByDefault Remove="publish\appsettings.Production.json" /> |
||||
|
<_ContentIncludedByDefault Remove="publish\appsettings.secrets.json" /> |
||||
|
<_ContentIncludedByDefault Remove="publish\CompanyName.ProjectName.HttpApi.Host.deps.json" /> |
||||
|
<_ContentIncludedByDefault Remove="publish\CompanyName.ProjectName.HttpApi.Host.runtimeconfig.json" /> |
||||
|
<_ContentIncludedByDefault Remove="publish\publish\appsettings.Development.json" /> |
||||
|
<_ContentIncludedByDefault Remove="publish\publish\appsettings.json" /> |
||||
|
<_ContentIncludedByDefault Remove="publish\publish\appsettings.Production.json" /> |
||||
|
<_ContentIncludedByDefault Remove="publish\publish\appsettings.secrets.json" /> |
||||
|
<_ContentIncludedByDefault Remove="publish\publish\CompanyName.ProjectName.HttpApi.Host.deps.json" /> |
||||
|
<_ContentIncludedByDefault Remove="publish\publish\CompanyName.ProjectName.HttpApi.Host.runtimeconfig.json" /> |
||||
|
<_ContentIncludedByDefault Remove="publish\publish\publish\appsettings.Development.json" /> |
||||
|
<_ContentIncludedByDefault Remove="publish\publish\publish\appsettings.json" /> |
||||
|
<_ContentIncludedByDefault Remove="publish\publish\publish\appsettings.secrets.json" /> |
||||
|
<_ContentIncludedByDefault Remove="publish\publish\publish\CompanyName.ProjectName.HttpApi.Host.deps.json" /> |
||||
|
<_ContentIncludedByDefault Remove="publish\publish\publish\CompanyName.ProjectName.HttpApi.Host.runtimeconfig.json" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,19 @@ |
|||||
|
FROM mcr.microsoft.com/dotnet/aspnet:5.0 |
||||
|
|
||||
|
# 创建目录 |
||||
|
RUN mkdir /app |
||||
|
|
||||
|
COPY publish /app |
||||
|
|
||||
|
# 设置工作目录 |
||||
|
WORKDIR /app |
||||
|
|
||||
|
# 暴露80端口 |
||||
|
EXPOSE 80 |
||||
|
|
||||
|
# 设置环境变量 |
||||
|
ENV ASPNETCORE_ENVIRONMENT=Production |
||||
|
|
||||
|
ENTRYPOINT ["dotnet", "CompanyName.ProjectName.HttpApi.Host.dll"] |
||||
|
|
||||
|
|
||||
@ -0,0 +1,438 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.IO; |
||||
|
using System.Linq; |
||||
|
using System.Net.Http; |
||||
|
using System.Text; |
||||
|
using CompanyName.ProjectName.ConfigurationOptions; |
||||
|
using Microsoft.AspNetCore.Authentication.JwtBearer; |
||||
|
using Microsoft.AspNetCore.Builder; |
||||
|
using Microsoft.AspNetCore.Cors; |
||||
|
using Microsoft.AspNetCore.DataProtection; |
||||
|
using Microsoft.AspNetCore.Hosting; |
||||
|
using Microsoft.Extensions.Configuration; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Hosting; |
||||
|
using CompanyName.ProjectName.EntityFrameworkCore; |
||||
|
using CompanyName.ProjectName.Extensions.Filters; |
||||
|
using CompanyName.ProjectName.Jobs; |
||||
|
using CompanyName.ProjectName.MultiTenancy; |
||||
|
using CompanyNameProjectName.Extensions.Filters; |
||||
|
using Hangfire; |
||||
|
using Hangfire.MySql; |
||||
|
using Microsoft.IdentityModel.Tokens; |
||||
|
using StackExchange.Redis; |
||||
|
using Microsoft.OpenApi.Models; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Account.Web; |
||||
|
using Volo.Abp.AspNetCore.Authentication.JwtBearer; |
||||
|
using Volo.Abp.AspNetCore.Mvc; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; |
||||
|
using Volo.Abp.AspNetCore.Serilog; |
||||
|
using Volo.Abp.Autofac; |
||||
|
using Volo.Abp.BackgroundJobs; |
||||
|
using Volo.Abp.BackgroundJobs.Hangfire; |
||||
|
using Volo.Abp.Caching; |
||||
|
using Volo.Abp.Caching.StackExchangeRedis; |
||||
|
using Volo.Abp.Identity.AspNetCore; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.Swashbuckle; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
using System.Threading.Tasks; |
||||
|
using CompanyName.ProjectName.CAP; |
||||
|
using Volo.Abp.AspNetCore.MultiTenancy; |
||||
|
using Volo.Abp.MultiTenancy; |
||||
|
using CompanyName.ProjectName.Extensions.Customs.Http; |
||||
|
|
||||
|
namespace CompanyName.ProjectName |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(ProjectNameHttpApiModule), |
||||
|
typeof(AbpAutofacModule), |
||||
|
typeof(AbpCachingStackExchangeRedisModule), |
||||
|
typeof(AbpAspNetCoreMvcUiMultiTenancyModule), |
||||
|
typeof(ProjectNameApplicationModule), |
||||
|
typeof(ProjectNameEntityFrameworkCoreDbMigrationsModule), |
||||
|
typeof(AbpAspNetCoreSerilogModule), |
||||
|
typeof(AbpSwashbuckleModule), |
||||
|
typeof(AbpAccountWebModule), |
||||
|
typeof(AbpAspNetCoreAuthenticationJwtBearerModule), |
||||
|
typeof(AbpBackgroundJobsHangfireModule), |
||||
|
typeof(AbpCapModule) |
||||
|
)] |
||||
|
public class ProjectNameHttpApiHostModule : AbpModule |
||||
|
{ |
||||
|
private const string DefaultCorsPolicyName = "Default"; |
||||
|
|
||||
|
public override void OnPostApplicationInitialization(ApplicationInitializationContext context) |
||||
|
{ |
||||
|
// context.CreateRecurringJob();
|
||||
|
base.OnPostApplicationInitialization(context); |
||||
|
} |
||||
|
|
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var configuration = context.Services.GetConfiguration(); |
||||
|
var hostingEnvironment = context.Services.GetHostingEnvironment(); |
||||
|
|
||||
|
//ConfigureConventionalControllers();
|
||||
|
//ConfigureAuthentication(context, configuration);
|
||||
|
ConfigureLocalization(); |
||||
|
ConfigureCache(context); |
||||
|
ConfigureVirtualFileSystem(context); |
||||
|
//ConfigureRedis(context);
|
||||
|
ConfigureCors(context, configuration); |
||||
|
ConfigureSwaggerServices(context, configuration); |
||||
|
ConfigureOptions(context); |
||||
|
ConfigureHealthChecks(context); |
||||
|
ConfigureJwtAuthentication(context, configuration); |
||||
|
ConfigureHangfireMysql(context); |
||||
|
ConfigurationCap(context); |
||||
|
ConfigurationStsHttpClient(context); |
||||
|
} |
||||
|
|
||||
|
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
||||
|
{ |
||||
|
var app = context.GetApplicationBuilder(); |
||||
|
var env = context.GetEnvironment(); |
||||
|
|
||||
|
if (env.IsDevelopment()) |
||||
|
{ |
||||
|
app.UseDeveloperExceptionPage(); |
||||
|
} |
||||
|
|
||||
|
app.UseAbpRequestLocalization(); |
||||
|
|
||||
|
if (!env.IsDevelopment()) |
||||
|
{ |
||||
|
app.UseErrorPage(); |
||||
|
} |
||||
|
|
||||
|
app.UseCorrelationId(); |
||||
|
app.UseStaticFiles(); |
||||
|
app.UseRouting(); |
||||
|
app.UseCors(DefaultCorsPolicyName); |
||||
|
app.UseAuthentication(); |
||||
|
//
|
||||
|
// if (MultiTenancyConsts.IsEnabled)
|
||||
|
// {
|
||||
|
// app.UseMultiTenancy();
|
||||
|
// }
|
||||
|
|
||||
|
app.UseAuthorization(); |
||||
|
|
||||
|
app.UseSwagger(); |
||||
|
app.UseAbpSwaggerUI(options => |
||||
|
{ |
||||
|
options.SwaggerEndpoint("/swagger/v1/swagger.json", "ProjectName API"); |
||||
|
|
||||
|
var configuration = context.GetConfiguration(); |
||||
|
options.OAuthClientId(configuration["AuthServer:SwaggerClientId"]); |
||||
|
options.OAuthClientSecret(configuration["AuthServer:SwaggerClientSecret"]); |
||||
|
options.OAuthScopes("ProjectName"); |
||||
|
}); |
||||
|
|
||||
|
app.UseAuditing(); |
||||
|
app.UseAbpSerilogEnrichers(); |
||||
|
app.UseUnitOfWork(); |
||||
|
app.UseConfiguredEndpoints(); |
||||
|
app.UseEndpoints(endpoints => { endpoints.MapHealthChecks("/health"); }); |
||||
|
app.UseHangfireDashboard("/hangfire", new DashboardOptions() |
||||
|
{ |
||||
|
Authorization = new[] {new CustomHangfireAuthorizeFilter()}, |
||||
|
IgnoreAntiforgeryToken = true |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public void ConfigureHangfireMysql(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
Configure<AbpBackgroundJobOptions>(options => { options.IsJobExecutionEnabled = true; }); |
||||
|
context.Services.AddHangfire(config => |
||||
|
{ |
||||
|
config.UseStorage(new MySqlStorage(context.Services.GetConfiguration().GetConnectionString("Default"), |
||||
|
new MySqlStorageOptions() |
||||
|
{ |
||||
|
//CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
|
||||
|
//SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
|
||||
|
//QueuePollInterval = TimeSpan.Zero,
|
||||
|
//UseRecommendedIsolationLevel = true,
|
||||
|
//DisableGlobalLocks = true
|
||||
|
})); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 配置JWT
|
||||
|
/// </summary>
|
||||
|
/// <param name="context"></param>
|
||||
|
/// <param name="configuration"></param>
|
||||
|
private void ConfigureJwtAuthentication(ServiceConfigurationContext context, IConfiguration configuration) |
||||
|
{ |
||||
|
context.Services.AddAuthentication(options => |
||||
|
{ |
||||
|
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; |
||||
|
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; |
||||
|
}) |
||||
|
.AddJwtBearer(options => |
||||
|
{ |
||||
|
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters() |
||||
|
{ |
||||
|
// 是否开启签名认证
|
||||
|
ValidateIssuerSigningKey = true, |
||||
|
ValidateIssuer = true, |
||||
|
ValidateAudience = true, |
||||
|
ValidateLifetime = true, |
||||
|
//ClockSkew = TimeSpan.Zero,
|
||||
|
ValidIssuer = configuration["Jwt:Issuer"], |
||||
|
ValidAudience = configuration["Jwt:Audience"], |
||||
|
IssuerSigningKey = |
||||
|
new SymmetricSecurityKey(Encoding.ASCII.GetBytes(configuration["Jwt:SecurityKey"])) |
||||
|
}; |
||||
|
|
||||
|
options.Events = new JwtBearerEvents |
||||
|
{ |
||||
|
OnMessageReceived = currentContext => |
||||
|
{ |
||||
|
var accessToken = currentContext.Request.Query["access_token"]; |
||||
|
// 如果请求来自signalr
|
||||
|
var path = currentContext.HttpContext.Request.Path; |
||||
|
if (path.StartsWithSegments("/signalr")) |
||||
|
{ |
||||
|
currentContext.Token = accessToken; |
||||
|
} |
||||
|
|
||||
|
// 如果请求来自hangfire 或者cap
|
||||
|
if (path.ToString().StartsWith("/hangfire") || path.ToString().StartsWith("/cap")) |
||||
|
{ |
||||
|
currentContext.HttpContext.Response.Headers.Remove("X-Frame-Options"); |
||||
|
if (!string.IsNullOrEmpty(accessToken)) |
||||
|
{ |
||||
|
currentContext.Token = accessToken; |
||||
|
currentContext.HttpContext.Response.Cookies |
||||
|
.Append("ProjectNameCookie", accessToken); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
var cookies = currentContext.Request.Cookies; |
||||
|
if (cookies.ContainsKey("ProjectNameCookie")) |
||||
|
{ |
||||
|
currentContext.Token = cookies["ProjectNameCookie"]; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
}; |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 配置options
|
||||
|
/// </summary>
|
||||
|
/// <param name="context"></param>
|
||||
|
private void ConfigureOptions(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.Configure<JwtOptions>(context.Services.GetConfiguration().GetSection("Jwt")); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Redis缓存
|
||||
|
/// </summary>
|
||||
|
private void ConfigureCache(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var redisConnectionString = |
||||
|
context.Services.GetConfiguration().GetValue<string>("Cache:Redis:ConnectionString"); |
||||
|
var redisDatabaseId = context.Services.GetConfiguration().GetValue<int>("Cache:Redis:DatabaseId"); |
||||
|
var password = context.Services.GetConfiguration().GetValue<string>("Cache:Redis:Password"); |
||||
|
var connectString = $"{redisConnectionString},password={password},defaultdatabase={redisDatabaseId}"; |
||||
|
var redis = ConnectionMultiplexer.Connect(connectString); |
||||
|
context.Services.AddStackExchangeRedisCache(options => { options.Configuration = connectString; }); |
||||
|
context.Services |
||||
|
.AddDataProtection() |
||||
|
.PersistKeysToStackExchangeRedis(redis, "ProjectName-Protection-Keys"); |
||||
|
} |
||||
|
|
||||
|
private void ConfigureVirtualFileSystem(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
Configure<AbpVirtualFileSystemOptions>(options => { options.FileSets.AddEmbedded<ProjectNameHttpApiHostModule>(); }); |
||||
|
|
||||
|
// var hostingEnvironment = context.Services.GetHostingEnvironment();
|
||||
|
//
|
||||
|
// if (hostingEnvironment.IsDevelopment())
|
||||
|
// {
|
||||
|
// Configure<AbpVirtualFileSystemOptions>(options =>
|
||||
|
// {
|
||||
|
// options.FileSets.ReplaceEmbeddedByPhysical<ProjectNameDomainSharedModule>(
|
||||
|
// Path.Combine(hostingEnvironment.ContentRootPath,
|
||||
|
// $"..{Path.DirectorySeparatorChar}CompanyName.ProjectName.Domain.Shared"));
|
||||
|
// options.FileSets.ReplaceEmbeddedByPhysical<ProjectNameDomainModule>(
|
||||
|
// Path.Combine(hostingEnvironment.ContentRootPath,
|
||||
|
// $"..{Path.DirectorySeparatorChar}CompanyName.ProjectName.Domain"));
|
||||
|
// options.FileSets.ReplaceEmbeddedByPhysical<ProjectNameApplicationContractsModule>(
|
||||
|
// Path.Combine(hostingEnvironment.ContentRootPath,
|
||||
|
// $"..{Path.DirectorySeparatorChar}CompanyName.ProjectName.Application.Contracts"));
|
||||
|
// options.FileSets.ReplaceEmbeddedByPhysical<ProjectNameApplicationModule>(
|
||||
|
// Path.Combine(hostingEnvironment.ContentRootPath,
|
||||
|
// $"..{Path.DirectorySeparatorChar}CompanyName.ProjectName.Application"));
|
||||
|
// });
|
||||
|
// }
|
||||
|
} |
||||
|
|
||||
|
private void ConfigurationStsHttpClient(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.AddHttpClient(HttpClientNameConsts.Sts, |
||||
|
options => |
||||
|
{ |
||||
|
options.BaseAddress = |
||||
|
new Uri(context.Services.GetConfiguration().GetSection("HttpClient:Sts:Url").Value); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private void ConfigureConventionalControllers() |
||||
|
{ |
||||
|
Configure<AbpAspNetCoreMvcOptions>(options => |
||||
|
{ |
||||
|
options.ConventionalControllers.Create(typeof(ProjectNameApplicationModule).Assembly); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 健康检查
|
||||
|
/// </summary>
|
||||
|
/// <param name="context"></param>
|
||||
|
private void ConfigureHealthChecks(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var redisConnectionString = |
||||
|
context.Services.GetConfiguration().GetValue<string>("Cache:Redis:ConnectionString"); |
||||
|
var redisDatabaseId = context.Services.GetConfiguration().GetValue<int>("Cache:Redis:DatabaseId"); |
||||
|
var password = context.Services.GetConfiguration().GetValue<string>("Cache:Redis:Password"); |
||||
|
var connectString = $"{redisConnectionString},password={password},defaultdatabase={redisDatabaseId}"; |
||||
|
context.Services.AddHealthChecks().AddRedis(redisConnectionString).AddMySql(connectString); |
||||
|
} |
||||
|
|
||||
|
private static void ConfigureSwaggerServices(ServiceConfigurationContext context, IConfiguration configuration) |
||||
|
{ |
||||
|
context.Services.AddSwaggerGen( |
||||
|
options => |
||||
|
{ |
||||
|
options.SwaggerDoc("v1", new OpenApiInfo {Title = "CompanyNameProjectName API", Version = "v1"}); |
||||
|
|
||||
|
options.DocInclusionPredicate((docName, description) => true); |
||||
|
options.EnableAnnotations(); // 启用注解
|
||||
|
options.DocumentFilter<HiddenAbpDefaultApiFilter>(); |
||||
|
options.SchemaFilter<EnumSchemaFilter>(); |
||||
|
options.AddSecurityDefinition(JwtBearerDefaults.AuthenticationScheme, new OpenApiSecurityScheme() |
||||
|
{ |
||||
|
Description = "Please enter into field the word 'Bearer' followed by a space and the JWT value", |
||||
|
Name = "Authorization", |
||||
|
In = ParameterLocation.Header, |
||||
|
Type = SecuritySchemeType.Http, |
||||
|
Scheme = JwtBearerDefaults.AuthenticationScheme, |
||||
|
BearerFormat = "JWT" |
||||
|
}); |
||||
|
options.AddSecurityRequirement(new OpenApiSecurityRequirement |
||||
|
{ |
||||
|
{ |
||||
|
new OpenApiSecurityScheme |
||||
|
{ |
||||
|
Reference = new OpenApiReference |
||||
|
{ |
||||
|
Type = ReferenceType.SecurityScheme, Id = "Bearer" |
||||
|
} |
||||
|
}, |
||||
|
new List<string>() |
||||
|
} |
||||
|
}); |
||||
|
|
||||
|
options.AddSecurityDefinition("ApiKey", new OpenApiSecurityScheme() |
||||
|
{ |
||||
|
Type = SecuritySchemeType.ApiKey, |
||||
|
In = ParameterLocation.Header, |
||||
|
Name = "Accept-Language", |
||||
|
Description = "多语言" |
||||
|
}); |
||||
|
|
||||
|
options.AddSecurityRequirement(new OpenApiSecurityRequirement |
||||
|
{ |
||||
|
{ |
||||
|
new OpenApiSecurityScheme |
||||
|
{ |
||||
|
Reference = new OpenApiReference {Type = ReferenceType.SecurityScheme, Id = "ApiKey"} |
||||
|
}, |
||||
|
new string[] { } |
||||
|
} |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private void ConfigureLocalization() |
||||
|
{ |
||||
|
Configure<AbpLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.Languages.Add(new LanguageInfo("ar", "ar", "العربية")); |
||||
|
options.Languages.Add(new LanguageInfo("cs", "cs", "Čeština")); |
||||
|
options.Languages.Add(new LanguageInfo("en", "en", "English")); |
||||
|
options.Languages.Add(new LanguageInfo("en-GB", "en-GB", "English (UK)")); |
||||
|
options.Languages.Add(new LanguageInfo("fr", "fr", "Français")); |
||||
|
options.Languages.Add(new LanguageInfo("hu", "hu", "Magyar")); |
||||
|
options.Languages.Add(new LanguageInfo("pt-BR", "pt-BR", "Português")); |
||||
|
options.Languages.Add(new LanguageInfo("ru", "ru", "Русский")); |
||||
|
options.Languages.Add(new LanguageInfo("tr", "tr", "Türkçe")); |
||||
|
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); |
||||
|
options.Languages.Add(new LanguageInfo("zh-Hant", "zh-Hant", "繁體中文")); |
||||
|
options.Languages.Add(new LanguageInfo("de-DE", "de-DE", "Deutsch", "de")); |
||||
|
options.Languages.Add(new LanguageInfo("es", "es", "Español", "es")); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private void ConfigureCors(ServiceConfigurationContext context, IConfiguration configuration) |
||||
|
{ |
||||
|
context.Services.AddAntiforgery(o => o.SuppressXFrameOptionsHeader = true); |
||||
|
context.Services.AddCors(options => |
||||
|
{ |
||||
|
options.AddPolicy(DefaultCorsPolicyName, builder => |
||||
|
{ |
||||
|
builder |
||||
|
.WithOrigins( |
||||
|
configuration["App:CorsOrigins"] |
||||
|
.Split(",", StringSplitOptions.RemoveEmptyEntries) |
||||
|
.Select(o => o.RemovePostFix("/")) |
||||
|
.ToArray() |
||||
|
) |
||||
|
.WithAbpExposedHeaders() |
||||
|
.SetIsOriginAllowedToAllowWildcardSubdomains() |
||||
|
.AllowAnyHeader() |
||||
|
.AllowAnyMethod() |
||||
|
.AllowCredentials(); |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
private void ConfigurationCap(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var configuration = context.Services.GetConfiguration(); |
||||
|
context.AddAbpCap(capOptions => |
||||
|
{ |
||||
|
capOptions.UseEntityFramework<ProjectNameDbContext>(); |
||||
|
capOptions.UseRabbitMQ(option => |
||||
|
{ |
||||
|
option.HostName = configuration.GetValue<string>("RabbitMq:HostName"); |
||||
|
option.UserName = configuration.GetValue<string>("RabbitMq:UserName"); |
||||
|
option.Password = configuration.GetValue<string>("RabbitMq:Password"); |
||||
|
}); |
||||
|
|
||||
|
var hostingEnvironment = context.Services.GetHostingEnvironment(); |
||||
|
bool auth = !hostingEnvironment.IsDevelopment(); |
||||
|
capOptions.UseDashboard(options => |
||||
|
{ |
||||
|
options.UseAuth = auth; |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,53 @@ |
|||||
|
{ |
||||
|
"App": { |
||||
|
"CorsOrigins": "https://*.ProjectName.com,http://localhost:4200,http://localhost:3100" |
||||
|
}, |
||||
|
"ConnectionStrings": { |
||||
|
"Default": "Data Source=localhost;Database=CompanyNameProjectNameDB;uid=root;pwd=1q2w3E*;charset=utf8mb4;Allow User Variables=true;AllowLoadLocalInfile=true" |
||||
|
}, |
||||
|
|
||||
|
"Cache": { |
||||
|
"Redis": { |
||||
|
"ConnectionString": "localhost", |
||||
|
"Password": "mypassword", |
||||
|
"DatabaseId": 0 |
||||
|
} |
||||
|
}, |
||||
|
"AuthServer": { |
||||
|
"Authority": "https://localhost:44354", |
||||
|
"RequireHttpsMetadata": "true", |
||||
|
"SwaggerClientId": "ProjectName_Swagger", |
||||
|
"SwaggerClientSecret": "1q2w3e*" |
||||
|
}, |
||||
|
"StringEncryption": { |
||||
|
"DefaultPassPhrase": "YFLtqf75HkDnKR0n" |
||||
|
}, |
||||
|
"Jwt": { |
||||
|
"Audience": "CompanyNameProjectName", |
||||
|
//客户端标识 |
||||
|
"SecurityKey": "dzehzRz9a8asdfasfdadfasdfasdfafsdadfasbasdf=", |
||||
|
"Issuer": "CompanyNameProjectName", |
||||
|
//签发者 |
||||
|
"ExpirationTime": 24 |
||||
|
//过期时间 hour |
||||
|
}, |
||||
|
"RabbitMq": { |
||||
|
"HostName": "localhost", |
||||
|
"UserName": "admin", |
||||
|
"Password": "admin" |
||||
|
}, |
||||
|
"LogToElasticSearch": { |
||||
|
"Enabled": "true", |
||||
|
"ElasticSearch": { |
||||
|
"Url": "http://es.cn", |
||||
|
"IndexFormat": "CompanyName.ProjectName.HttpApi.dev-{0:yyyy.MM.dd}", |
||||
|
"UserName": "CompanyName.ProjectName", |
||||
|
"Password": "TCYobkZxWu0ELYZY" |
||||
|
} |
||||
|
}, |
||||
|
"HttpClient": { |
||||
|
"Sts": { |
||||
|
"Url": "http://localhost:44354" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,48 @@ |
|||||
|
{ |
||||
|
"App": { |
||||
|
"CorsOrigins": "https://*.ProjectName.com,http://localhost:4200,http://localhost:3100,http://120.24.194.14:8012" |
||||
|
}, |
||||
|
"ConnectionStrings": { |
||||
|
"Default": "Data Source=120.24.194.14;Database=CompanyNameProjectNameDB;uid=root;pwd=1q2w3E*;charset=utf8mb4;Allow User Variables=true;AllowLoadLocalInfile=true", |
||||
|
}, |
||||
|
|
||||
|
"Cache": { |
||||
|
"Redis": { |
||||
|
"ConnectionString": "120.24.194.14", |
||||
|
"Password": "1q2w3E*", |
||||
|
"DatabaseId": 1 |
||||
|
} |
||||
|
}, |
||||
|
"AuthServer": { |
||||
|
"Authority": "https://localhost:44354", |
||||
|
"RequireHttpsMetadata": "true", |
||||
|
"SwaggerClientId": "ProjectName_Swagger", |
||||
|
"SwaggerClientSecret": "1q2w3e*" |
||||
|
}, |
||||
|
"StringEncryption": { |
||||
|
"DefaultPassPhrase": "YFLtqf75HkDnKR0n" |
||||
|
}, |
||||
|
"Jwt": { |
||||
|
"Audience": "CompanyNameProjectName", |
||||
|
//客户端标识 |
||||
|
"SecurityKey": "dzehzRz9a8asdfasfdadfasdfasdfafsdadfasbasdf=", |
||||
|
"Issuer": "CompanyNameProjectName", |
||||
|
//签发者 |
||||
|
"ExpirationTime": 24 |
||||
|
//过期时间 hour |
||||
|
}, |
||||
|
"RabbitMq": { |
||||
|
"HostName": "localhost", |
||||
|
"UserName": "admin", |
||||
|
"Password": "admin" |
||||
|
}, |
||||
|
"LogToElasticSearch": { |
||||
|
"Enabled": "true", |
||||
|
"ElasticSearch": { |
||||
|
"Url": "http://es.cn", |
||||
|
"IndexFormat": "CompanyName.ProjectName.HttpApi.dev-{0:yyyy.MM.dd}", |
||||
|
"UserName": "CompanyName.ProjectName", |
||||
|
"Password": "TCYobkZxWu0ELYZY" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,39 @@ |
|||||
|
version: '3' |
||||
|
services: |
||||
|
mysql: |
||||
|
hostname: mysql |
||||
|
image: mysql:5.7.26 |
||||
|
container_name: mysql # 指定容器名称,如果不设置此参数,则由系统自动生成 |
||||
|
restart: always # 设置容器自启模式 |
||||
|
command: mysqld --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci # 设置utf8字符集 |
||||
|
environment: |
||||
|
- TZ=Asia/Shanghai # 设置容器时区与宿主机保持一致 |
||||
|
- MYSQL_ROOT_PASSWORD=1q2w3E* # 设置root密码 |
||||
|
ports: |
||||
|
- "3308:3306" |
||||
|
|
||||
|
redis: |
||||
|
hostname: redis |
||||
|
image: redis:5.0.4 |
||||
|
container_name: redis |
||||
|
restart: always |
||||
|
environment: |
||||
|
- TZ=Asia/Shanghai |
||||
|
ports: |
||||
|
- "6380:6379" |
||||
|
|
||||
|
rabbitmq: |
||||
|
image: rabbitmq:management-alpine |
||||
|
container_name: rabbitmq |
||||
|
environment: |
||||
|
- RABBITMQ_DEFAULT_USER=xxxx |
||||
|
- RABBITMQ_DEFAULT_PASS=xxxx |
||||
|
restart: always |
||||
|
ports: |
||||
|
- "15673:15672" |
||||
|
- "5678:5672" |
||||
|
logging: |
||||
|
driver: "json-file" |
||||
|
options: |
||||
|
max-size: "200k" |
||||
|
max-file: "10" |
||||
@ -0,0 +1,36 @@ |
|||||
|
[client] |
||||
|
port = 3306 |
||||
|
socket = /var/lib/mysql/data/mysql.sock |
||||
|
[mysqld] |
||||
|
# 针对5.7版本执行group by字句出错问题解决 |
||||
|
sql_mode='STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' |
||||
|
# 一般配置选项 |
||||
|
basedir = /var/lib/mysql |
||||
|
datadir = /var/lib/mysql/data |
||||
|
port = 3306 |
||||
|
socket = /var/lib/mysql/data/mysql.sock |
||||
|
lc-messages-dir = /usr/share/mysql # 务必配置此项,否则执行sql出错时,只能显示错误代码而不显示具体错误消息 |
||||
|
character-set-server=utf8 |
||||
|
back_log = 300 |
||||
|
max_connections = 3000 |
||||
|
max_connect_errors = 50 |
||||
|
table_open_cache = 4096 |
||||
|
max_allowed_packet = 32M |
||||
|
#binlog_cache_size = 4M |
||||
|
max_heap_table_size = 128M |
||||
|
read_rnd_buffer_size = 16M |
||||
|
sort_buffer_size = 16M |
||||
|
join_buffer_size = 16M |
||||
|
thread_cache_size = 16 |
||||
|
query_cache_size = 64M |
||||
|
query_cache_limit = 4M |
||||
|
ft_min_word_len = 8 |
||||
|
thread_stack = 512K |
||||
|
transaction_isolation = REPEATABLE-READ |
||||
|
tmp_table_size = 64M |
||||
|
#log-bin=mysql-bin |
||||
|
long_query_time = 6 |
||||
|
server_id=1 |
||||
|
innodb_buffer_pool_size = 256M |
||||
|
innodb_thread_concurrency = 16 |
||||
|
innodb_log_buffer_size = 16M |
||||
@ -0,0 +1,51 @@ |
|||||
|
<Project Sdk="Microsoft.NET.Sdk.Web"> |
||||
|
|
||||
|
<Import Project="..\..\..\common.props" /> |
||||
|
|
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net5.0</TargetFramework> |
||||
|
<RootNamespace>CompanyName.ProjectName</RootNamespace> |
||||
|
<AssetTargetFallback>$(AssetTargetFallback);portable-net45+win8+wp8+wpa81;</AssetTargetFallback> |
||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects> |
||||
|
<GenerateBindingRedirectsOutputType>true</GenerateBindingRedirectsOutputType> |
||||
|
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles> |
||||
|
<PreserveCompilationContext>true</PreserveCompilationContext> |
||||
|
<MvcRazorExcludeRefAssembliesFromPublish>false</MvcRazorExcludeRefAssembliesFromPublish> |
||||
|
<PreserveCompilationReferences>true</PreserveCompilationReferences> |
||||
|
<UserSecretsId>CompanyName.ProjectName-4681b4fd-151f-4221-84a4-929d86723e4c</UserSecretsId> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<Compile Remove="Logs\**" /> |
||||
|
<Content Remove="Logs\**" /> |
||||
|
<EmbeddedResource Remove="Logs\**" /> |
||||
|
<None Remove="Logs\**" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<None Update="Pages\**\*.js"> |
||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory> |
||||
|
</None> |
||||
|
<None Update="Pages\**\*.css"> |
||||
|
<CopyToOutputDirectory>Always</CopyToOutputDirectory> |
||||
|
</None> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Serilog.AspNetCore" Version="4.1.0" /> |
||||
|
<PackageReference Include="Serilog.Sinks.Async" Version="1.4.0" /> |
||||
|
<PackageReference Include="Microsoft.AspNetCore.DataProtection.StackExchangeRedis" Version="5.0.*" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<PackageReference Include="Volo.Abp.Autofac" Version="$(AbpPackageVersion)" /> |
||||
|
<PackageReference Include="Volo.Abp.Caching.StackExchangeRedis" Version="$(AbpPackageVersion)" /> |
||||
|
<PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic" Version="$(AbpPackageVersion)" /> |
||||
|
<PackageReference Include="Volo.Abp.AspNetCore.Serilog" Version="$(AbpPackageVersion)" /> |
||||
|
<PackageReference Include="Volo.Abp.Account.Web.IdentityServer" Version="$(AbpPackageVersion)" /> |
||||
|
<PackageReference Include="Volo.Abp.Account.Application" Version="$(AbpPackageVersion)" /> |
||||
|
<ProjectReference Include="..\..\src\CompanyName.ProjectName.Domain.Shared\CompanyName.ProjectName.Domain.Shared.csproj" /> |
||||
|
<ProjectReference Include="..\..\src\CompanyName.ProjectName.EntityFrameworkCore.DbMigrations\CompanyName.ProjectName.EntityFrameworkCore.DbMigrations.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
</Project> |
||||
@ -0,0 +1,71 @@ |
|||||
|
using Microsoft.AspNetCore.Builder; |
||||
|
using Microsoft.AspNetCore.Http; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
|
||||
|
namespace CompanyName.ProjectName.Extensions |
||||
|
{ |
||||
|
public static class SameSiteCookiesServiceCollectionExtensions |
||||
|
{ |
||||
|
public static IServiceCollection AddSameSiteCookiePolicy(this IServiceCollection services) |
||||
|
{ |
||||
|
services.Configure<CookiePolicyOptions>(options => |
||||
|
{ |
||||
|
options.MinimumSameSitePolicy = SameSiteMode.Unspecified; |
||||
|
options.OnAppendCookie = cookieContext => |
||||
|
CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); |
||||
|
options.OnDeleteCookie = cookieContext => |
||||
|
CheckSameSite(cookieContext.Context, cookieContext.CookieOptions); |
||||
|
}); |
||||
|
|
||||
|
return services; |
||||
|
} |
||||
|
|
||||
|
private static void CheckSameSite(HttpContext httpContext, CookieOptions options) |
||||
|
{ |
||||
|
if (options.SameSite == SameSiteMode.None) |
||||
|
{ |
||||
|
var userAgent = httpContext.Request.Headers["User-Agent"].ToString(); |
||||
|
if (!httpContext.Request.IsHttps || DisallowsSameSiteNone(userAgent)) |
||||
|
{ |
||||
|
// For .NET Core < 3.1 set SameSite = (SameSiteMode)(-1)
|
||||
|
options.SameSite = SameSiteMode.Unspecified; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private static bool DisallowsSameSiteNone(string userAgent) |
||||
|
{ |
||||
|
// Cover all iOS based browsers here. This includes:
|
||||
|
// - Safari on iOS 12 for iPhone, iPod Touch, iPad
|
||||
|
// - WkWebview on iOS 12 for iPhone, iPod Touch, iPad
|
||||
|
// - Chrome on iOS 12 for iPhone, iPod Touch, iPad
|
||||
|
// All of which are broken by SameSite=None, because they use the iOS networking stack
|
||||
|
if (userAgent.Contains("CPU iPhone OS 12") || userAgent.Contains("iPad; CPU OS 12")) |
||||
|
{ |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
// Cover Mac OS X based browsers that use the Mac OS networking stack. This includes:
|
||||
|
// - Safari on Mac OS X.
|
||||
|
// This does not include:
|
||||
|
// - Chrome on Mac OS X
|
||||
|
// Because they do not use the Mac OS networking stack.
|
||||
|
if (userAgent.Contains("Macintosh; Intel Mac OS X 10_14") && |
||||
|
userAgent.Contains("Version/") && userAgent.Contains("Safari")) |
||||
|
{ |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
// Cover Chrome 50-69, because some versions are broken by SameSite=None,
|
||||
|
// and none in this range require it.
|
||||
|
// Note: this covers some pre-Chromium Edge versions,
|
||||
|
// but pre-Chromium Edge does not require SameSite=None.
|
||||
|
if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6")) |
||||
|
{ |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,36 @@ |
|||||
|
@page |
||||
|
@using CompanyName.ProjectName.Pages |
||||
|
@using Volo.Abp.Users |
||||
|
@model IndexModel |
||||
|
@inject ICurrentUser CurrentUser |
||||
|
@if (CurrentUser.IsAuthenticated) |
||||
|
{ |
||||
|
<div> |
||||
|
<abp-row> |
||||
|
<abp-column size-md="_3" class="text-center"> |
||||
|
<i class="fa fa-user d-block" style="font-size: 10em; color: #12b900"></i> |
||||
|
<a abp-button="Primary" href="/Account/Logout">Logout</a> |
||||
|
</abp-column> |
||||
|
<abp-column size-md="_9"> |
||||
|
<h2>@CurrentUser.UserName</h2> |
||||
|
<h5 class="text-muted">@CurrentUser.Email</h5> |
||||
|
<div> |
||||
|
<strong>Roles</strong>: @CurrentUser.Roles.JoinAsString(", ") |
||||
|
<br /> |
||||
|
<strong>Claims</strong>: <br /> |
||||
|
@Html.Raw(CurrentUser.GetAllClaims().Select(c => $"{c.Type}={c.Value}").JoinAsString(" <br /> ")) |
||||
|
</div> |
||||
|
</abp-column> |
||||
|
</abp-row> |
||||
|
</div> |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
@if (!CurrentUser.IsAuthenticated) |
||||
|
{ |
||||
|
<div class="text-center"> |
||||
|
<i class="fa fa-user d-block" style="font-size: 10em; color: #aaa"></i><br /><br /> |
||||
|
<a abp-button="Primary" asp-page="/Account/Login">Login</a> |
||||
|
</div> |
||||
|
} |
||||
@ -0,0 +1,186 @@ |
|||||
|
using System; |
||||
|
using System.IO; |
||||
|
using System.Linq; |
||||
|
using Localization.Resources.AbpUi; |
||||
|
using Microsoft.AspNetCore.Builder; |
||||
|
using Microsoft.AspNetCore.Cors; |
||||
|
using Microsoft.AspNetCore.DataProtection; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Hosting; |
||||
|
using CompanyName.ProjectName.EntityFrameworkCore; |
||||
|
using CompanyName.ProjectName.Extensions; |
||||
|
using CompanyName.ProjectName.Localization; |
||||
|
using CompanyName.ProjectName.MultiTenancy; |
||||
|
using StackExchange.Redis; |
||||
|
using Volo.Abp; |
||||
|
using Volo.Abp.Account; |
||||
|
using Volo.Abp.Account.Web; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI.Bundling; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Bundling; |
||||
|
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared; |
||||
|
using Volo.Abp.AspNetCore.Serilog; |
||||
|
using Volo.Abp.Auditing; |
||||
|
using Volo.Abp.Autofac; |
||||
|
using Volo.Abp.BackgroundJobs; |
||||
|
using Volo.Abp.Caching; |
||||
|
using Volo.Abp.Caching.StackExchangeRedis; |
||||
|
using Volo.Abp.Localization; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.UI.Navigation.Urls; |
||||
|
using Volo.Abp.UI; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
|
namespace CompanyName.ProjectName |
||||
|
{ |
||||
|
[DependsOn( |
||||
|
typeof(AbpAutofacModule), |
||||
|
typeof(AbpCachingStackExchangeRedisModule), |
||||
|
typeof(AbpAccountWebIdentityServerModule), |
||||
|
typeof(AbpAccountApplicationModule), |
||||
|
typeof(AbpAspNetCoreMvcUiBasicThemeModule), |
||||
|
typeof(ProjectNameEntityFrameworkCoreDbMigrationsModule), |
||||
|
typeof(AbpAspNetCoreSerilogModule) |
||||
|
)] |
||||
|
public class ProjectNameIdentityServerModule : AbpModule |
||||
|
{ |
||||
|
private const string DefaultCorsPolicyName = "Default"; |
||||
|
|
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
var hostingEnvironment = context.Services.GetHostingEnvironment(); |
||||
|
var configuration = context.Services.GetConfiguration(); |
||||
|
context.Services.AddSameSiteCookiePolicy(); |
||||
|
Configure<AbpLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.Resources |
||||
|
.Get<ProjectNameResource>() |
||||
|
.AddBaseTypes( |
||||
|
typeof(AbpUiResource) |
||||
|
); |
||||
|
|
||||
|
options.Languages.Add(new LanguageInfo("ar", "ar", "العربية")); |
||||
|
options.Languages.Add(new LanguageInfo("cs", "cs", "Čeština")); |
||||
|
options.Languages.Add(new LanguageInfo("en", "en", "English")); |
||||
|
options.Languages.Add(new LanguageInfo("en-GB", "en-GB", "English (UK)")); |
||||
|
options.Languages.Add(new LanguageInfo("fr", "fr", "Français")); |
||||
|
options.Languages.Add(new LanguageInfo("hu", "hu", "Magyar")); |
||||
|
options.Languages.Add(new LanguageInfo("pt-BR", "pt-BR", "Português")); |
||||
|
options.Languages.Add(new LanguageInfo("ru", "ru", "Русский")); |
||||
|
options.Languages.Add(new LanguageInfo("tr", "tr", "Türkçe")); |
||||
|
options.Languages.Add(new LanguageInfo("zh-Hans", "zh-Hans", "简体中文")); |
||||
|
options.Languages.Add(new LanguageInfo("zh-Hant", "zh-Hant", "繁體中文")); |
||||
|
options.Languages.Add(new LanguageInfo("de-DE", "de-DE", "Deutsch", "de")); |
||||
|
options.Languages.Add(new LanguageInfo("es", "es", "Español", "es")); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpBundlingOptions>(options => |
||||
|
{ |
||||
|
options.StyleBundles.Configure( |
||||
|
BasicThemeBundles.Styles.Global, |
||||
|
bundle => |
||||
|
{ |
||||
|
bundle.AddFiles("/global-styles.css"); |
||||
|
} |
||||
|
); |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpAuditingOptions>(options => |
||||
|
{ |
||||
|
//options.IsEnabledForGetRequests = true;
|
||||
|
options.ApplicationName = "AuthServer"; |
||||
|
}); |
||||
|
|
||||
|
if (hostingEnvironment.IsDevelopment()) |
||||
|
{ |
||||
|
Configure<AbpVirtualFileSystemOptions>(options => { options.FileSets.AddEmbedded<ProjectNameIdentityServerModule>(); }); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
Configure<AppUrlOptions>(options => |
||||
|
{ |
||||
|
options.Applications["MVC"].RootUrl = configuration["App:SelfUrl"]; |
||||
|
options.RedirectAllowedUrls.AddRange(configuration["App:RedirectAllowedUrls"].Split(',')); |
||||
|
|
||||
|
options.Applications["Angular"].RootUrl = configuration["App:ClientUrl"]; |
||||
|
options.Applications["Angular"].Urls[AccountUrlNames.PasswordReset] = "account/reset-password"; |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpBackgroundJobOptions>(options => |
||||
|
{ |
||||
|
options.IsJobExecutionEnabled = false; |
||||
|
}); |
||||
|
|
||||
|
Configure<AbpDistributedCacheOptions>(options => |
||||
|
{ |
||||
|
options.KeyPrefix = "ProjectName:"; |
||||
|
}); |
||||
|
|
||||
|
if (!hostingEnvironment.IsDevelopment()) |
||||
|
{ |
||||
|
var redis = ConnectionMultiplexer.Connect(configuration["Redis:Configuration"]); |
||||
|
context.Services |
||||
|
.AddDataProtection() |
||||
|
.PersistKeysToStackExchangeRedis(redis, "ProjectName-Protection-Keys"); |
||||
|
} |
||||
|
|
||||
|
context.Services.AddCors(options => |
||||
|
{ |
||||
|
options.AddPolicy(DefaultCorsPolicyName, builder => |
||||
|
{ |
||||
|
builder |
||||
|
.WithOrigins( |
||||
|
configuration["App:CorsOrigins"] |
||||
|
.Split(",", StringSplitOptions.RemoveEmptyEntries) |
||||
|
.Select(o => o.RemovePostFix("/")) |
||||
|
.ToArray() |
||||
|
) |
||||
|
.WithAbpExposedHeaders() |
||||
|
.SetIsOriginAllowedToAllowWildcardSubdomains() |
||||
|
.AllowAnyHeader() |
||||
|
.AllowAnyMethod() |
||||
|
.AllowCredentials(); |
||||
|
}); |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
public override void OnApplicationInitialization(ApplicationInitializationContext context) |
||||
|
{ |
||||
|
var app = context.GetApplicationBuilder(); |
||||
|
var env = context.GetEnvironment(); |
||||
|
|
||||
|
if (env.IsDevelopment()) |
||||
|
{ |
||||
|
app.UseDeveloperExceptionPage(); |
||||
|
} |
||||
|
|
||||
|
app.UseAbpRequestLocalization(); |
||||
|
|
||||
|
if (!env.IsDevelopment()) |
||||
|
{ |
||||
|
app.UseErrorPage(); |
||||
|
} |
||||
|
|
||||
|
app.UseCorrelationId(); |
||||
|
app.UseStaticFiles(); |
||||
|
app.UseRouting(); |
||||
|
app.UseCors(DefaultCorsPolicyName); |
||||
|
app.UseCookiePolicy(); |
||||
|
app.UseAuthentication(); |
||||
|
//
|
||||
|
// if (MultiTenancyConsts.IsEnabled)
|
||||
|
// {
|
||||
|
// app.UseMultiTenancy();
|
||||
|
// }
|
||||
|
|
||||
|
app.UseUnitOfWork(); |
||||
|
app.UseIdentityServer(); |
||||
|
app.UseAuthorization(); |
||||
|
app.UseAuditing(); |
||||
|
app.UseAbpSerilogEnrichers(); |
||||
|
app.UseConfiguredEndpoints(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,14 @@ |
|||||
|
{ |
||||
|
|
||||
|
"profiles": { |
||||
|
|
||||
|
"CompanyName.ProjectName.IdentityServer": { |
||||
|
"commandName": "Project", |
||||
|
"launchBrowser": true, |
||||
|
"applicationUrl": "http://localhost:44354", |
||||
|
"environmentVariables": { |
||||
|
"ASPNETCORE_ENVIRONMENT": "Development" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,17 @@ |
|||||
|
{ |
||||
|
"App": { |
||||
|
"SelfUrl": "https://localhost:44354", |
||||
|
"ClientUrl": "http://localhost:4200", |
||||
|
"CorsOrigins": "https://*.ProjectName.com,http://localhost:4200,https://localhost:44307,https://localhost:44315", |
||||
|
"RedirectAllowedUrls": "http://localhost:4200,https://localhost:44307" |
||||
|
}, |
||||
|
"ConnectionStrings": { |
||||
|
"Default": "Data Source=localhost;Database=CompanyNameProjectNameDB;uid=root;pwd=1q2w3E*;charset=utf8mb4;Allow User Variables=true;AllowLoadLocalInfile=true" |
||||
|
}, |
||||
|
"Redis": { |
||||
|
"Configuration": "localhost,password=mypassword" |
||||
|
}, |
||||
|
"StringEncryption": { |
||||
|
"DefaultPassPhrase": "YFLtqf75HkDnKR0n" |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,2 @@ |
|||||
|
{ |
||||
|
} |
||||
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 122 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 712 KiB After Width: | Height: | Size: 712 KiB |
|
Before Width: | Height: | Size: 141 KiB After Width: | Height: | Size: 141 KiB |
|
Before Width: | Height: | Size: 889 KiB After Width: | Height: | Size: 889 KiB |