From 7dd1810290f2b4f1290b983044dbcf09c6985ba3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A4=A7=E7=9F=B3=E5=A4=B4?= Date: Sun, 8 Oct 2023 10:54:30 +0800 Subject: [PATCH] =?UTF-8?q?[feat]=20OAuth=E7=99=BB=E5=BD=95=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5=E6=97=B6=E4=B8=8D=E8=A6=81=E8=BF=94=E5=9B=9E500?= =?UTF-8?q?=E3=80=82close=20https://github.com/NewLifeX/NewLife.Cube/issue?= =?UTF-8?q?s/85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- NewLife.CubeNC/Common/AreaRegistrationBase.cs | 206 +++++++++--------- .../Common/EntityAuthorizeAttribute.cs | 3 +- NewLife.CubeNC/Controllers/SsoController.cs | 17 +- .../WebMiddleware/RunTimeMiddleware.cs | 1 + 4 files changed, 115 insertions(+), 112 deletions(-) diff --git a/NewLife.CubeNC/Common/AreaRegistrationBase.cs b/NewLife.CubeNC/Common/AreaRegistrationBase.cs index f6afa459..26894ba2 100644 --- a/NewLife.CubeNC/Common/AreaRegistrationBase.cs +++ b/NewLife.CubeNC/Common/AreaRegistrationBase.cs @@ -1,141 +1,135 @@ -using System; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; +using System.Collections.Concurrent; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Controllers; -using NewLife.Cube.Entity; using NewLife.Cube.Membership; using NewLife.Log; using NewLife.Reflection; using XCode; using XCode.Membership; -namespace NewLife.Cube -{ - /// 区域特性基类 - /// - /// 提供以下功能: - /// 1,区域名称。从类名中截取。其中DisplayName特性作为菜单中文名。 - /// 2,静态构造注册一次视图引擎、绑定提供者、过滤器 - /// 3,注册区域默认路由 - /// - public class AreaBase : AreaAttribute - { - private static readonly ConcurrentDictionary _areas = new(); +namespace NewLife.Cube; - /// 实例化区域注册 - public AreaBase(String areaName) : base(areaName) => RegisterArea(GetType()); +/// 区域特性基类 +/// +/// 提供以下功能: +/// 1,区域名称。从类名中截取。其中DisplayName特性作为菜单中文名。 +/// 2,静态构造注册一次视图引擎、绑定提供者、过滤器 +/// 3,注册区域默认路由 +/// +public class AreaBase : AreaAttribute +{ + private static readonly ConcurrentDictionary _areas = new(); - /// 注册区域,每个继承此区域特性的类的静态构造函数都调用此方法,以进行相关注册 - public static void RegisterArea() where T : AreaBase => RegisterArea(typeof(T)); + /// 实例化区域注册 + public AreaBase(String areaName) : base(areaName) => RegisterArea(GetType()); - /// 注册区域,每个继承此区域特性的类的静态构造函数都调用此方法,以进行相关注册 - public static void RegisterArea(Type areaType) - { - if (!_areas.TryAdd(areaType, areaType)) return; + /// 注册区域,每个继承此区域特性的类的静态构造函数都调用此方法,以进行相关注册 + public static void RegisterArea() where T : AreaBase => RegisterArea(typeof(T)); - var ns = areaType.Namespace + ".Controllers"; - var areaName = areaType.Name.TrimEnd("Area"); - XTrace.WriteLine("开始注册权限管理区域[{0}],控制器命名空间[{1}]", areaName, ns); + /// 注册区域,每个继承此区域特性的类的静态构造函数都调用此方法,以进行相关注册 + public static void RegisterArea(Type areaType) + { + if (!_areas.TryAdd(areaType, areaType)) return; - // 更新区域名集合 - var rs = CubeService.AreaNames?.ToList() ?? new List(); - if (!rs.Contains(areaName)) - { - rs.Add(areaName); - CubeService.AreaNames = rs.ToArray(); - } + var ns = areaType.Namespace + ".Controllers"; + var areaName = areaType.Name.TrimEnd("Area"); + XTrace.WriteLine("开始注册权限管理区域[{0}],控制器命名空间[{1}]", areaName, ns); - // 自动检查并添加菜单 - var task = Task.Run(() => - { - using var span = DefaultTracer.Instance?.NewSpan(nameof(ScanController), areaType.FullName); - try - { - ScanController(areaType); - } - catch (Exception ex) - { - span?.SetError(ex, null); - XTrace.WriteException(ex); - } - }); - task.Wait(5_000); + // 更新区域名集合 + var rs = CubeService.AreaNames?.ToList() ?? new List(); + if (!rs.Contains(areaName)) + { + rs.Add(areaName); + CubeService.AreaNames = rs.ToArray(); } - /// 自动扫描控制器,并添加到菜单 - /// 默认操作当前注册区域的下一级Controllers命名空间 - protected static void ScanController(Type areaType) + // 自动检查并添加菜单 + var task = Task.Run(() => { - var areaName = areaType.Name.TrimEnd("Area"); - XTrace.WriteLine("start------初始化[{0}]的菜单体系------start", areaName); + using var span = DefaultTracer.Instance?.NewSpan(nameof(ScanController), areaType.FullName); + try + { + ScanController(areaType); + } + catch (Exception ex) + { + span?.SetError(ex, null); + XTrace.WriteException(ex); + } + }); + task.Wait(5_000); + } - var mf = ManageProvider.Menu; - if (mf == null) return; + /// 自动扫描控制器,并添加到菜单 + /// 默认操作当前注册区域的下一级Controllers命名空间 + protected static void ScanController(Type areaType) + { + var areaName = areaType.Name.TrimEnd("Area"); + XTrace.WriteLine("start------初始化[{0}]的菜单体系------start", areaName); - // 初始化数据库 - _ = Menu.Meta.Count; - //_ = ModelTable.Meta.Count; - //_ = ModelColumn.Meta.Count; + var mf = ManageProvider.Menu; + if (mf == null) return; - //using var tran = (mf as IEntityFactory).Session.CreateTrans(); + // 初始化数据库 + _ = Menu.Meta.Count; + //_ = ModelTable.Meta.Count; + //_ = ModelColumn.Meta.Count; - //var menus = mf.ScanController(areaName, areaType.Assembly, areaType.Namespace + ".Controllers"); - var menus = MenuHelper.ScanController(mf, areaName, areaType); + //using var tran = (mf as IEntityFactory).Session.CreateTrans(); - // 更新区域名称为友好中文名 - var menu = mf.Root.FindByPath(areaName); - if (menu != null && menu.DisplayName.IsNullOrEmpty()) - { - var dis = areaType.GetDisplayName(); - var des = areaType.GetDescription(); + //var menus = mf.ScanController(areaName, areaType.Assembly, areaType.Namespace + ".Controllers"); + var menus = MenuHelper.ScanController(mf, areaName, areaType); - if (!dis.IsNullOrEmpty()) menu.DisplayName = dis; - if (!des.IsNullOrEmpty()) menu.Remark = des; + // 更新区域名称为友好中文名 + var menu = mf.Root.FindByPath(areaName); + if (menu != null && menu.DisplayName.IsNullOrEmpty()) + { + var dis = areaType.GetDisplayName(); + var des = areaType.GetDescription(); - (menu as IEntity).Update(); - } + if (!dis.IsNullOrEmpty()) menu.DisplayName = dis; + if (!des.IsNullOrEmpty()) menu.Remark = des; - //tran.Commit(); + (menu as IEntity).Update(); + } - //// 扫描模型表 - //ScanModel(areaName, menus); + //tran.Commit(); - // 再次检查菜单权限,因为上面的ScanController里开启菜单权限检查时,菜单可能还没有生成 - var task = Task.Run(() => - { - //Thread.Sleep(1000); - XTrace.WriteLine("新增了菜单,需要检查权限。二次检查,双重保障"); - typeof(Role).Invoke("CheckRole"); - }); - task.Wait(5_000); + //// 扫描模型表 + //ScanModel(areaName, menus); - XTrace.WriteLine("end---------初始化[{0}]的菜单体系---------end", areaName); - } + // 再次检查菜单权限,因为上面的ScanController里开启菜单权限检查时,菜单可能还没有生成 + var task = Task.Run(() => + { + //Thread.Sleep(1000); + XTrace.WriteLine("新增了菜单,需要检查权限。二次检查,双重保障"); + typeof(Role).Invoke("CheckRole"); + }); + task.Wait(5_000); - private static ICollection _namespaces; + XTrace.WriteLine("end---------初始化[{0}]的菜单体系---------end", areaName); + } - /// 判断控制器是否归属于魔方管辖 - /// - /// - public static Boolean Contains(ControllerActionDescriptor controllerActionDescriptor) - { - // 判断控制器是否在管辖范围之内 - var controller = controllerActionDescriptor.ControllerTypeInfo; - var ns = controller.Namespace; - if (!ns.EndsWith(".Controllers")) return false; + private static ICollection _namespaces; - _namespaces ??= new HashSet(_areas.Keys.Select(e => e.Namespace)); + /// 判断控制器是否归属于魔方管辖 + /// + /// + public static Boolean Contains(ControllerActionDescriptor controllerActionDescriptor) + { + // 判断控制器是否在管辖范围之内 + var controller = controllerActionDescriptor.ControllerTypeInfo; + var ns = controller.Namespace; + if (!ns.EndsWith(".Controllers")) return false; - // 该控制器父级命名空间必须有对应的区域注册类,才会拦截其异常 - ns = ns.TrimEnd(".Controllers"); - return _namespaces.Contains(ns); - } + _namespaces ??= new HashSet(_areas.Keys.Select(e => e.Namespace)); - /// 获取所有区域 - /// - public static ICollection GetAreas() => _areas.Keys; + // 该控制器父级命名空间必须有对应的区域注册类,才会拦截其异常 + ns = ns.TrimEnd(".Controllers"); + return _namespaces.Contains(ns); } + + /// 获取所有区域 + /// + public static ICollection GetAreas() => _areas.Keys; } \ No newline at end of file diff --git a/NewLife.CubeNC/Common/EntityAuthorizeAttribute.cs b/NewLife.CubeNC/Common/EntityAuthorizeAttribute.cs index ff38ac8a..9212c776 100644 --- a/NewLife.CubeNC/Common/EntityAuthorizeAttribute.cs +++ b/NewLife.CubeNC/Common/EntityAuthorizeAttribute.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections.Concurrent; +using System.Collections.Concurrent; using System.Reflection; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http.Extensions; diff --git a/NewLife.CubeNC/Controllers/SsoController.cs b/NewLife.CubeNC/Controllers/SsoController.cs index 64aaa986..5c84f671 100644 --- a/NewLife.CubeNC/Controllers/SsoController.cs +++ b/NewLife.CubeNC/Controllers/SsoController.cs @@ -8,6 +8,7 @@ using NewLife.Cube.Web.Models; using NewLife.Log; using NewLife.Model; +using NewLife.Net; using NewLife.Remoting; using NewLife.Security; using NewLife.Web; @@ -82,12 +83,20 @@ static SsoController() public virtual ActionResult Login(String name) { var prov = Provider; - var client = prov.GetClient(name); - client.Init(GetUserAgent()); - var rurl = prov.GetReturnUrl(Request, true); - return base.Redirect(OnLogin(client, null, rurl, null)); + try + { + var client = prov.GetClient(name); + client.Init(GetUserAgent()); + + return base.Redirect(OnLogin(client, null, rurl, null)); + } + catch (InvalidOperationException) + { + var retUrl = "~/Admin/User/Login".AppendReturn(rurl); + return Redirect(retUrl); + } } private String OnLogin(OAuthClient client, String state, String returnUrl, OAuthLog log) diff --git a/NewLife.CubeNC/WebMiddleware/RunTimeMiddleware.cs b/NewLife.CubeNC/WebMiddleware/RunTimeMiddleware.cs index c04b82b5..78c24f69 100644 --- a/NewLife.CubeNC/WebMiddleware/RunTimeMiddleware.cs +++ b/NewLife.CubeNC/WebMiddleware/RunTimeMiddleware.cs @@ -41,6 +41,7 @@ public async Task Invoke(HttpContext ctx) var userAgent = ctx.Request.Headers["User-Agent"] + ""; var ua = new UserAgentParser(); ua.Parse(userAgent); + ctx.Items["UserAgent"] = ua; // 识别拦截爬虫 if (!ValidRobot(ctx, ua)) return;