Merge branch 'abp' of https://gitee.com/ccnetcore/Yi into abp

This commit is contained in:
陈淳
2023-12-21 08:57:17 +08:00
60 changed files with 25424 additions and 372 deletions

View File

@@ -24,5 +24,12 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss
/// 封面
/// </summary>
public string? Cover { get; set; }
public int OrderNum { get; set; } = 0;
/// <summary>
/// 是否禁止评论创建功能
/// </summary>
public bool IsDisableCreateComment { get; set; }
}
}

View File

@@ -7,6 +7,10 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss
{
public class DiscussGetListOutputDto : EntityDto<Guid>
{
/// <summary>
/// <20>Ƿ<EFBFBD><C7B7><EFBFBD>ֹ<EFBFBD><D6B9><EFBFBD>۴<EFBFBD><DBB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
public bool IsDisableCreateComment { get; set; }
/// <summary>
/// <20>Ƿ<EFBFBD><C7B7>ѵ<EFBFBD><D1B5>ޣ<EFBFBD>Ĭ<EFBFBD><C4AC>δ<EFBFBD><CEB4>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>

View File

@@ -6,6 +6,10 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss
{
public class DiscussGetOutputDto : EntityDto<Guid>
{
/// <summary>
/// <20>Ƿ<EFBFBD><C7B7><EFBFBD>ֹ<EFBFBD><D6B9><EFBFBD>۴<EFBFBD><DBB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
public bool IsDisableCreateComment { get; set; }
public string Title { get; set; }
public string? Types { get; set; }
public string? Introduction { get; set; }

View File

@@ -20,5 +20,12 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss
/// <20><><EFBFBD><EFBFBD>
/// </summary>
public string? Cover { get; set; }
public int OrderNum { get; set; }
/// <summary>
/// <20>Ƿ<EFBFBD><C7B7><EFBFBD>ֹ<EFBFBD><D6B9><EFBFBD>۴<EFBFBD><DBB4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
/// </summary>
public bool IsDisableCreateComment { get; set; }
}
}

View File

@@ -10,5 +10,9 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Plate
public string? Introduction { get; set; }
public string Code { get; set; }
public int OrderNum { get; set; }
public bool IsDisableCreateDiscuss { get; set; }
}
}

View File

@@ -12,5 +12,8 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Plate
public string Code { get; set; }
public DateTime CreationTime { get; set; }
public int OrderNum { get; set; }
public bool IsDisableCreateDiscuss { get; set; }
}
}

View File

@@ -10,5 +10,8 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Plate
public string Code { get; set; }
public DateTime CreationTime { get; set; }
public int OrderNum { get; set; }
public bool IsDisableCreateDiscuss { get; set; }
}
}

View File

@@ -7,5 +7,10 @@ namespace Yi.Framework.Bbs.Application.Contracts.Dtos.Plate
public string? Introduction { get; set; }
public string? Code { get; set; }
public int OrderNum { get; set; }
public bool IsDisableCreateDiscuss { get; set; }
}
}

View File

@@ -11,6 +11,7 @@ using Yi.Framework.Bbs.Application.Contracts.Dtos.Article;
using Yi.Framework.Bbs.Application.Contracts.Dtos.Plate;
using Yi.Framework.Bbs.Application.Contracts.IServices;
using Yi.Framework.Bbs.Domain.Entities;
using Yi.Framework.Bbs.Domain.Extensions;
using Yi.Framework.Bbs.Domain.Repositories;
using Yi.Framework.Bbs.Domain.Shared.Consts;
using Yi.Framework.Core.Extensions;
@@ -47,7 +48,7 @@ namespace Yi.Framework.Bbs.Application.Services
RefAsync<int> total = 0;
var entities = await _articleRepository._DbQueryable.WhereIF(!string.IsNullOrEmpty(input.Name), x => x.Name.Contains(input.Name!))
//.WhereIF(!string.IsNullOrEmpty(input.Code), x => x.Name.Contains(input.Code!))
//.WhereIF(!string.IsNullOrEmpty(input.Code), x => x.Name.Contains(input.Code!))
.WhereIF(input.StartTime is not null && input.EndTime is not null, x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime)
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
return new PagedResultDto<ArticleGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities));
@@ -98,34 +99,60 @@ namespace Yi.Framework.Bbs.Application.Services
/// <exception cref="UserFriendlyException"></exception>
public async override Task<ArticleGetOutputDto> CreateAsync(ArticleCreateInputVo input)
{
var discuss = await _discussRepository.GetFirstAsync(x => x.Id == input.DiscussId);
if (discuss is null)
{
throw new UserFriendlyException(DiscussConst.No_Exist);
}
if (input.ParentId != Guid.Empty && !await _articleRepository.IsAnyAsync(x => x.Id == input.ParentId))
{
throw new UserFriendlyException(ArticleConst.No_Exist);
}
await VerifyDiscussCreateIdAsync(discuss.CreatorId);
await VerifyDiscussCreateIdAsync(input.DiscussId);
return await base.CreateAsync(input);
}
/// <summary>
/// 更新文章
/// </summary>
/// <param name="id"></param>
/// <param name="input"></param>
/// <returns></returns>
public override async Task<ArticleGetOutputDto> UpdateAsync(Guid id, ArticleUpdateInputVo input)
{
var entity = await _articleRepository.GetByIdAsync(id);
await VerifyDiscussCreateIdAsync(entity.DiscussId);
return await base.UpdateAsync(id, input);
}
/// <summary>
/// 效验创建权限
/// 删除文章
/// </summary>
/// <param name="userId"></param>
/// <param name="id"></param>
/// <returns></returns>
public async Task VerifyDiscussCreateIdAsync(Guid? userId)
public override async Task DeleteAsync(Guid id)
{
var entity = await _articleRepository.GetByIdAsync(id);
await VerifyDiscussCreateIdAsync(entity.DiscussId);
await base.DeleteAsync(id);
}
/// <summary>
/// 效验创建权限userId为主题创建者
/// </summary>
/// <param name="disucssId"></param>
/// <returns></returns>
private async Task VerifyDiscussCreateIdAsync(Guid disucssId)
{
var discuss = await _discussRepository.GetFirstAsync(x => x.Id == disucssId);
if (discuss is null)
{
throw new UserFriendlyException(DiscussConst.No_Exist);
}
//只有文章是特殊的,不能在其他主题下创建
//主题的创建者不是当前用户,同时,没有权限或者超级管理
//false & true & false ,三个条件任意满意一个,即可成功使用||,最后取反,一个都不满足
//
if (userId != CurrentUser.Id && !UserConst.Admin.Equals(this.CurrentUser.UserName) && this.LazyServiceProvider.GetRequiredService<IHttpContextAccessor>().HttpContext.GetUserPermissions(TokenTypeConst.Permission).Contains("bbs:discuss:add"))
//一个条件都不满足,即可拦截
if (discuss.CreatorId != CurrentUser.Id && !UserConst.Admin.Equals(this.CurrentUser.UserName) && !CurrentUser.GetPermissions().Contains("bbs:discuss:add"))
{
throw new UserFriendlyException("权限在其他用户主题中创建子文章");
throw new UserFriendlyException("权限不足,请联系主题作者或管理员申请开通");
}
}
}

View File

@@ -102,10 +102,17 @@ namespace Yi.Framework.Bbs.Application.Services
/// <exception cref="UserFriendlyException"></exception>
public override async Task<CommentGetOutputDto> CreateAsync(CommentCreateInputVo input)
{
if (!await _discussRepository.IsAnyAsync(x => x.Id == input.DiscussId))
var discuess = await _discussRepository.GetFirstAsync(x => x.Id == input.DiscussId);
if (discuess is null)
{
throw new UserFriendlyException(DiscussConst.No_Exist);
}
if (discuess.IsDisableCreateComment == true)
{
throw new UserFriendlyException("该主题已禁止评论功能");
}
var entity = await _forumManager.CreateCommentAsync(input.DiscussId, input.ParentId, input.RootId, input.Content);
return await MapToGetOutputDtoAsync(entity);
}

View File

@@ -9,6 +9,7 @@ using Volo.Abp.Users;
using Yi.Framework.Bbs.Application.Contracts.Dtos.Discuss;
using Yi.Framework.Bbs.Application.Contracts.IServices;
using Yi.Framework.Bbs.Domain.Entities;
using Yi.Framework.Bbs.Domain.Extensions;
using Yi.Framework.Bbs.Domain.Managers;
using Yi.Framework.Bbs.Domain.Shared.Consts;
using Yi.Framework.Bbs.Domain.Shared.Enums;
@@ -16,6 +17,7 @@ using Yi.Framework.Bbs.Domain.Shared.Etos;
using Yi.Framework.Ddd.Application;
using Yi.Framework.Rbac.Application.Contracts.Dtos.User;
using Yi.Framework.Rbac.Domain.Entities;
using Yi.Framework.Rbac.Domain.Shared.Consts;
using Yi.Framework.SqlSugarCore.Abstractions;
namespace Yi.Framework.Bbs.Application.Services
@@ -26,11 +28,13 @@ namespace Yi.Framework.Bbs.Application.Services
public class DiscussService : YiCrudAppService<DiscussEntity, DiscussGetOutputDto, DiscussGetListOutputDto, Guid, DiscussGetListInputVo, DiscussCreateInputVo, DiscussUpdateInputVo>,
IDiscussService
{
public DiscussService(ForumManager forumManager, ISqlSugarRepository<PlateEntity> plateEntityRepository, ILocalEventBus localEventBus) : base(forumManager._discussRepository)
private ISqlSugarRepository<DiscussTopEntity> _discussTopEntityRepository;
public DiscussService(ForumManager forumManager, ISqlSugarRepository<DiscussTopEntity> discussTopEntityRepository, ISqlSugarRepository<PlateEntity> plateEntityRepository, ILocalEventBus localEventBus) : base(forumManager._discussRepository)
{
_forumManager = forumManager;
_plateEntityRepository = plateEntityRepository;
_localEventBus = localEventBus;
_discussTopEntityRepository = discussTopEntityRepository;
}
private readonly ILocalEventBus _localEventBus;
private ForumManager _forumManager { get; set; }
@@ -78,12 +82,17 @@ namespace Yi.Framework.Bbs.Application.Services
var items = await _forumManager._discussRepository._DbQueryable
.WhereIF(!string.IsNullOrEmpty(input.Title), x => x.Title.Contains(input.Title))
.WhereIF(input.PlateId is not null, x => x.PlateId == input.PlateId)
.WhereIF(input.IsTop==true, x => x.IsTop == input.IsTop)
.WhereIF(input.IsTop == true, x => x.IsTop == input.IsTop)
.LeftJoin<UserEntity>((discuss, user) => discuss.CreatorId == user.Id)
.OrderByDescending(discuss => discuss.OrderNum)
.OrderByIF(input.Type == QueryDiscussTypeEnum.New, discuss => discuss.CreationTime, OrderByType.Desc)
.OrderByIF(input.Type == QueryDiscussTypeEnum.Host, discuss => discuss.SeeNum, OrderByType.Desc)
.OrderByIF(input.Type == QueryDiscussTypeEnum.Suggest, discuss => discuss.AgreeNum, OrderByType.Desc)
.Select((discuss, user) => new DiscussGetListOutputDto
{
Id = discuss.Id,
@@ -99,6 +108,18 @@ namespace Yi.Framework.Bbs.Application.Services
return new PagedResultDto<DiscussGetListOutputDto>(total, items);
}
/// <summary>
/// 获取首页的置顶主题
/// </summary>
/// <returns></returns>
public async Task<List<DiscussGetListOutputDto>> GetListTopAsync()
{
var entities = await _discussTopEntityRepository._DbQueryable.Includes(x => x.Discuss).OrderByDescending(x => x.OrderNum).ToListAsync();
var output = await MapToGetListOutputDtosAsync(entities.Select(x => x.Discuss).ToList());
return output;
}
/// <summary>
/// 创建主题
/// </summary>
@@ -106,17 +127,28 @@ namespace Yi.Framework.Bbs.Application.Services
/// <returns></returns>
public override async Task<DiscussGetOutputDto> CreateAsync(DiscussCreateInputVo input)
{
if (!await _plateEntityRepository.IsAnyAsync(x => x.Id == input.PlateId))
var plate = await _plateEntityRepository.FindAsync(x => x.Id == input.PlateId);
if (plate is null)
{
throw new UserFriendlyException(PlateConst.No_Exist);
}
//如果开启了禁用创建主题
if (plate.IsDisableCreateDiscuss == true)
{
if (!CurrentUser.GetPermissions().Contains("") && CurrentUser.UserName != UserConst.Admin)
{
throw new UserFriendlyException("该板块已禁止创建主题,请在其他板块中发布");
}
}
var entity = await _forumManager.CreateDiscussAsync(await MapToEntityAsync(input));
return await MapToGetOutputDtoAsync(entity);
}
/// <summary>
/// 效验主题查询权限
/// </summary>

View File

@@ -29,6 +29,7 @@ namespace Yi.Framework.Bbs.Application.Services
var entities = await _repository._DbQueryable.WhereIF(!string.IsNullOrEmpty(input.Name), x => x.Name.Contains(input.Name!))
.WhereIF(!string.IsNullOrEmpty(input.Code), x => x.Name.Contains(input.Code!))
.WhereIF(input.StartTime is not null && input.EndTime is not null, x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime)
.OrderByDescending(x=>x.OrderNum)
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
return new PagedResultDto<PlateGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities));
}

View File

@@ -39,6 +39,8 @@ namespace Yi.Framework.Bbs.Domain.Entities
//是否置顶默认false
public bool IsTop { get; set; }
public int OrderNum { get; set; } = 0;
public DiscussPermissionTypeEnum PermissionType { get; set; }
@@ -57,5 +59,10 @@ namespace Yi.Framework.Bbs.Domain.Entities
/// </summary>
[SugarColumn(IsJson = true)]//使用json处理
public List<Guid>? PermissionUserIds { get; set; }
/// <summary>
/// 是否禁止评论创建功能
/// </summary>
public bool IsDisableCreateComment { get; set; }
}
}

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SqlSugar;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities;
namespace Yi.Framework.Bbs.Domain.Entities
{
/// <summary>
/// 首页置顶主题
/// </summary>
[SugarTable("DiscussTop")]
public class DiscussTopEntity : Entity<Guid>, IHasModificationTime
{
[SugarColumn(ColumnName = "Id", IsPrimaryKey = true)]
public override Guid Id { get; protected set; }
public int OrderNum { get; set; }
public Guid DiscussId { get; set; }
[Navigate(NavigateType.OneToOne, nameof(DiscussId))]
public DiscussEntity Discuss { get; set; }
public DateTime? LastModificationTime { get; set; }
}
}

View File

@@ -6,7 +6,7 @@ using Volo.Abp.Auditing;
namespace Yi.Framework.Bbs.Domain.Entities
{
[SugarTable("Plate")]
public class PlateEntity : Entity<Guid>, ISoftDelete,IAuditedObject
public class PlateEntity : Entity<Guid>, ISoftDelete, IAuditedObject
{
[SugarColumn(ColumnName = "Id", IsPrimaryKey = true)]
@@ -27,5 +27,12 @@ namespace Yi.Framework.Bbs.Domain.Entities
public Guid? LastModifierId { get; set; }
public DateTime? LastModificationTime { get; set; }
public int OrderNum { get; set; }
/// <summary>
/// 是否禁用创建主题,禁用后,只有管理员或者权限者能够发送
/// </summary>
public bool IsDisableCreateDiscuss { get; set; }
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Users;
using Yi.Framework.Rbac.Domain.Shared.Consts;
namespace Yi.Framework.Bbs.Domain.Extensions
{
public static class CurrestUserExtensions
{
/// <summary>
/// 获取用户权限codes
/// </summary>
/// <param name="currentUser"></param>
/// <returns></returns>
public static List<string> GetPermissions(this ICurrentUser currentUser)
{
return currentUser.FindClaims(TokenTypeConst.Permission).Select(x => x.Value).ToList();
}
}
}

View File

@@ -41,6 +41,8 @@ namespace Yi.Framework.Rbac.Application.Services
private IDistributedCache<CaptchaPhoneCacheItem, CaptchaPhoneCacheKey> _phoneCache;
private readonly ICaptcha _captcha;
private readonly IGuidGenerator _guidGenerator;
private readonly RbacOptions _rbacOptions;
private readonly IAliyunManger _aliyunManger;
public AccountService(IUserRepository userRepository,
ICurrentUser currentUser,
AccountManager accountManager,
@@ -50,7 +52,11 @@ namespace Yi.Framework.Rbac.Application.Services
IOptions<JwtOptions> jwtOptions,
IDistributedCache<CaptchaPhoneCacheItem, CaptchaPhoneCacheKey> phoneCache,
ICaptcha captcha,
IGuidGenerator guidGenerator)
IGuidGenerator guidGenerator,
IOptions<RbacOptions> options,
IAliyunManger aliyunManger,
ISqlSugarRepository<RoleEntity> roleRepository,
UserManager userManager)
{
_userRepository = userRepository;
_currentUser = currentUser;
@@ -62,6 +68,10 @@ namespace Yi.Framework.Rbac.Application.Services
_phoneCache = phoneCache;
_captcha = captcha;
_guidGenerator = guidGenerator;
_rbacOptions = options.Value;
_aliyunManger = aliyunManger;
_roleRepository = roleRepository;
_userManager = userManager;
}
@@ -79,27 +89,17 @@ namespace Yi.Framework.Rbac.Application.Services
/// </summary>
private void ValidationImageCaptcha(LoginInputVo input)
{
//登录不想要验证码 ,可不效验
if (!_captcha.Validate(input.Uuid, input.Code))
if (_rbacOptions.EnableCaptcha)
{
throw new UserFriendlyException("验证码错误");
//登录不想要验证码 ,可不效验
if (!_captcha.Validate(input.Uuid, input.Code))
{
throw new UserFriendlyException("验证码错误");
}
}
}
/// <summary>
/// 效验电话验证码,需要与电话号码绑定
/// </summary>
private void ValidationPhoneCaptcha(RegisterDto input)
{
//var value = _memoryCache.Get<string>($"Yi:Phone:{input.Phone}");
//if (value is not null && value.Equals($"{input.Code}"))
//{
// //成功,需要清空
// _memoryCache.Remove($"Yi:Phone:{input.Phone}");
// return;
//}
//throw new UserFriendlyException("验证码错误");
}
/// <summary>
/// 登录
@@ -114,7 +114,7 @@ namespace Yi.Framework.Rbac.Application.Services
}
//效验验证码
// ValidationImageCaptcha(input);
ValidationImageCaptcha(input);
UserEntity user = new();
//登录成功
@@ -123,6 +123,12 @@ namespace Yi.Framework.Rbac.Application.Services
//获取用户信息
var userInfo = await _userRepository.GetUserAllInfoAsync(user.Id);
//判断用户状态
if (userInfo.User.State == false)
{
throw new UserFriendlyException(UserConst.State_Is_State);
}
if (userInfo.RoleCodes.Count == 0)
{
throw new UserFriendlyException(UserConst.No_Role);
@@ -216,19 +222,9 @@ namespace Yi.Framework.Rbac.Application.Services
//生成一个4位数的验证码
//发送短信同时生成uuid
////key 电话号码 value:验证码+uuid
//var code = _securityCode.GetRandomEnDigitalText(4);
var code = Guid.NewGuid().ToString().Substring(0, 4);
var uuid = Guid.NewGuid();
//未开启短信验证默认8888
//if (_smsAliyunManagerOptions.Value.EnableFeature)
//{
// await _smsAliyunManager.Send(input.Phone, code);
//}
//else
//{
var code = "8888";
//}
//_memoryCache.Set($"Yi:Phone:{input.Phone}", $"{code}", new TimeSpan(0, 10, 0));
await _aliyunManger.SendSmsAsync(input.Phone, code);
await _phoneCache.SetAsync(new CaptchaPhoneCacheKey(input.Phone), new CaptchaPhoneCacheItem(code), new DistributedCacheEntryOptions { SlidingExpiration = TimeSpan.FromMinutes(10) });
return new
@@ -237,6 +233,22 @@ namespace Yi.Framework.Rbac.Application.Services
};
}
/// <summary>
/// 效验电话验证码,需要与电话号码绑定
/// </summary>
private async Task ValidationPhoneCaptchaAsync(RegisterDto input)
{
var item = await _phoneCache.GetAsync(new CaptchaPhoneCacheKey(input.Phone.ToString()));
if (item is not null && item.Code.Equals($"{input.Code}"))
{
//成功,需要清空
await _phoneCache.RemoveAsync(new CaptchaPhoneCacheKey(input.Phone.ToString()));
return;
}
throw new UserFriendlyException("验证码错误");
}
/// <summary>
/// 注册,需要验证码通过
/// </summary>
@@ -246,6 +258,11 @@ namespace Yi.Framework.Rbac.Application.Services
[UnitOfWork]
public async Task<object> PostRegisterAsync(RegisterDto input)
{
if (_rbacOptions.EnableRegister == false)
{
throw new UserFriendlyException("该系统暂未开放注册功能");
}
if (input.UserName == UserConst.Admin)
{
throw new UserFriendlyException("用户名无效注册!");
@@ -260,15 +277,13 @@ namespace Yi.Framework.Rbac.Application.Services
throw new UserFriendlyException("密码需大于等于6位");
}
//效验验证码,根据电话号码获取 value比对验证码已经uuid
ValidationPhoneCaptcha(input);
await ValidationPhoneCaptchaAsync(input);
//输入的用户名与电话号码都不能在数据库中存在
UserEntity user = new();
var isExist = await _userRepository.IsAnyAsync(x =>
x.UserName == input.UserName
|| x.Phone == input.Phone);
var isExist = await _userRepository.IsAnyAsync(x =>x.UserName == input.UserName|| x.Phone == input.Phone);
if (isExist)
{
throw new UserFriendlyException("用户已存在,注册失败");
@@ -278,8 +293,7 @@ namespace Yi.Framework.Rbac.Application.Services
var entity = await _userRepository.InsertReturnEntityAsync(newUser);
//赋上一个初始角色
var roleRepository = _roleRepository;
var role = await roleRepository.GetFirstAsync(x => x.RoleCode == UserConst.GuestRoleCode);
var role = await _roleRepository.GetFirstAsync(x => x.RoleCode == UserConst.GuestRoleCode);
if (role is not null)
{
await _userManager.GiveUserSetRoleAsync(new List<Guid> { entity.Id }, new List<Guid> { role.Id });

View File

@@ -11,7 +11,7 @@
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.2.5" />
<PackageReference Include="Lazy.Captcha.Core" Version="2.0.7" />
<PackageReference Include="SkiaSharp.NativeAssets.Linux.NoDependencies" Version="2.88.6" />
<PackageReference Include="Volo.Abp.BackgroundWorkers.Quartz" Version="8.0.0-rc.3" />
<PackageReference Include="Volo.Abp.BackgroundWorkers.Quartz" Version="8.0.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -16,6 +16,7 @@ namespace Yi.Framework.Rbac.Domain.Shared.Consts
public const string Login_User_No_Exist = "登录失败!用户名不存在!";
public const string Login_Passworld_Error = "密码为空,添加失败!";
public const string User_Exist = "用户已经存在,添加失败!";
public const string State_Is_State = "该用户已被禁用,请联系管理员进行恢复";
public const string No_Permission = "登录禁用!该用户分配无任何权限,无意义登录!";
public const string No_Role = "登录禁用!该用户分配无任何角色,无意义登录!";

View File

@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Yi.Framework.Rbac.Domain.Shared.Options
{
public class AliyunOptions
{
public string AccessKeyId { get; set; }
public string AccessKeySecret { get; set; }
public AliyunSms Sms { get; set; }
}
public class AliyunSms
{
public string SignName { get; set; }
public string TemplateCode { get; set; }
}
}

View File

@@ -12,5 +12,15 @@ namespace Yi.Framework.Rbac.Domain.Shared.Options
/// 超级管理员默认密码
/// </summary>
public string AdminPassword { get; set; } = "123456";
/// <summary>
/// 是否开启登录验证码
/// </summary>
public bool EnableCaptcha { get; set; } = false;
/// <summary>
/// 是否开启用户注册功能
/// </summary>
public bool EnableRegister { get; set; } = false;
}
}

View File

@@ -7,7 +7,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Volo.Abp.Ddd.Domain.Shared" Version="8.0.0-rc.3" />
<PackageReference Include="Volo.Abp.Ddd.Domain.Shared" Version="8.0.0" />
</ItemGroup>
<ItemGroup>

View File

@@ -0,0 +1,69 @@
using AlibabaCloud.SDK.Dysmsapi20170525;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Volo.Abp.Domain.Services;
using Yi.Framework.Rbac.Domain.Shared.Options;
namespace Yi.Framework.Rbac.Domain.Managers
{
public class AliyunManger : DomainService, IAliyunManger
{
private ILogger<AliyunManger> _logger;
private AliyunOptions Options { get; set; }
public AliyunManger(ILogger<AliyunManger> logger, IOptions<AliyunOptions> options)
{
Options = options.Value;
_logger = logger;
}
private Client CreateClient()
{
AlibabaCloud.OpenApiClient.Models.Config config = new AlibabaCloud.OpenApiClient.Models.Config
{
// 必填,您的 AccessKey ID
AccessKeyId = Options.AccessKeyId,
// 必填,您的 AccessKey Secret
AccessKeySecret = Options.AccessKeySecret,
};
// 访问的域名
config.Endpoint = "dysmsapi.aliyuncs.com";
return new Client(config);
}
/// <summary>
/// 发送短信
/// </summary>
/// <param name="phoneNumbers"></param>
/// <param name="code"></param>
/// <returns></returns>
public async Task SendSmsAsync(string phoneNumbers, string code)
{
try
{
var _aliyunClient = CreateClient();
AlibabaCloud.SDK.Dysmsapi20170525.Models.SendSmsRequest sendSmsRequest = new AlibabaCloud.SDK.Dysmsapi20170525.Models.SendSmsRequest
{
PhoneNumbers = phoneNumbers,
SignName = Options.Sms.SignName,
TemplateCode = Options.Sms.TemplateCode,
TemplateParam = System.Text.Json.JsonSerializer.Serialize(new { code })
};
var response = await _aliyunClient.SendSmsAsync(sendSmsRequest);
}
catch (Exception _error)
{
_logger.LogError(_error, "阿里云短信发送错误:" + _error.Message);
}
}
}
public interface IAliyunManger
{
Task SendSmsAsync(string phoneNumbers, string code);
}
}

View File

@@ -10,13 +10,13 @@ namespace Yi.Framework.Rbac.Domain.SignalRHubs
{
[HubRoute("/hub/main")]
[Authorize]
public class OnlineUserHub : AbpHub
public class OnlineUserHub : AbpHub
{
public static readonly List<OnlineUserModel> clientUsers = new();
private HttpContext? _httpContext;
private ILogger<OnlineUserHub> _logger=> LoggerFactory.CreateLogger<OnlineUserHub>();
private ILogger<OnlineUserHub> _logger => LoggerFactory.CreateLogger<OnlineUserHub>();
public OnlineUserHub(IHttpContextAccessor httpContextAccessor)
{
_httpContext = httpContextAccessor?.HttpContext;
@@ -68,10 +68,15 @@ namespace Yi.Framework.Rbac.Domain.SignalRHubs
//判断用户是否存在,否则添加集合
if (user != null)
{
clientUsers.Remove(user);
Clients.All.SendAsync("onlineNum", clientUsers.Count);
//Clients.All.SendAsync(HubsConstant.OnlineUser, clientUsers);
_logger.LogInformation($"用户{user?.UserName}离开了,当前已连接{clientUsers.Count}个");
var clientUser = clientUsers.FirstOrDefault(x => x.ConnnectionId == user.ConnnectionId);
if (clientUser is not null)
{
clientUsers.Remove(clientUser);
Clients.All.SendAsync("onlineNum", clientUsers.Count);
//Clients.All.SendAsync(HubsConstant.OnlineUser, clientUsers);
_logger.LogInformation($"用户{user?.UserName}离开了,当前已连接{clientUsers.Count}个");
}
}
return base.OnDisconnectedAsync(exception);
}

View File

@@ -1,19 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" />
<ItemGroup>
<PackageReference Include="AlibabaCloud.SDK.Dysmsapi20170525" Version="2.0.24" />
<PackageReference Include="IPTools.China" Version="1.6.0" />
<PackageReference Include="TencentCloudSDK" Version="3.0.917" />
<PackageReference Include="UAParser" Version="3.1.47" />
<PackageReference Include="Volo.Abp.AspNetCore.SignalR" Version="8.0.0-rc.3" />
<PackageReference Include="Volo.Abp.AspNetCore.SignalR" Version="8.0.0" />
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="8.0.0-rc.3" />
<PackageReference Include="Volo.Abp.Caching" Version="8.0.0-rc.3" />
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="8.0.0" />
<PackageReference Include="Volo.Abp.Caching" Version="8.0.0" />
</ItemGroup>

View File

@@ -7,6 +7,7 @@ using Yi.Framework.Mapster;
using Yi.Framework.Rbac.Domain.Authorization;
using Yi.Framework.Rbac.Domain.Operlog;
using Yi.Framework.Rbac.Domain.Shared;
using Yi.Framework.Rbac.Domain.Shared.Options;
namespace Yi.Framework.Rbac.Domain
{
@@ -22,11 +23,15 @@ namespace Yi.Framework.Rbac.Domain
public override void ConfigureServices(ServiceConfigurationContext context)
{
var service = context.Services;
var configuration = context.Services.GetConfiguration();
service.AddControllers(options =>
{
options.Filters.Add<PermissionGlobalAttribute>();
options.Filters.Add<OperLogGlobalAttribute>();
});
//配置阿里云短信
Configure<AliyunOptions>(configuration.GetSection(nameof(AliyunOptions)));
}
}
}