feat: 初始化后台管理模块与基础业务框架
1. 新增依赖注入生命周期标记接口、基础仓储与管理员仓储实现 2. 新增管理员认证与用户服务接口,补充认证相关DTO 3. 重构实体审计字段命名,统一Created/UpdatedAt规范 4. 新增大量业务实体类与API版本枚举配置 5. 集成Autofac依赖注入、JWT自动刷新与跨域配置 6. 替换原有微信小程序与旧认证服务为后台管理系统架构 7. 完善Swagger文档配置与项目基础部署配置
This commit is contained in:
205
QYZH.InteractiveMagazine.WebApi/Controllers/AdminController.cs
Normal file
205
QYZH.InteractiveMagazine.WebApi/Controllers/AdminController.cs
Normal file
@ -0,0 +1,205 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using QYZH.InteractiveMagazine.IService;
|
||||
using QYZH.InteractiveMagazine.IService.Dto;
|
||||
using QYZH.InteractiveMagazine.Models.Common;
|
||||
using QYZH.InteractiveMagazine.Models.Dto;
|
||||
using QYZH.InteractiveMagazine.Models.Enum;
|
||||
|
||||
namespace QYZH.InteractiveMagazine.WebApi.Controllers;
|
||||
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class AdminController : BaseController
|
||||
{
|
||||
private readonly IAdminAuthService _adminAuthService;
|
||||
private readonly IAdminUserService _adminUserService;
|
||||
private readonly ILogger<AdminController> _logger;
|
||||
|
||||
public AdminController(IAdminAuthService adminAuthService, IAdminUserService adminUserService, ILogger<AdminController> logger)
|
||||
{
|
||||
_adminAuthService = adminAuthService;
|
||||
_adminUserService = adminUserService;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[AllowAnonymous]
|
||||
[HttpPost("login")]
|
||||
public async Task<BaseResponse<AdminLoginOutput>> LoginAsync([FromBody] AdminLoginInput input)
|
||||
{
|
||||
var result = await _adminAuthService.LoginAsync(input);
|
||||
return Success(result);
|
||||
}
|
||||
|
||||
[HttpPost("logout")]
|
||||
public async Task<BaseResponse<object>> LogoutAsync()
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
if (userId == null)
|
||||
{
|
||||
return Fail("未获取到用户信息", 401);
|
||||
}
|
||||
|
||||
await _adminAuthService.LogoutAsync(userId.Value);
|
||||
return Success(new object(), "登出成功");
|
||||
}
|
||||
|
||||
[HttpGet("info")]
|
||||
public async Task<BaseResponse<AdminUserInfoOutput>> GetAdminInfoAsync()
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
if (userId == null)
|
||||
{
|
||||
return BaseResponse<AdminUserInfoOutput>.Fail("未获取到用户信息", 401);
|
||||
}
|
||||
|
||||
var result = await _adminAuthService.GetAdminInfoAsync(userId.Value);
|
||||
return Success(result);
|
||||
}
|
||||
|
||||
[HttpPost("changePassword")]
|
||||
public async Task<BaseResponse<object>> ChangePasswordAsync([FromBody] ChangePasswordInput input)
|
||||
{
|
||||
var userId = GetCurrentUserId();
|
||||
if (userId == null)
|
||||
{
|
||||
return Fail("未获取到用户信息", 401);
|
||||
}
|
||||
|
||||
await _adminAuthService.ChangePasswordAsync(userId.Value, input.OldPassword, input.NewPassword);
|
||||
return Success(new object(), "密码修改成功");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建管理员
|
||||
/// </summary>
|
||||
/// <param name="input">管理员输入</param>
|
||||
/// <returns>创建的管理员信息</returns>
|
||||
[HttpPost("users")]
|
||||
public async Task<BaseResponse<AdminUserOutput>> CreateUserAsync([FromBody] AdminUserInput input)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await _adminUserService.CreateAsync(input);
|
||||
return Success(result, "创建管理员成功");
|
||||
}
|
||||
catch (BusinessException ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "创建管理员业务异常: {Message}", ex.Message);
|
||||
return BaseResponse<AdminUserOutput>.Fail(ex.Message, ex.Code);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "创建管理员系统异常,参数:{Input}", input);
|
||||
return BaseResponse<AdminUserOutput>.Fail("创建管理员失败,请稍后重试", 500);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新管理员
|
||||
/// </summary>
|
||||
/// <param name="id">管理员ID</param>
|
||||
/// <param name="input">管理员输入</param>
|
||||
/// <returns>更新后的管理员信息</returns>
|
||||
[HttpPut("users/{id}")]
|
||||
public async Task<BaseResponse<AdminUserOutput>> UpdateUserAsync(long id, [FromBody] AdminUserInput input)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await _adminUserService.UpdateAsync(id, input);
|
||||
return Success(result, "更新管理员成功");
|
||||
}
|
||||
catch (BusinessException ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "更新管理员业务异常: {Message}", ex.Message);
|
||||
return BaseResponse<AdminUserOutput>.Fail(ex.Message, ex.Code);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "更新管理员系统异常,ID:{Id},参数:{Input}", id, input);
|
||||
return BaseResponse<AdminUserOutput>.Fail("更新管理员失败,请稍后重试", 500);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除管理员
|
||||
/// </summary>
|
||||
/// <param name="id">管理员ID</param>
|
||||
/// <returns>操作结果</returns>
|
||||
[HttpDelete("users/{id}")]
|
||||
public async Task<BaseResponse<object>> DeleteUserAsync(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
await _adminUserService.DeleteAsync(id);
|
||||
return Success(new object(), "删除管理员成功");
|
||||
}
|
||||
catch (BusinessException ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "删除管理员业务异常: {Message}", ex.Message);
|
||||
return BaseResponse<object>.Fail(ex.Message, ex.Code);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "删除管理员系统异常,ID:{Id}", id);
|
||||
return BaseResponse<object>.Fail("删除管理员失败,请稍后重试", 500);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 根据ID获取管理员
|
||||
/// </summary>
|
||||
/// <param name="id">管理员ID</param>
|
||||
/// <returns>管理员信息</returns>
|
||||
[HttpGet("users/{id}")]
|
||||
public async Task<BaseResponse<AdminUserOutput>> GetUserByIdAsync(long id)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await _adminUserService.GetByIdAsync(id);
|
||||
return Success(result);
|
||||
}
|
||||
catch (BusinessException ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "获取管理员业务异常: {Message}", ex.Message);
|
||||
return BaseResponse<AdminUserOutput>.Fail(ex.Message, ex.Code);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "获取管理员系统异常,ID:{Id}", id);
|
||||
return BaseResponse<AdminUserOutput>.Fail("获取管理员信息失败,请稍后重试", 500);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 分页查询管理员列表
|
||||
/// </summary>
|
||||
/// <param name="input">查询条件</param>
|
||||
/// <returns>分页结果</returns>
|
||||
[HttpPost("users/list")]
|
||||
public async Task<BaseResponse<PageListModel<AdminUserOutput>>> GetUsersListAsync([FromBody] AdminUserQueryInput input)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = await _adminUserService.GetListAsync(input);
|
||||
return Success(result);
|
||||
}
|
||||
catch (BusinessException ex)
|
||||
{
|
||||
_logger.LogWarning(ex, "查询管理员列表业务异常: {Message}", ex.Message);
|
||||
return BaseResponse<PageListModel<AdminUserOutput>>.Fail(ex.Message, ex.Code);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "查询管理员列表系统异常,参数:{Input}", input);
|
||||
return BaseResponse<PageListModel<AdminUserOutput>>.Fail("查询管理员列表失败,请稍后重试", 500);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ChangePasswordInput
|
||||
{
|
||||
public string OldPassword { get; set; } = string.Empty;
|
||||
|
||||
public string NewPassword { get; set; } = string.Empty;
|
||||
}
|
||||
@ -1,61 +0,0 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using QYZH.InteractiveMagazine.IService;
|
||||
using QYZH.InteractiveMagazine.IService.Dto;
|
||||
using QYZH.InteractiveMagazine.Models.Dto;
|
||||
|
||||
namespace QYZH.InteractiveMagazine.WebApi.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// 认证控制器
|
||||
/// </summary>
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
public class AuthController : BaseController
|
||||
{
|
||||
private readonly IAuthService _authService;
|
||||
|
||||
public AuthController(IAuthService authService)
|
||||
{
|
||||
_authService = authService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户登录
|
||||
/// </summary>
|
||||
/// <param name="input">登录信息</param>
|
||||
/// <returns>登录结果</returns>
|
||||
[AllowAnonymous]
|
||||
[HttpPost("login")]
|
||||
public async Task<BaseResponse<LoginOutput>> LoginAsync([FromBody] LoginInput input)
|
||||
{
|
||||
var result = await _authService.LoginAsync(input.Account, input.Password);
|
||||
return Success(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 用户注册
|
||||
/// </summary>
|
||||
/// <param name="input">注册信息</param>
|
||||
/// <returns>是否成功</returns>
|
||||
[AllowAnonymous]
|
||||
[HttpPost("register")]
|
||||
public async Task<BaseResponse<bool>> RegisterAsync([FromBody] RegisterInput input)
|
||||
{
|
||||
var result = await _authService.RegisterAsync(input);
|
||||
return Success(result, "注册成功");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刷新令牌
|
||||
/// </summary>
|
||||
/// <param name="refreshToken">刷新令牌</param>
|
||||
/// <returns>新的登录结果</returns>
|
||||
[AllowAnonymous]
|
||||
[HttpPost("refreshToken")]
|
||||
public async Task<BaseResponse<LoginOutput>> RefreshTokenAsync([FromQuery] string refreshToken)
|
||||
{
|
||||
var result = await _authService.RefreshTokenAsync(refreshToken);
|
||||
return Success(result);
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using QYZH.InteractiveMagazine.Models.Dto;
|
||||
using QYZH.InteractiveMagazine.Models.Enum;
|
||||
|
||||
namespace QYZH.InteractiveMagazine.WebApi.Controllers;
|
||||
|
||||
@ -8,6 +9,7 @@ namespace QYZH.InteractiveMagazine.WebApi.Controllers;
|
||||
/// </summary>
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
[ApiExplorerSettings(GroupName = nameof(ApiVersionEnum.Platform))]
|
||||
public abstract class BaseController : ControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@ -1,35 +0,0 @@
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using QYZH.InteractiveMagazine.IService;
|
||||
using QYZH.InteractiveMagazine.IService.Dto;
|
||||
using QYZH.InteractiveMagazine.Models.Dto;
|
||||
|
||||
namespace QYZH.InteractiveMagazine.WebApi.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// 微信小程序控制器
|
||||
/// </summary>
|
||||
[Route("api/[controller]")]
|
||||
[ApiController]
|
||||
[AllowAnonymous]
|
||||
public class WeChatController : BaseController
|
||||
{
|
||||
private readonly IWeChatMiniProgramService _weChatService;
|
||||
|
||||
public WeChatController(IWeChatMiniProgramService weChatService)
|
||||
{
|
||||
_weChatService = weChatService;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 微信登录
|
||||
/// </summary>
|
||||
/// <param name="code">微信登录凭证</param>
|
||||
/// <returns>微信登录结果</returns>
|
||||
[HttpPost("login")]
|
||||
public async Task<BaseResponse<WeChatLoginOutput>> WeChatLoginAsync([FromQuery] string code)
|
||||
{
|
||||
var result = await _weChatService.WeChatLoginAsync(code);
|
||||
return Success(result);
|
||||
}
|
||||
}
|
||||
19
QYZH.InteractiveMagazine.WebApi/Dockerfile
Normal file
19
QYZH.InteractiveMagazine.WebApi/Dockerfile
Normal file
@ -0,0 +1,19 @@
|
||||
# 使用 ASP.NET Core 8.0 运行时基础镜像
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 将当前目录(发布文件夹)的所有内容复制到容器内的 /app 目录
|
||||
COPY . .
|
||||
|
||||
# 设置时区(可选)
|
||||
ENV TZ=Asia/Shanghai
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
# 暴露端口(根据您的 WebApi 实际监听的端口,通常为 80 或 8080)
|
||||
# 注意:这里只是声明,实际映射需要在运行容器时指定
|
||||
EXPOSE 8090
|
||||
|
||||
# 启动应用
|
||||
ENTRYPOINT ["dotnet", "QYZH.InteractiveMagazine.WebApi.dll"]
|
||||
@ -1,38 +1,98 @@
|
||||
using Autofac;
|
||||
using Autofac.Extensions.DependencyInjection;
|
||||
using BCrypt.Net;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.OpenApi;
|
||||
using QYZH.InteractiveMagazine.Common.Extensions;
|
||||
using QYZH.InteractiveMagazine.Infrastructure.Extensions;
|
||||
using QYZH.InteractiveMagazine.Infrastructure.Middleware;
|
||||
using QYZH.InteractiveMagazine.Models.Entity;
|
||||
using QYZH.InteractiveMagazine.Models.Enum;
|
||||
using QYZH.InteractiveMagazine.Repository;
|
||||
using Serilog;
|
||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||
using Swashbuckle.AspNetCore.SwaggerUI;
|
||||
using QYZH.InteractiveMagazine.Infrastructure.Autofacs;
|
||||
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// autofac注入 允许使用autofac作为DI容器
|
||||
builder.UseAutofac();
|
||||
|
||||
// 配置Serilog
|
||||
Log.Logger = new LoggerConfiguration()
|
||||
.ReadFrom.Configuration(builder.Configuration)
|
||||
.Enrich.FromLogContext()
|
||||
.WriteTo.Console()
|
||||
.CreateLogger();
|
||||
|
||||
builder.Host.UseSerilog();
|
||||
|
||||
// 注册服务
|
||||
builder.Services.AddControllers();
|
||||
builder.Services.AddEndpointsApiExplorer();
|
||||
builder.Services.AddSwaggerGen();
|
||||
|
||||
// 基础设施服务注册(JWT、Redis、RabbitMQ)
|
||||
// 跨域配置
|
||||
builder.AddCorsRegister();
|
||||
|
||||
// 注册 Swagger 文档
|
||||
builder.Services.AddSwaggerGen(option =>
|
||||
{
|
||||
var xmlFile = $"{AppDomain.CurrentDomain.FriendlyName}.xml";
|
||||
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
|
||||
var modelXml = Path.Combine(AppContext.BaseDirectory, $"QYZH.InteractiveMagazine.Models.xml");
|
||||
|
||||
|
||||
Enum.GetValues<ApiVersionEnum>().ToList().ForEach(version =>
|
||||
{
|
||||
// 配置文档信息
|
||||
option.SwaggerDoc(version.ToString(), new OpenApiInfo
|
||||
{
|
||||
Title = AppDomain.CurrentDomain.FriendlyName,
|
||||
Version = "互动期刊接口文档",
|
||||
Description = $"{version.GetDescription()}接口,Last Modify Time:{new FileInfo(xmlPath).LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss")}"
|
||||
});
|
||||
});
|
||||
// 配置接口路径排序
|
||||
option.OrderActionsBy(o => o.RelativePath);
|
||||
|
||||
if (File.Exists(xmlPath))
|
||||
option.IncludeXmlComments(xmlPath, true);
|
||||
if (File.Exists(modelXml))
|
||||
option.IncludeXmlComments(modelXml, true);
|
||||
|
||||
option.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
|
||||
{
|
||||
Description = "请输入 Token,格式为 Bearer Token",
|
||||
Name = "Authorization",
|
||||
In = ParameterLocation.Header,
|
||||
Type = SecuritySchemeType.ApiKey,
|
||||
BearerFormat = "JWT",
|
||||
Scheme = "Bearer"
|
||||
});
|
||||
|
||||
|
||||
// 过滤文档/路径/方法筛选接口的响应结果
|
||||
option.DocInclusionPredicate((docName, apiDesc) =>
|
||||
{
|
||||
// 方式 1:将接口的 [ApiExplorerSettings(GroupName = "xxx")] 特性匹配
|
||||
if (!apiDesc.TryGetMethodInfo(out var methodInfo)) return false;
|
||||
var groupName = methodInfo.DeclaringType?
|
||||
.GetCustomAttributes(true)
|
||||
.OfType<ApiExplorerSettingsAttribute>()
|
||||
.FirstOrDefault()?
|
||||
.GroupName;
|
||||
|
||||
// 匹配当前文档(分组)则显示
|
||||
return groupName == docName;
|
||||
});
|
||||
});
|
||||
|
||||
builder.Services.AddInfrastructureServices(builder.Configuration);
|
||||
|
||||
// 注册中间件
|
||||
builder.Services.AddTransient<GlobalExceptionMiddleware>();
|
||||
builder.Services.AddTransient<OperationLogMiddleware>();
|
||||
|
||||
// 注册业务服务
|
||||
builder.Services.AddScoped<QYZH.InteractiveMagazine.IService.IAuthService, QYZH.InteractiveMagazine.Service.AuthService>();
|
||||
builder.Services.AddScoped<QYZH.InteractiveMagazine.IService.IWeChatMiniProgramService, QYZH.InteractiveMagazine.Service.WeChatMiniProgramService>();
|
||||
|
||||
// 初始化SqlSugar
|
||||
SqlSugarDbContext.Init(builder.Configuration);
|
||||
|
||||
|
||||
// 添加CORS
|
||||
builder.Services.AddCors(options =>
|
||||
{
|
||||
@ -46,19 +106,27 @@ builder.Services.AddCors(options =>
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// 配置HTTP请求管道
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.UseSwagger();
|
||||
app.UseSwaggerUI();
|
||||
app.UseSwaggerUI(c =>
|
||||
{
|
||||
// 根据版本名称倒序 遍历展示
|
||||
Enum.GetValues<ApiVersionEnum>().OrderBy(e => e).ToList().ForEach(version =>
|
||||
{
|
||||
c.SwaggerEndpoint($"/swagger/{version}/swagger.json", $"{version.GetDescription()}接口");
|
||||
});
|
||||
c.DocExpansion(DocExpansion.None); // ->修改界面打开时自动折叠
|
||||
});
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
app.UseCors("AllowAll");
|
||||
app.UseMiddleware<GlobalExceptionMiddleware>();
|
||||
app.UseMiddleware<OperationLogMiddleware>();
|
||||
app.UseMiddleware<JwtAutoRefreshMiddleware>();
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
|
||||
|
||||
@ -4,9 +4,13 @@
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Autofac" Version="9.1.0" />
|
||||
<PackageReference Include="Autofac.Extensions.DependencyInjection" Version="11.0.0" />
|
||||
<PackageReference Include="BCrypt.Net-Next" Version="4.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.27" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="10.2.0" />
|
||||
</ItemGroup>
|
||||
@ -19,4 +23,8 @@
|
||||
<ProjectReference Include="..\QYZH.InteractiveMagazine.Models\QYZH.InteractiveMagazine.Models.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Controllers\WeChat\" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@ -1,23 +1,23 @@
|
||||
{
|
||||
"ConnectionStrings": {
|
||||
"DefaultConnection": "Server=localhost;Database=interactive_magazine;Uid=root;Pwd=root;Charset=utf8mb4;"
|
||||
"DefaultConnection": "server=192.168.20.150;port=13306;database=InteractiveMagazine;user=user;password=n68792bu!y99r905;charset=utf8mb4;"
|
||||
},
|
||||
"JwtSettings": {
|
||||
"Issuer": "QYZH.InteractiveMagazine",
|
||||
"Audience": "QYZH.InteractiveMagazine.Client",
|
||||
"SecretKey": "your-256-bit-secret-key-here-change-in-production",
|
||||
"Audience": "QYZH.InteractiveMagazine",
|
||||
"SecretKey": "zG7pLqR9xVw2bN8fYtHk3mPc5sA1dF6eUjW4gXhC7vB",
|
||||
"ExpiryMinutes": 120
|
||||
},
|
||||
"RedisSettings": {
|
||||
"ConnectionString": "localhost:6379",
|
||||
"ConnectionString": "192.168.20.150:16379,defaultDatabase=5",
|
||||
"InstanceName": "interactive_magazine"
|
||||
},
|
||||
"RabbitMQSettings": {
|
||||
"HostName": "localhost",
|
||||
"HostName": "192.168.20.150",
|
||||
"Port": 5672,
|
||||
"UserName": "guest",
|
||||
"Password": "guest",
|
||||
"VirtualHost": "/"
|
||||
"UserName": "smartschool",
|
||||
"Password": "@ss%&*otz%d*pq2S",
|
||||
"VirtualHost": "InteractiveMagazine"
|
||||
},
|
||||
"WeChatSettings": {
|
||||
"AppId": "your-wechat-appid",
|
||||
|
||||
Reference in New Issue
Block a user