From f624a24a82ccb960731e4be95c13b69681eaa880 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A9=99=E5=AD=90?= <454313500@qq.com> Date: Tue, 11 Jan 2022 16:40:15 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=9D=83=E9=99=90=E7=82=B9?= =?UTF-8?q?=E5=AF=B9=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Yi.Framework.Net6/.dockerignore | 25 +++++ .../Controllers/AccountController.cs | 44 +++++---- .../Controllers/MenuController.cs | 7 +- .../Controllers/UserController.cs | 12 ++- .../Yi.Framework.ApiMicroservice/Program.cs | 4 + .../Yi.Framework.ApiMicroservice.csproj | 3 + .../3e1a699a-6634-4378-a98d-76a082843c92.jpg | Bin 0 -> 30394 bytes .../Yi.Framework.Common/Const/RedisConst.cs | 2 + .../Yi.Framework.Core/CacheClientDB.cs | 7 +- .../Yi.Framework.Core/MakeJwt.cs | 9 +- .../Yi.Framework.DTOModel/menuDto.cs | 19 ++++ .../Yi.Framework.Interface/IUserService.cs | 15 +++ .../Yi.Framework.Interface.csproj | 1 + .../Yi.Framework.Service/MenuService.cs | 5 +- .../Yi.Framework.Service/UserService.cs | 49 ++++++---- .../Yi.Framework.Service.csproj | 1 + .../CustomAuthorizationHandler.cs | 89 ++++++++++++++++++ .../CustomAuthorizationRequirement.cs | 19 ++++ .../AuthorizationPolicy/PolicyEnum.cs | 20 ++++ .../Yi.Framework.WebCore/CommonExtend.cs | 1 + .../Mapper/MapperHelper.cs | 8 ++ .../AuthorizationExtension.cs | 28 ++++++ 22 files changed, 319 insertions(+), 49 deletions(-) create mode 100644 Yi.Framework.Net6/.dockerignore create mode 100644 Yi.Framework.Net6/Yi.Framework.ApiMicroservice/wwwroot/image/3e1a699a-6634-4378-a98d-76a082843c92.jpg create mode 100644 Yi.Framework.Net6/Yi.Framework.DTOModel/menuDto.cs create mode 100644 Yi.Framework.Net6/Yi.Framework.WebCore/AuthorizationPolicy/CustomAuthorizationHandler.cs create mode 100644 Yi.Framework.Net6/Yi.Framework.WebCore/AuthorizationPolicy/CustomAuthorizationRequirement.cs create mode 100644 Yi.Framework.Net6/Yi.Framework.WebCore/AuthorizationPolicy/PolicyEnum.cs create mode 100644 Yi.Framework.Net6/Yi.Framework.WebCore/MiddlewareExtend/AuthorizationExtension.cs diff --git a/Yi.Framework.Net6/.dockerignore b/Yi.Framework.Net6/.dockerignore new file mode 100644 index 00000000..3729ff0c --- /dev/null +++ b/Yi.Framework.Net6/.dockerignore @@ -0,0 +1,25 @@ +**/.classpath +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/AccountController.cs b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/AccountController.cs index 62ec149c..6d815d82 100644 --- a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/AccountController.cs +++ b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/AccountController.cs @@ -16,6 +16,7 @@ using Yi.Framework.DTOModel; using Yi.Framework.Interface; using Yi.Framework.Model.Models; using Yi.Framework.WebCore; +using Yi.Framework.WebCore.AuthorizationPolicy; using Yi.Framework.WebCore.Mapper; namespace Yi.Framework.ApiMicroservice.Controllers @@ -32,7 +33,7 @@ namespace Yi.Framework.ApiMicroservice.Controllers private CacheClientDB _cacheClientDB; private IRoleService _roleService; private IHttpContextAccessor _httpContext; - public AccountController(ILogger logger, IUserService userService, IMenuService menuService,RabbitMQInvoker rabbitMQInvoker,CacheClientDB cacheClientDB, IRoleService roleService, IHttpContextAccessor httpContext) + public AccountController(ILogger logger, IUserService userService, IMenuService menuService, RabbitMQInvoker rabbitMQInvoker, CacheClientDB cacheClientDB, IRoleService roleService, IHttpContextAccessor httpContext) { _logger = logger; _userService = userService; @@ -52,18 +53,20 @@ namespace Yi.Framework.ApiMicroservice.Controllers [HttpPost] public async Task Login(loginDto login) { - var _user= MapperHelper.Map(login); + var _user = MapperHelper.Map(login); var user_data = await _userService.Login(_user); if (user_data == null) { return Result.Error("该用户不存在"); } var menuList = await _menuService.GetTopMenuByUserId(user_data.id); - if ( user_data!=null) - { - var token = MakeJwt.app(new jwtUser() {user=user_data,menuIds= menuList}); - + if (user_data != null) + { + var token = MakeJwt.app(new jwtUser() { user = user_data, menuIds = menuList }); JobModel.visitNum += 1; + //同时要将api路径放置到redis中 + var menuDto = MapperHelper.MapList(menuList); + _userService.SaveUserApi(user_data.id, menuDto); return Result.Success().SetData(new { user = new { user_data.id, user_data.username, user_data.introduction, user_data.icon, user_data.nick }, token }); } return Result.Error(); @@ -73,6 +76,7 @@ namespace Yi.Framework.ApiMicroservice.Controllers /// 不用写,单纯制作日志 /// /// + [HttpPost] public Result Logout() { @@ -88,17 +92,17 @@ namespace Yi.Framework.ApiMicroservice.Controllers [HttpPost] public async Task Register(user _user, string code) { - _user.username=_user.username.Trim(); - if(string.IsNullOrEmpty(_user.username)) - code = code.Trim(); + _user.username = _user.username.Trim(); + if (string.IsNullOrEmpty(_user.username)) + code = code.Trim(); - string trueCode= _cacheClientDB.Get(RedisConst.keyCode + _user.phone); + string trueCode = _cacheClientDB.Get(RedisConst.keyCode + _user.phone); if (code == trueCode) { //设置默认头像 var setting = JsonHelper.StrToObj(_cacheClientDB.Get(RedisConst.key)); _user.icon = setting.InitIcon; - _user.ip = _httpContext.HttpContext.Request.Headers["X-Real-IP"].FirstOrDefault();//通过上下文获取ip + _user.ip = _httpContext.HttpContext?.Request.Headers["X-Real-IP"].FirstOrDefault();//通过上下文获取ip //设置默认角色 if (string.IsNullOrEmpty(setting.InitRole)) { @@ -120,7 +124,7 @@ namespace Yi.Framework.ApiMicroservice.Controllers /// /// [HttpPost] - public async Task SendSMS(string SMSAddress) + public async Task SendSMS(string SMSAddress) { if (string.IsNullOrEmpty(SMSAddress)) { @@ -131,15 +135,15 @@ namespace Yi.Framework.ApiMicroservice.Controllers { SMSQueueModel sMSQueueModel = new SMSQueueModel(); sMSQueueModel.phone = SMSAddress; - sMSQueueModel.code =RandomHelper.GenerateCheckCodeNum(6); + sMSQueueModel.code = RandomHelper.GenerateCheckCodeNum(6); //10分钟过期 - _cacheClientDB.Set(RedisConst.keyCode+sMSQueueModel.phone, sMSQueueModel.code, TimeSpan.FromMinutes(10)); + _cacheClientDB.Set(RedisConst.keyCode + sMSQueueModel.phone, sMSQueueModel.code, TimeSpan.FromMinutes(10)); _rabbitMQInvoker.Send(new Common.IOCOptions.RabbitMQConsumerModel() { ExchangeName = RabbitConst.SMS_Exchange, QueueName = RabbitConst.SMS_Queue_Send }, JsonHelper.ObjToStr(sMSQueueModel)); return Result.Success("发送短信成功,10分钟后过期,请留意短信接收"); } - return Result.Error("该号码已被注册"); + return Result.Error("该号码已被注册"); } /// @@ -179,11 +183,11 @@ namespace Yi.Framework.ApiMicroservice.Controllers [HttpPut] [Authorize] public async Task ChangePassword(ChangePwdDto pwdDto) - { + { var user_data = await _userService.GetUserById(pwdDto.user.id); string msg = "修改成功"; - if (! string.IsNullOrEmpty( pwdDto.newPassword)) - { + if (!string.IsNullOrEmpty(pwdDto.newPassword)) + { if (user_data.password == pwdDto.user.password) { @@ -195,7 +199,7 @@ namespace Yi.Framework.ApiMicroservice.Controllers user_data.address = pwdDto.user.address; user_data.nick = pwdDto.user.nick; - + await _userService.UpdateAsync(user_data); user_data.password = null; return Result.Success(msg); @@ -219,6 +223,6 @@ namespace Yi.Framework.ApiMicroservice.Controllers return Result.Success(msg); } - + } } \ No newline at end of file diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/MenuController.cs b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/MenuController.cs index ce14e68b..7bb08bd4 100644 --- a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/MenuController.cs +++ b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/MenuController.cs @@ -19,9 +19,11 @@ namespace Yi.Framework.ApiMicroservice.Controllers public class MenuController : ControllerBase { private IMenuService _menuService; - public MenuController(IMenuService menuService) + private IUserService _userService; + public MenuController(IMenuService menuService,IUserService userService) { _menuService = menuService; + _userService = userService; } /// /// 这个是要递归的,但是要过滤掉删除的,所以,可以写一个通用过滤掉删除的方法 @@ -105,8 +107,7 @@ namespace Yi.Framework.ApiMicroservice.Controllers [HttpGet] public async Task GetTopMenusByHttpUser() { - HttpContext.GetCurrentUserInfo(out List menuIds); - + var menuIds = _userService.GetCurrentMenuInfo(HttpContext.GetCurrentUserInfo().id); return Result.Success().SetData(await _menuService.GetTopMenusByTopMenuIds(menuIds)); } } diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/UserController.cs b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/UserController.cs index c552a081..bb580786 100644 --- a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/UserController.cs +++ b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Controllers/UserController.cs @@ -10,6 +10,7 @@ using Yi.Framework.DTOModel; using Yi.Framework.Interface; using Yi.Framework.Model.Models; using Yi.Framework.WebCore; +using Yi.Framework.WebCore.AuthorizationPolicy; namespace Yi.Framework.ApiMicroservice.Controllers { @@ -31,6 +32,8 @@ namespace Yi.Framework.ApiMicroservice.Controllers /// 查 /// /// + + [Authorize(PolicyName.Menu)] [HttpGet] public async Task GetUser() { @@ -43,6 +46,7 @@ namespace Yi.Framework.ApiMicroservice.Controllers /// /// [HttpPut] + [Authorize(PolicyName.Menu)] public async Task UpdateUser(user _user) { await _userService.UpdateAsync(_user); @@ -56,6 +60,7 @@ namespace Yi.Framework.ApiMicroservice.Controllers /// /// [HttpDelete] + [Authorize(PolicyName.Menu)] public async Task DelListUser(List _ids) { await _userService.DelListByUpdateAsync(_ids); @@ -68,6 +73,7 @@ namespace Yi.Framework.ApiMicroservice.Controllers /// /// [HttpPost] + [Authorize(PolicyName.Menu)] public async Task AddUser(user _user) { await _userService.AddAsync(_user); @@ -109,7 +115,7 @@ namespace Yi.Framework.ApiMicroservice.Controllers [HttpGet] public async Task GetMenuByHttpUser() { - HttpContext.GetCurrentUserInfo(out var allMenuIds); + var allMenuIds= _userService.GetCurrentMenuInfo(HttpContext.GetCurrentUserInfo().id); return Result.Success().SetData(await _userService.GetMenuByHttpUser(allMenuIds)); } @@ -121,8 +127,8 @@ namespace Yi.Framework.ApiMicroservice.Controllers [HttpGet] public async Task GetAxiosByRouter(string router) { - - var _user = HttpContext.GetCurrentUserInfo(out List menuIds); + var _user = HttpContext.GetCurrentUserInfo(); + var menuIds = _userService.GetCurrentMenuInfo(_user.id); if (menuIds == null) { return Result.Error(); diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Program.cs b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Program.cs index 6a1ce8a9..3d8684a6 100644 --- a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Program.cs +++ b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Program.cs @@ -67,6 +67,10 @@ builder.Services.AddCorsService(); #endregion builder.Services.AddJwtService(); #region +//Ȩ +#endregion +builder.Services.AddAuthorizationService(); +#region //ݿ #endregion builder.Services.AddDbService(); diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Yi.Framework.ApiMicroservice.csproj b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Yi.Framework.ApiMicroservice.csproj index d27a1c55..67e6d2f3 100644 --- a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Yi.Framework.ApiMicroservice.csproj +++ b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/Yi.Framework.ApiMicroservice.csproj @@ -4,6 +4,8 @@ net6.0 enable enable + f5ce4739-9524-4330-9aea-cfcdb41501de + Linux @@ -23,6 +25,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/wwwroot/image/3e1a699a-6634-4378-a98d-76a082843c92.jpg b/Yi.Framework.Net6/Yi.Framework.ApiMicroservice/wwwroot/image/3e1a699a-6634-4378-a98d-76a082843c92.jpg new file mode 100644 index 0000000000000000000000000000000000000000..aa4daf73a8242565ffac4469083aa29d20c1cff3 GIT binary patch literal 30394 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 MP(Agz_y2qKf6`TAZ2$lO literal 0 HcmV?d00001 diff --git a/Yi.Framework.Net6/Yi.Framework.Common/Const/RedisConst.cs b/Yi.Framework.Net6/Yi.Framework.Common/Const/RedisConst.cs index 1c59a4db..13d1fa87 100644 --- a/Yi.Framework.Net6/Yi.Framework.Common/Const/RedisConst.cs +++ b/Yi.Framework.Net6/Yi.Framework.Common/Const/RedisConst.cs @@ -14,6 +14,8 @@ namespace Yi.Framework.Common.Const public const string key = "YiFramework:data"; public const string keyCode = "YiFramework:code"; + + public const string userMenusApi = "YiFramework:userMenusApi"; ///// ///// 初始化角色名 ///// diff --git a/Yi.Framework.Net6/Yi.Framework.Core/CacheClientDB.cs b/Yi.Framework.Net6/Yi.Framework.Core/CacheClientDB.cs index 32187406..c9ffbb7e 100644 --- a/Yi.Framework.Net6/Yi.Framework.Core/CacheClientDB.cs +++ b/Yi.Framework.Net6/Yi.Framework.Core/CacheClientDB.cs @@ -1040,9 +1040,14 @@ namespace Yi.Framework.Core public bool SetEntryInHash(string hashId, string key, T value) { + return this.TryCatch(() => this.client.SetEntryInHash(hashId, key, TextExtensions.SerializeToString(value)), hashId); } - + public bool SetEntryInHash(string hashId, string key, T value, TimeSpan expiresIn) + { + + return this.TryCatch(() => this.client.SetEntryInHash(hashId, key, TextExtensions.SerializeToString(value)), hashId); + } public T GetValueFromHash(string hashId, string key) { return this.TryCatch(() => JsonSerializer.DeserializeFromString(this.client.GetValueFromHash(hashId, key)), hashId); diff --git a/Yi.Framework.Net6/Yi.Framework.Core/MakeJwt.cs b/Yi.Framework.Net6/Yi.Framework.Core/MakeJwt.cs index 841351a2..08420c39 100644 --- a/Yi.Framework.Net6/Yi.Framework.Core/MakeJwt.cs +++ b/Yi.Framework.Net6/Yi.Framework.Core/MakeJwt.cs @@ -37,10 +37,11 @@ namespace Yi.Framework.Core claims.Add(new Claim(JwtRegisteredClaimNames.Exp, $"{new DateTimeOffset(DateTime.Now.AddMinutes(30)).ToUnixTimeSeconds()}")); claims.Add(new Claim(ClaimTypes.Name, _user.user.username)); claims.Add(new Claim(ClaimTypes.Sid, _user.user.id.ToString())); - foreach (var k in _user?.menuIds) - { - claims.Add(new Claim("menuIds",k.id.ToString())); - } + //现在不存放在jwt中,而存放在redis中 + //foreach (var k in _user?.menuIds) + //{ + // claims.Add(new Claim("menuIds",k.id.ToString())); + //} foreach (var k in _user.user.roles) { claims.Add(new Claim(ClaimTypes.Role, k.role_name)); diff --git a/Yi.Framework.Net6/Yi.Framework.DTOModel/menuDto.cs b/Yi.Framework.Net6/Yi.Framework.DTOModel/menuDto.cs new file mode 100644 index 00000000..4e52123b --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.DTOModel/menuDto.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.Model.Models; + +namespace Yi.Framework.DTOModel +{ + public class menuDto + { + public int id { get; set; } + public string icon { get; set; } + public string router { get; set; } + public string menu_name { get; set; } + + public mould mould { get; set; } + } +} diff --git a/Yi.Framework.Net6/Yi.Framework.Interface/IUserService.cs b/Yi.Framework.Net6/Yi.Framework.Interface/IUserService.cs index 86f11bce..76a268d1 100644 --- a/Yi.Framework.Net6/Yi.Framework.Interface/IUserService.cs +++ b/Yi.Framework.Net6/Yi.Framework.Interface/IUserService.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Yi.Framework.DTOModel; using Yi.Framework.Model.Models; namespace Yi.Framework.Interface @@ -67,5 +68,19 @@ namespace Yi.Framework.Interface /// Task> GetAxiosByRouter(string router,int userId, List menuIds); + + /// + /// 将登录用户的api保存的redis中 + /// + /// + /// + public bool SaveUserApi(int userId, List menus); + + /// + /// 通过用户id得到redis中菜单列表 + /// + /// + /// + public List GetCurrentMenuInfo(int userId); } } diff --git a/Yi.Framework.Net6/Yi.Framework.Interface/Yi.Framework.Interface.csproj b/Yi.Framework.Net6/Yi.Framework.Interface/Yi.Framework.Interface.csproj index cd69cc15..498021a8 100644 --- a/Yi.Framework.Net6/Yi.Framework.Interface/Yi.Framework.Interface.csproj +++ b/Yi.Framework.Net6/Yi.Framework.Interface/Yi.Framework.Interface.csproj @@ -17,6 +17,7 @@ + diff --git a/Yi.Framework.Net6/Yi.Framework.Service/MenuService.cs b/Yi.Framework.Net6/Yi.Framework.Service/MenuService.cs index 41f71ca9..5eb878a7 100644 --- a/Yi.Framework.Net6/Yi.Framework.Service/MenuService.cs +++ b/Yi.Framework.Net6/Yi.Framework.Service/MenuService.cs @@ -66,7 +66,10 @@ namespace Yi.Framework.Service var m = u.menus.Where(u => u.is_delete == Normal).ToList(); menuList = menuList.Union(m).ToList(); }); - return menuList; + + var menuIds=menuList.Select(u => u.id).ToList(); + + return await _DbRead.Set().Include(u => u.mould).Where(u => menuIds.Contains(u.id)).ToListAsync(); } } diff --git a/Yi.Framework.Net6/Yi.Framework.Service/UserService.cs b/Yi.Framework.Net6/Yi.Framework.Service/UserService.cs index 6e9396cf..b679451d 100644 --- a/Yi.Framework.Net6/Yi.Framework.Service/UserService.cs +++ b/Yi.Framework.Net6/Yi.Framework.Service/UserService.cs @@ -5,7 +5,9 @@ using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; +using Yi.Framework.Common.Const; using Yi.Framework.Core; +using Yi.Framework.DTOModel; using Yi.Framework.Interface; using Yi.Framework.Model; using Yi.Framework.Model.ModelFactory; @@ -15,6 +17,11 @@ namespace Yi.Framework.Service { public partial class UserService : BaseService, IUserService { + CacheClientDB _cacheClientDB; + public UserService(CacheClientDB cacheClientDB, IDbContextFactory DbFactory) : base(DbFactory) + { + _cacheClientDB = cacheClientDB; + } short Normal = (short)Common.Enum.DelFlagEnum.Normal; public async Task PhoneIsExsit(string smsAddress) { @@ -42,42 +49,43 @@ namespace Yi.Framework.Service /// public async Task GetUserById(int userId) { - return await _DbRead.Set().Include(u => u.roles).ThenInclude(u => u.menus).ThenInclude(u => u.children).ThenInclude(u => u.mould).Where(u=>u.id==userId).FirstOrDefaultAsync(); + return await _DbRead.Set().Include(u => u.roles).ThenInclude(u => u.menus).ThenInclude(u => u.children).ThenInclude(u => u.mould).Where(u => u.id == userId).FirstOrDefaultAsync(); } - public async Task> GetAxiosByRouter(string router, int userId, List menuIds) + public async Task> GetAxiosByRouter(string router, int userId, List menuIds) { - var user_data =await GetUserById(userId); + var user_data = await GetUserById(userId); List menuList = new(); - foreach(var item in user_data.roles) + foreach (var item in user_data.roles) { - var m=item.menus.Where(u =>u?.router?.ToUpper() == router.ToUpper()).FirstOrDefault(); + var m = item.menus.Where(u => u?.router?.ToUpper() == router.ToUpper()).FirstOrDefault(); if (m == null) { break; } - menuList = m.children?.Where(u => menuIds.Contains(u.id)&&u.is_delete==Normal).ToList(); - + menuList = m.children?.Where(u => menuIds.Contains(u.id) && u.is_delete == Normal).ToList(); + } - return menuList; - } + return menuList; + } public async Task GetMenuByHttpUser(List allMenuIds) { - var topMenu =await _DbRead.Set().Include(u => u.children).ThenInclude(u => u.children).ThenInclude(u => u.children).ThenInclude(u => u.children).ThenInclude(u => u.children).Where(u => u.is_top == (short)Common.Enum.ShowFlagEnum.Show).FirstOrDefaultAsync(); + var topMenu = await _DbRead.Set().Include(u => u.children).ThenInclude(u => u.children).ThenInclude(u => u.children).ThenInclude(u => u.children).ThenInclude(u => u.children).Where(u => u.is_top == (short)Common.Enum.ShowFlagEnum.Show).FirstOrDefaultAsync(); //现在要开始关联菜单了 return TreeMenuBuild.Sort(TreeMenuBuild.ShowFormat(topMenu, allMenuIds)); ; - } + } public async Task GetUserInRolesByHttpUser(int userId) { var data = await GetUserById(userId); - data.roles?.ForEach(u=> { + data.roles?.ForEach(u => + { u.users = null; u.menus = null; }); - return data; + return data; } public async Task Login(user _user) { - var user_data = await _DbRead.Set().Include(u => u.roles).Where(u => u.username == _user.username && u.password ==_user.password &&u.is_delete == Normal).FirstOrDefaultAsync(); + var user_data = await _DbRead.Set().Include(u => u.roles).Where(u => u.username == _user.username && u.password == _user.password && u.is_delete == Normal).FirstOrDefaultAsync(); return user_data; } @@ -93,12 +101,19 @@ namespace Yi.Framework.Service public async Task SetRoleByUser(List roleIds, List userIds) { - var user_data = await _DbRead.Set().Include(u => u.roles).Where(u => userIds.Contains(u.id)).ToListAsync(); + var user_data = await _DbRead.Set().Include(u => u.roles).Where(u => userIds.Contains(u.id)).ToListAsync(); var roleList = await _DbRead.Set().Where(u => roleIds.Contains(u.id)).ToListAsync(); - user_data.ForEach(u => u.roles = roleList); + user_data.ForEach(u => u.roles = roleList); return await UpdateListAsync(user_data); } - + public bool SaveUserApi(int userId, List menus) + { + return _cacheClientDB.Set(RedisConst.userMenusApi+":"+userId.ToString(),menus,new TimeSpan(0,30,0)); + } + public List GetCurrentMenuInfo(int userId) + { + return _cacheClientDB.Get>(RedisConst.userMenusApi+":"+userId).Select(u=>u.id).ToList(); + } } } diff --git a/Yi.Framework.Net6/Yi.Framework.Service/Yi.Framework.Service.csproj b/Yi.Framework.Net6/Yi.Framework.Service/Yi.Framework.Service.csproj index 7d3c9014..3591bcb8 100644 --- a/Yi.Framework.Net6/Yi.Framework.Service/Yi.Framework.Service.csproj +++ b/Yi.Framework.Net6/Yi.Framework.Service/Yi.Framework.Service.csproj @@ -18,6 +18,7 @@ + diff --git a/Yi.Framework.Net6/Yi.Framework.WebCore/AuthorizationPolicy/CustomAuthorizationHandler.cs b/Yi.Framework.Net6/Yi.Framework.WebCore/AuthorizationPolicy/CustomAuthorizationHandler.cs new file mode 100644 index 00000000..111842ea --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.WebCore/AuthorizationPolicy/CustomAuthorizationHandler.cs @@ -0,0 +1,89 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Claims; +using System.Threading.Tasks; +using Yi.Framework.Common.Const; +using Yi.Framework.Core; +using Yi.Framework.DTOModel; +using Yi.Framework.Model.Models; + +namespace Yi.Framework.WebCore.AuthorizationPolicy +{ + //策略验证的Handler 继承AuthorizationHandler 泛型类 泛型参数为 策略参数 + public class CustomAuthorizationHandler : AuthorizationHandler + { + + private CacheClientDB _cacheClientDB; + /// + /// 构造函数 + /// + public CustomAuthorizationHandler(CacheClientDB cacheClientDB) + { + _cacheClientDB= cacheClientDB; + } + + //验证的方法就在这里 + protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomAuthorizationRequirement requirement) + { + var currentClaim = context.User.Claims.FirstOrDefault(u => u.Type == ClaimTypes.Sid); + + if (currentClaim==null) //说明没有写入Sid 没有登录 + { + return Task.CompletedTask; //验证不同过 + } + + int currentUserId = 0; + if (!string.IsNullOrWhiteSpace(currentClaim.Value)) + { + currentUserId = Convert.ToInt32(currentClaim.Value); + } + DefaultHttpContext httpcontext = (DefaultHttpContext)context.Resource; + Dictionary dicMenueDictionary = new Dictionary(); + //现在只需要登录的时候把用户的api路径添加到redis去 + //每次访问的时候进行redis判断一下即可 + //注意一下,redis不能一直保存,和jwt一样搞一个期限 + var menuList=_cacheClientDB.Get>(RedisConst.userMenusApi+":"+currentUserId); + foreach (var k in menuList) + { + if (k.mould != null) + { + dicMenueDictionary.Add(k.mould?.id.ToString(), "/api"+ k.mould?.url); + } + + } + + if (dicMenueDictionary.ContainsValue(httpcontext.Request.Path)) + { + context.Succeed(requirement); //验证通过了 + } + return Task.CompletedTask; //验证不同过 + + } + } + + + /// + /// 菜单权限策略 + /// + public static class CustomAuthorizationHandlerExtension + { + public static Task AuthorizationMenueExtension(this AuthorizationHandlerContext handlerContext, CustomAuthorizationRequirement requirement) + { + bool bog = true; + if (bog) + { + return Task.Run(() => + { + handlerContext.Succeed(requirement); //验证通过了 + }); + } + else + { + return Task.CompletedTask; //验证不同过 + } + } + } +} diff --git a/Yi.Framework.Net6/Yi.Framework.WebCore/AuthorizationPolicy/CustomAuthorizationRequirement.cs b/Yi.Framework.Net6/Yi.Framework.WebCore/AuthorizationPolicy/CustomAuthorizationRequirement.cs new file mode 100644 index 00000000..a2b72310 --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.WebCore/AuthorizationPolicy/CustomAuthorizationRequirement.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Authorization; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Yi.Framework.WebCore.AuthorizationPolicy +{ + //定义策略参数,必须实现这个IAuthorizationRequirement接口 + public class CustomAuthorizationRequirement: IAuthorizationRequirement + { + public CustomAuthorizationRequirement(PolicyEnum policyname) + { + this.PolicyName = policyname; + } + public PolicyEnum PolicyName { get; set; } + + } +} diff --git a/Yi.Framework.Net6/Yi.Framework.WebCore/AuthorizationPolicy/PolicyEnum.cs b/Yi.Framework.Net6/Yi.Framework.WebCore/AuthorizationPolicy/PolicyEnum.cs new file mode 100644 index 00000000..ad8ac425 --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.WebCore/AuthorizationPolicy/PolicyEnum.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Yi.Framework.WebCore.AuthorizationPolicy +{ + public enum PolicyEnum + { + /// + /// 菜单 + /// + MenuPermissions, + //...还可以定义其他的各种权限策略名称 + } + public static class PolicyName + { + public const string Menu = "Menu"; + } +} diff --git a/Yi.Framework.Net6/Yi.Framework.WebCore/CommonExtend.cs b/Yi.Framework.Net6/Yi.Framework.WebCore/CommonExtend.cs index 35bf7cda..ccdc66ac 100644 --- a/Yi.Framework.Net6/Yi.Framework.WebCore/CommonExtend.cs +++ b/Yi.Framework.Net6/Yi.Framework.WebCore/CommonExtend.cs @@ -26,6 +26,7 @@ namespace Yi.Framework.WebCore /// /// 基于HttpContext,当前鉴权方式解析,获取用户信息 + /// 现在使用redis作为缓存,不需要将菜单存放至jwt中了 /// /// /// diff --git a/Yi.Framework.Net6/Yi.Framework.WebCore/Mapper/MapperHelper.cs b/Yi.Framework.Net6/Yi.Framework.WebCore/Mapper/MapperHelper.cs index d8b1b5f9..2812369f 100644 --- a/Yi.Framework.Net6/Yi.Framework.WebCore/Mapper/MapperHelper.cs +++ b/Yi.Framework.Net6/Yi.Framework.WebCore/Mapper/MapperHelper.cs @@ -28,5 +28,13 @@ namespace Yi.Framework.WebCore.Mapper IMapper mapper = new AutoMapper.Mapper(config); return mapper.Map(source); } + public static List MapList(List source) + { + var cfg = new MapperConfigurationExpression(); + cfg.CreateMap(); + var config = new MapperConfiguration(cfg); + IMapper mapper = new AutoMapper.Mapper(config); + return mapper.Map, List>(source); + } } } diff --git a/Yi.Framework.Net6/Yi.Framework.WebCore/MiddlewareExtend/AuthorizationExtension.cs b/Yi.Framework.Net6/Yi.Framework.WebCore/MiddlewareExtend/AuthorizationExtension.cs new file mode 100644 index 00000000..826520b9 --- /dev/null +++ b/Yi.Framework.Net6/Yi.Framework.WebCore/MiddlewareExtend/AuthorizationExtension.cs @@ -0,0 +1,28 @@ +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Yi.Framework.WebCore.AuthorizationPolicy; + +namespace Yi.Framework.WebCore.MiddlewareExtend +{ + public static class AuthorizationExtension + { + public static IServiceCollection AddAuthorizationService(this IServiceCollection services) + { + services.AddAuthorization(options => + { + options.AddPolicy(PolicyName.Menu, polic => + { + polic.AddRequirements(new CustomAuthorizationRequirement(PolicyEnum.MenuPermissions)); + }); + }); + + services.AddSingleton(); + return services; + } + } +}