ASP.NET MVC的5种AuthorizationFilter

一、IAuthorizationFilter

所有的AuthorizationFilter实现了接口IAuthorizationFilter。如下面的代码片断所示,IAuthorizationFilter定义了一个OnAuthorization方法用于实现授权的操作。作为该方法的参数filterContext是一个表示授权上下文的AuthorizationContext对象, 而AuthorizationContext直接继承自ControllerContext。

 1: public interface IAuthorizationFilter
 2: { 
 3: void OnAuthorization(AuthorizationContext filterContext);
 4: }
 5:  
 6: public class AuthorizationContext : ControllerContext
 7: { 
 8: public AuthorizationContext(); 
 9: public AuthorizationContext(ControllerContext controllerContext, ActionDescriptor actionDescriptor);
 10: 
 11: public virtual ActionDescriptor ActionDescriptor { get; set; }
 12: public ActionResult Result { get; set; }
 13: }

AuthorizationContext的ActionDescriptor属性表示描述当前执行Action的ActionDescriptor对象,而Result属性返回一个用于在授权阶段呈现的ActionResult。AuthorizationFilter的执行是ActionInvoker进行Action执行的第一项工作,因为后续的工作(Model绑定、Model验证、Action方法执行等)只有在成功授权的基础上才会有意义

ActionInvoker在通过执行AuthorizationFilter之前,会先根据当前的Controller上下文和解析出来的用于描述当前Action的ActionDescriptor,并以此创建一个表示授权上下文的AuthorizationContext对象。然后将此AuthorizationContext对象作为参数,按照Filter对象Order和Scope属性决定的顺序执行所有AuthorizationFilter的OnAuthorization。

在所有的AuthorizationFilter都执行完毕之后,如果指定的AuthorizationContext对象的Result属性表示得ActionResult不为Null,整个Action的执行将会终止,而ActionInvoker将会直接执行该ActionResult。一般来说,某个AuthorizationFilter在对当前请求实施授权的时候,如果授权失败它可以通过设置传入的AuthorizationContext对象的Result属性响应一个“401,Unauthrized”回复,或者呈现一个错误页面。

二、AuthorizeAttribute

如果我们要求某个Action只能被认证的用户访问,可以在Controller类型或者Action方法上应用具有如下定义的AuthorizeAttribute特性。AuthorizeAttribute还可以具体限制目标Action可被访问的用户或者角色,它的Users和Roles属性用于指定被授权的用户名和角色列表,中间用采用逗号作为分隔符。如果没有显式地对Users和Roles属性进行设置,AuthorizeAttribute在进行授权操作的时候只要求访问者是被认证的用户。

 1: [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited=true, AllowMultiple=true)]
 2: public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
 3: {
 4: //其他成员 
 5: public virtual void OnAuthorization(AuthorizationContext filterContext);
 6: protected virtual HttpValidationStatus OnCacheAuthorization(HttpContextBase httpContext);
 7: 
 8: public string Roles { get; set; }
 9: public override object TypeId { get; }
 10: public string Users { get; set; }
 11: }

如果授权失败(当前访问者是未被授权用户,或者当前用户的用户名或者角色没有在指定的授权用户或者角色列表中),AuthorizeAttribute会创建一个HttpUnauthorizedResult对象,并赋值给AuthorizationContext的Result属性,意味着会响应一个状态为“401,Unauthorized”的回复。如果采用Forms认证,配置的登录页面会自动被显示。

很多会将AuthorizeAttribute对方法的授权与PrincipalPermissionAttribute等同起来,实际上不但它们实现授权的机制不一样(后者是通过代码访问安全检验实现对方法调用的授权),它们的授权策略也一样。以下面定义的两个方法为例,应用了PrincipalPermissionAttribute的FooOrAdmin意味着可以被帐号为Foo或者具有Admin角色的用户访问,而应用了AuthorizeAttribute特性的方法FooAndAdmin方法则只能被用户Foo访问,而且该用户必须具有Admin角色。也就是说PrincipalPermissionAttribute特性对User和Role的授权逻辑是“逻辑或”,而AuthorizeAttribute 采用的则是“逻辑与”。

 1: [PrincipalPermission( SecurityAction.Demand,Name="Foo", Role="Admin")]
 2: public void FooOrAdmin()
 3: { }
 4:  
 5: [Authorize(Users="Foo", Roles="Admin")]
 6: public void FooAndAdmin()
 7: { }

除此之外,我们可以将多个PrincipalPermissionAttribute和AuthorizeAttribute应用到同一个类型或者方法上。对于前者,如果当前用于通过了任意一个PrincipalPermissionAttribute特性的授权就有权调用目标方法;对于后者来说,意味着需要通过所有AuthorizeAttribute特性的授权在具有了调用目标方法的权限。以如下两个方法为例,用户Foo或者Bar可以有权限调用FooOrBar方法,但是没有任何一个用户有权调用CannotCall方法(因为一个用户只一个用户名)。

 1: [PrincipalPermission( SecurityAction.Demand, Name="Foo")
 2: [PrincipalPermission( SecurityAction.Demand, Name="Bar")]
 3: public void FooOrBar()
 4: { }
 5:  
 6: [Authorize(Users="Foo")]
 7: [Authorize(Users="Bar")]
 8: public void CannotCall()
 9: {}

三、RequireHttpsAttribute

从名称也可以看出来来,RequireHttpsAttribute这个AuthorizationFilter要求用用户总是以HTTP请求的方式访问目标方法。如果当前并不是一个HTTPS请求(通过当前HttpRequest的IsSecureConnection属性判断),在HTTP方法为GET的情下,会创建一个RedirectResult对象并用其对AuthorizationContext的Result属性进行设置,当前请求的URL地址的Scheme替换成HTTPS就成了该RedirectResult的地址。也就是说,如果当前请求地址为http://www.artech.com/home/index,会自动重定向到https://www.artech.com/home/index

 1: [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited=true, AllowMultiple=false)]
 2: public class RequireHttpsAttribute : FilterAttribute, IAuthorizationFilter
 3: { 
 4: protected virtual void HandleNonHttpsRequest(AuthorizationContext filterContext);
 5: public virtual void OnAuthorization(AuthorizationContext filterContext);
 6: }

如果当前请求的HTTP方法并不是GET,RequireHttpsAttribute会直接抛出一个InvalidOperationException异常。如上面的代码片断所示,针对非HTTPS请求的处理通过调用受保护的方法HandleNonHttpsRequest来完成,如果我们需要不同的处理,可以继承RequireHttpsAttribute并重写该方法。

四、ValidateInputAttribute

为了避免用户在请求中包含一些不合法的内容对网站进行恶意攻击(比如XSS攻击),我们一般需要对请求的输入进行验证。如下面的代码片断所示,表示HTTP请求的基类HttpRequestBase具有一个ValidateInput方法用于验证请求的输入。实际上这个方法仅仅是在请求上作一下标记而已,在读取相应的请求输入时才根据这些表示决定是否需要进行相应的验证。不过为了便于表达,我们就将针对该ValidateInput方法的调用说成是针对请求输入的验证。

 1: public abstract class HttpRequestBase
 2: {
 3: //其他成员
 4: public virtual void ValidateInput();
 5: }

所有Controller的基类ControllerBase具有如下一个布尔类型的属性ValidateRequest表示是否需要对请求输入进行验证,在默认情况下该属性的默认值为True,意味着针对请求输入的验证默认情况下是开启的。 当ActionInvoker在完成了对所有AuthorizationFilter的执行之后,会根据该属性决定是否会通过调用表示当前请求的HttpRequest对象的ValidateInput方法进行请求输入的验证。

 1: public abstract class ControllerBase : IController
 2: {
 3: //其他成员
 4: public bool ValidateRequest { get; set; }
 5: }

也正是由于ActionInvoker针对请求输入验证是在完成了所有AuthorizationFilter的执行之后进行的,所以我们可以通过自定义AuthorizationFilter的方式来设置当前Controller的ValidateRequest属性进而开启或者关闭针对请求输入的验证。ValidateInputAttribute就是这么做的,我们可以从如下表示ValidateInputAttribute的定义看出来(构造函数的参数enableValidation表示是否启动针对请求的输入验证)。

 1: [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited=true, AllowMultiple=false)]
 2: public class ValidateInputAttribute : FilterAttribute, IAuthorizationFilter
 3: { 
 4: public ValidateInputAttribute(bool enableValidation)
 5: {
 6: this.EnableValidation = enableValidation;
 7: }
 8:  
 9: public virtual void OnAuthorization(AuthorizationContext filterContext)
 10: {
 11: if (filterContext == null)
 12: {
 13: throw new ArgumentNullException("filterContext");
 14: }
 15: filterContext.Controller.ValidateRequest = this.EnableValidation;
 16: }
 17:  
 18: public bool EnableValidation { get; private set; }
 19: }

为了让读者对ValidateInputAttribute这个AuthorizationFilter针对开启和关闭输入验证的作用有一个深刻映像,我们来进行一个简单的实例演示。在通过Visual Studio的ASP.NET MVC项目模板创建的空Web应用中我们 定义了如下一个HomeController,包含在该Controller中的两个Action方法(Action1和Action2)具有一个字符串类型的参数foo,其中Action1上应用了ValidateInputAttribute特性并将参数设置为False。

 1: public class HomeController : Controller
 2: {
 3: [ValidateInput(false)]
 4: public void Action1(string foo, string bar)
 5: { 
 6: Response.Write(string.Format("{0}: {1}<br/>", "foo", Server.HtmlEncode(foo)));
 7: Response.Write(string.Format("{0}: {1}<br/>", "bar", Server.HtmlEncode(bar)));
 8: }
 9:  
 10: public void Action2(string foo, string bar)
 11: { 
 12: Response.Write(string.Format("{0}: {1}<br/>", "foo", Server.HtmlEncode(foo)));
 13: Response.Write(string.Format("{0}: {1}<br/>", "bar", Server.HtmlEncode(bar)));
 14: }
 15: }

我们直接运行该程序并在浏览器中通过输入相应的地址来访问这两个Action,并以查询字符串的形式指定它们的两个参数。为了检验ASP.NET MVC对请求输入的验证,我们将表示参数foo的查询字符串的值设置为为“<script></script>”。如下图所示,Action1能够正常地被调用,而Action2在调用过程中抛出异常 ,并提示请求中包含危险的查询字符串。

image

在前面文章中我们谈到可以通过AllowHtmlAttribute特性来定义表示Model元数据的ModelMetadata的RequestValidationEnabled属性的设置从而忽略对相应属性数据的验证,使之可以包含具有HTML标签的数据。这与ValidateInputAttribute的作用类似,不同的是AllowHtmlAttribute仅仅针对Model对象的默认属性,而ValidateInputAttribute则是针对整个请求。

五、ValidateAntiForgeryTokenAttribute

具有如下定义的System.Web.Mvc.ValidateAntiForgeryTokenAttribute用于解决一种叫做“跨站请求伪造(CSRF:Cross-Site Request Forgery)”。这是一种不同于XSS(Cross Site Script)的跨站网络攻击,如果说XSS是利用了用户对网站的信任,而CSRF就是利用了站点对认证用户的信任。

 1: [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple=false, Inherited=true)]
 2: public sealed class ValidateAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter
 3: { 
 4: public ValidateAntiForgeryTokenAttribute();
 5: public void OnAuthorization(AuthorizationContext filterContext);
 6: public string Salt { get; set; }
 7: }

我们通过一个简单的例子来对CSRF的原理进行说明。假设我们通过ASP.NET MVC构建了一个博客应用,作为博主的用户可以发表博文,而一般用于可以对博文发表评论。除此之外,注册用于可以修改自己的Email地址,相关的操作定义在如下所示的BlogController的Action方法UpdateAddress中。

 1: public class BlogController: Controller
 2: { 
 3: [Authorize]
 4: [HttpPost]
 5: public void UpdateEmailAddress(string emailAddress)
 6: { 
 7: //Email地址修改操作
 8: } 
 9: //其他成员
 10: }

对于上面定义的UpdateEmailAddress方法,由于应用了AuthorizeAttribute特性,意味着只有认证的用户才能调用它来修改自己提供的Email地址。此外,HttpPostAttribute特性应用在该Action方法上,使我们只能以POST请求的方式调用它,这无形之中也增强了安全系数。但是这个方法提供的Email修改功能真的安全吗?它真的确保修改后的Email地址真的是登录用户提供的Email地址吗?

我们假设BlogController所在的Web应用部署的域名为Foo,那么Action方法UpdateEmailAddress对应的地址可以表示为http://foo/blog/updateemailaddress。现在一个恶意攻击者创建如下一个简单的HTML页面,该页面具有一个指向上面这个地址的表单,并且该表单中具有一个名为emailAddress <input>元素提供属于供给者自身的Email地址。由于注册了window的onload事件,该表单会在页面加载完成之后自动提交。

 1: <html>
 2: <head>
 3: <script type="text/javascript">
1:  
 2: window.onload = function () {
 3: document.getElementById("updateEmail").submit();
 4: }
 5: 
</script>
 4: </head>
 5: <body>
 6: <form id="updateEmail" action="http://foo/blog/updateemailaddress" 
 7: method="post"> 
 8: <input type="hidden" name="emailAddress" value="malicious@gmail.com" />
 9: </form>
 10: </body>
 11: </html>

假设攻击者部署该页面的地址为http://bar/maliciouspage.html。然后它通过某篇博文中添加一个包含如下链接的评论。作为登录用户的你点击该连接后将会间接地调用定义在BlogController的UpdateEmailAddress方法。由于登录用户的安全令牌一般以Cookie形式存在,而该Cookie会存在于发送给针对Action方法UpdateEmailAddress的调用请求中,服务器会认为该请求来自被认证用户,所以最终造成了你的Email地址被恶意修改而不自知。如果攻击者具有你的用户名,它可以通过重置密码,是新的密码发送到属于他自己的电子邮箱中。

 1: <img src="http://bar/maliciouspage.html"/>

这个例子充分说明了CSRF是一种比较隐蔽并且具有很大危害型的网络攻击,促成攻击的原因在于服务器在针对某个请求执行某个操作的时候并没有验证请求的真正来源。对于ASP.NET MVC来说,如果我们在执行某个Action方法之前能够确认当前的请求来源的有效性,就能从根本上解决CSRF攻击,而ValidateAntiForgeryTokenAttribute结合HtmlHelper的AntiForgeryToken方法有效地解决了这个问题。

 1: public class HtmlHelper
 2: {
 3: //其他成员
 4: public MvcHtmlString AntiForgeryToken();
 5: public MvcHtmlString AntiForgeryToken(string salt);
 6: public MvcHtmlString AntiForgeryToken(string salt, string domain, string path);
 7: }

如上面的代码片断所示,HtmlHelper具有三个AntiForgeryToken方法(这里的方式是HtmlHelper的实例方法,不是扩展方法)。当我们在一个View中调用这些方法是,它们会为我们生成一个所谓“防伪令牌(Anti-Forgery Token)”的字符串,并以此生成一个类型为Hidden的<input>元素。除此之外,该方法的调用还会根据这个防伪令牌设置一个Cookie。接下来我们来详细地来讨论这个过程。

上述的这个防伪令牌通过内部类型为AntiForgeryData的对象生成。如下面的代码片断所示,AntiForgeryData具有四个属性,其核心是通过属性Value表示的值。属性UserName和CreationDate表示访问令牌授权的用户名和创建时间。字符串属性Salt是为了增强防伪令牌的安全系数,不同的Salt值对应着不同的防伪令牌,不同的防伪令牌在不同的地方被使用以避免供给者对一个防伪令牌的破解而使整个应用受到全面的攻击。ValidateAntiForgeryTokenAttribute也具有一个同名的属性。

 1: internal sealed class AntiForgeryData
 2: { 
 3: public string Value { get; set; }
 4: public string Salt { get; set; } 
 5: public DateTime CreationDate { get; set; }
 6: public string Username { get; set; } 
 7: }

当AntiForgeryToken被调用的时候,会先根据当前的请求的应用路径(对应HttpRequest的ApplicationPath属性)计算出表示防伪令牌Cookie的名称,该名称会在通过对应用路径进行Base64编码(编码之前需要进行一些特殊字符的替换工作)生成的字符串前添加“__RequestVerificationToken”前缀。

如果当前请求具有一个同名的Cookie,则直接通过对Cookie的值进行反序列化得到一个AntiForgeryData对象。需要注意的是,这里针对AntiForgeryData进行序列化和反序列化并不是一个简单地实现运行时对象到字符串之间的转换,还包含采用MachineKey对AntiForgeryData的四个属性进行加密/解密的过程。如果这样的Cookie不存在,HtmlHelper会随机生成一个长度为16的字节数组,并将对该字节数组进行Base64编码后生成的字符串作为值创建一个AntiForgeryData对象。系统当前时间(UTC)作为该AntiForgeryData对象的创建时间,但是该AntiForgeryData对象的UserName和Salt属性为空。

接下来HtmlHelper会根据之前计算出来的Cookie名称创建一个)HttpCookie对象,而新创建出来的AntiForgeryData对象被序列化后生成的字符串作为该HttpCookie的值。如果我们在AntiForgeryToken方法调用中设置了表示域和路径的domain和path参数,它们将会作为该HttpCookie对象的Path和Domain属性。最后HtmlHelper将HttpCookie对象设置给当前的HTTP响应。

AntiForgeryToken返回的是一个类型为hidden的<input>元素对应的HTML,该Hidden元素的名称为“__RequestVerificationToken”(即代码访问令牌Cookie名称的前缀)。为了生成该Hidden元素的值,HtmlHelper会根据现有的AntiForgeryData对象(从当前请求获取的或者新创建的)创建一个新的AntiForgeryData对象,两个对象具有相同的CreationDate和Value属性,而当前用户名和指定的Salt参数将会设置给新AntiForgeryData对象的UserName和Salt属性。

 1: @using (Html.BeginForm())
 2: {
 3: @Html.AntiForgeryToken("647B8734-EFCA-4F51-9D98-36502D13E4E7")
 4: ...
 5: }

在一个View中我们通过如上的代码在一个表单中调用HtmlHelper的AntiForgeryToken方法并将一个GUID作为Salt,最终将会生成如下一个名为“__RequestVerificationToken”的Hidden元素。

 1: <form action="..." method="post">
 2: <input name="__RequestVerificationToken" type="hidden" value="yvLaFQ81JVgguKECyF/oQ+pc2/6q0MuLEaF73PvY7pvxaE68lO5qgXZWhfqIk721CBS0SJZjvOjbc7o7GL3SQ3RxIW90no7FcxzR6ohHUYEKdxyfTBuAVjAuoil5miwoY8+6HNoSPbztyhMVvtCsQDtvQfyW1GNa7qvlQSqYxQW7b6nAR2W0OxNi4NgrFEqbMFrD+4CwwAg4PUWpvcQxYA==" />
 3: ...
 4: </form>

对于该View的首次访问(或者对应的Cookie不存在),如下所示的名称为“__RequestVerificationToken_L012Y0FwcDEx”防伪令牌Cookie将会设置,并且是HttpOnly的。

 1: HTTP/1.1 200 OK
 2: Cache-Control: private
 3: ...
 4: Set-Cookie: __RequestVerificationToken_L012Y0FwcDEx=EYPOofprbB0og8vI+Pzr1unY0Ye5BihYJgoIYBqzvZDZ+hcT5QUu+fj2hvFUVTTCFAZdjgCPzxwIGsoNdEyD8nSUbgapk8Xp3+ZD8cxguUrgl0lAdFd4ZGWEYzz0IN58l5saPJpuaChVR4QaMNbilNG4y7xiN2/UCrBF80LmPO4=; path=/; HttpOnly
 5: ...

对于一个请求,如果确保请求提供的表单中具有一个名为“__RequestVerificationToken”的Hidden元素,并且该元素的值与对应的防伪令牌的Cookie值相匹配,就能够确保请求并不是由第三方恶意站点发送的,进而防止CSRF攻击。原因很简单:由于Cookie值是经过加密的,供给者可以得到整个Cookie的内容,但是不能解密获得具体的值(AntiForgeryData的Value属性),所以不可能在提供的表单中也包含一个具有匹配值的Hidden元素。针对防伪令牌的验证就实现在ValidateAntiForgeryTokenAttribute的OnAuthorization方法中。

我们来具体介绍一下实现在ValidateAntiForgeryTokenAttribute中针对防伪令牌的验证逻辑。首先它根据当前请求的应用路径采用与生成防伪令牌Cookie相同的逻辑计算出Cookie名称。如果对应的Cookie不存在于当前请求中,则直接抛出HttpAntiForgeryException异常;否则获取Cookie值,并反序列化生成一个AntiForgeryData对象。

然后从提交的表单中提取一个名称为“__RequestVerificationToken”的输入元素,如果这样的元素不存在,同样抛出HttpAntiForgeryException异常;否则直接对具体的值进行反序列化生成一个AntiForgeryData对象。最后ValidateAntiForgeryTokenAttribute对这两个AntiForgeryData的Value属性进行比较,以及后者的UserName和Salt属性与当前用户名和自身的Salt属性值进行比较,任何一个不匹配都会抛出HttpAntiForgeryException异常。

六、ChildActionOnlyAttribute

如果我们希望定义在Controol中的方法能以子Action的形式在某个View中被调用,这样的调用一般用于生成组成整个View的某个部分的HTML,我们可以在方法上应用ChildActionOnlyAttribute特性。从如下给出的定义可以看出,ChildActionOnlyAttribute实际上是一个AuthorizationFilter,它在重写的OnAuthorization方法中对当前请求进行验证,对于非子Action调用下直接抛出InvalidOperationException异常。

 1: [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple=false, Inherited=true)]
 2: public sealed class ChildActionOnlyAttribute : FilterAttribute, IAuthorizationFilter
 3: {
 4: public void OnAuthorization(AuthorizationContext filterContext);
 5: }

有的读者可能会问,AuthorizationFilter如何区分当前的请求是基于子Action的调用,而不是一般的Action调用呢?其实很简单,当我们在调用HtmlHelper的扩展方法Action或者RenderAction的时候会将当前的View上下文作为“父View上下文”保存到表示当前路由信息的RouteData的DataTokens属性中,对应的Key为“ParentActionViewContext”。如下面的代码片断所示,ControllerContext中用于判断是否为子Action请求的IsChildAction属性正式通过该路由信息进行判断的。

 1: public class ControllerContext
 2: {
 3: //其他成员
 4: public virtual bool IsChildAction
 5: {
 6: get
 7: {
 8: RouteData routeData = this.RouteData;
 9: if (routeData == null)
 10: {
 11: return false;
 12: }
 13: return routeData.DataTokens.ContainsKey("ParentActionViewContext");
 14: }
 15: }
 16: }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/579572.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从计算机内存结构到iOS

一、冯.诺伊曼结构 当前计算机都是冯.诺伊曼结构&#xff08;Von Neumann architecture&#xff09;&#xff0c;是指存储器存放程序的指令以及数据&#xff0c;在程序运行时根据需要提供给CPU使用。 冯.诺伊曼瓶颈 在目前的科技水平之下&#xff0c;CPU与存储器之间的读写速…

挑战与应对:迅软科技探讨IT企业应对数据泄密危机的智慧之路

随着信息技术的快速发展&#xff0c;软件IT行业面临着前所未有的数据安全挑战。黑客攻击、病毒传播、内部泄密等安全威胁层出不穷&#xff0c;给企业的核心资产和运营带来严重威胁。同时&#xff0c;国家对于数据安全的法律法规也日益严格&#xff0c;要求企业必须采取更加有效…

https密钥认证、上传镜像实验

一、第一台主机通过https密钥对认证 1、安装docker服务 &#xff08;1&#xff09;安装环境依赖包 yum -y install yum-utils device-mapper-persistent-data lvm2 &#xff08;2&#xff09;设置阿里云镜像源 yum-config-manager --add-repo http://mirrors.aliyun.com/do…

ElasticSearch 数据备份参考

ElasticSearch 数据备份参考 总结&#xff1a; 规模数据建议使用Snapshot and Restore功能&#xff0c;或者用LogStash&#xff0c;小规模数据可以用 elasticdump。 官方建议&#xff1a; 在灾难中&#xff0c;快照可以防止永久数据丢失。快照生命周期管理是对集群进行定期备份…

VLAN简介

在配置交换机或者传输设备时&#xff0c;经常会提到vlan&#xff0c;这个vlan具体是啥呢&#xff1f; VLAN&#xff08;Virtual Local Area Network&#xff09;中文名为“虚拟局域网”。它是一种在物理网络上划分出逻辑网络的方法&#xff0c;将物理上的局域网在逻辑上划分为多…

设计模式——适配器模式(Adapter Pattern)

概述 适配器模式可以将一个类的接口和另一个类的接口匹配起来&#xff0c;而无须修改原来的适配者接口和抽象目标类接口。适配器模式(Adapter Pattern)&#xff1a;将一个接口转换成客户希望的另一个接口&#xff0c;使接口不兼容的那些类可以一起工作&#xff0c;其别名为包装…

分布式下有哪些好用的监控组件?

在之前的内容中&#xff0c;分析了分布式系统下的线上服务监控的常用指标&#xff0c;那么在实际开发中&#xff0c;如何收集各个监控指标呢&#xff1f;线上出现告警之后&#xff0c;又如何快速处理呢&#xff1f;本文我们就来看下这两个问题。 常用监控组件 目前分布式系统…

机器学习之降维(维度灾难和维度爆炸)

在机器学习中,降维是指通过减少数据的特征维度来简化数据表示的过程。高维数据集可能包含冗余的信息,降维的目标是保留尽可能多的有用信息,同时减少数据的维度。降维的主要优势包括提高模型的计算效率、减轻维度灾难(curse of dimensionality)的影响以及更好地可视化数据。…

MongoDB创建和查询视图(一)

目录 限制和注意事项 应用两种方式创建视图 本文整理mongodb的官方文档&#xff0c;介绍mongodb的视图创建和查询。 Mongodb中&#xff0c;允许使用两种方式来创建视图。 //使用db.createCollection()来创建视图 db.createCollection("<viewName>",{"…

Node.js版本对比

目录 1. node版本与Npm版本对照表 2. node版本与node-sass版本对照表 3. node-sass与sass-loader版本对照表 1. node版本与Npm版本对照表 以往的版本 | Node.js 下面显示最新的对应内容&#xff0c;如果需要查找历史版本&#xff0c;可以进入上面的页面查询 VersionLTSDateV8np…

鸿蒙实战-库的调用(ArkTS)

整体框架搭建 主页面、本地库组件页面、社区库组件页面三个页面组成&#xff0c;主页面由Navigation作为根组件实现全局标题&#xff0c;由Tabs组件实现本地库和社区库页面的切换。 // MainPage.ets import { Outer } from ../view/OuterComponent; import { Inner } from ..…

【微服务核心】Spring Boot

Spring Boot 文章目录 Spring Boot1. 简介2. 开发步骤3. 配置文件4. 整合 Spring MVC 功能5. 整合 Druid 和 Mybatis6. 使用声明式事务7. AOP整合配置8. SpringBoot项目打包和运行 1. 简介 SpringBoot&#xff0c;开箱即用&#xff0c;设置合理的默认值&#xff0c;同时也可以…

Debian Linux完全卸载gitlab-ce

Debian Linux完全卸载gitlab-ce 在Debian上本地安装了gitlab-ce&#xff0c;维护起来比较麻烦&#xff0c;而且占用了80和443端口 后面想改用docker&#xff0c;就想完全卸载gitlab-ce 卸载服务 sudo gitlab-ctl uninstall清理所有产生的数据&#xff0c;会提示等待60秒&am…

如何让机器人具备实时、多模态的触觉感知能力?

人类能够直观地感知和理解复杂的触觉信息&#xff0c;是因为分布在指尖皮肤的皮肤感受器同时接收到不同的触觉刺激&#xff0c;并将触觉信号立即传输到大脑。尽管许多研究小组试图模仿人类皮肤的结构和功能&#xff0c;但在一个系统内实现类似人类的触觉感知过程仍然是一个挑战…

“巴渝工匠杯”2022年重庆市职业院校技能大赛“区块链技术应用创新”赛项竞赛样题

“巴渝工匠杯”2022年重庆市职业院校技能大赛“区块链技术应用创新”赛项【区块链技术应用创新赛项】竞赛样题2022 年 2月目录第一部分&#xff1a;区块链网络部署第二部分&#xff1a;智能合约开发第三部分&#xff1a;区块链应用开发第四部分&#xff1a;文档编写第五部分&am…

Lua的底层原理与C#交互原理浅析【更新中】

目录 lua底层原理浅析 table底层原理浅析 Lua表的C语言定义 原理和实现 userdata lua和C#的交互机制&#xff08;更新中&#xff09; 基本介绍 Lua 与 C/C 的数据交互 Lua 调用 C/C 函数 C/C 调用 Lua 函数 基元类型传递 对象类型传递 Lua 调用 C# 总结 网上有很…

【go语言】CSP并发机制与Actor模型

一、多线程共享内存 1. 概念 多线程共享内存模型是一种并发编程模型&#xff0c;其中多个线程在同一个进程的地址空间中共享相同的内存区域。这种模型允许多个线程并发地读取和写入相同的数据结构&#xff0c;但也引入了一些潜在的问题&#xff0c;其中最常见的问题之一就是…

【WordPress插件】热门关键词推荐v1.3.0 Pro开心版

介绍&#xff1a; WordPress插件-WBOLT热门关键词推荐插件&#xff08;Smart Keywords Tool&#xff09;是一款集即时关键词推荐、关键词选词工具及文章智能标签功能于一体的WordPress网站SEO优化插件。 智能推荐&#xff1a; 热门关键词推荐引擎-支持360搜索、Bing、谷歌&a…

【已解决】c++qt如何制作翻译供程序调用

本博文源于笔者正在编写的工具需要创建翻译文件&#xff0c;恰好将qt如何进行翻译&#xff0c;从零到结果进行读者查阅&#xff0c;并非常推荐读者进行收藏点赞&#xff0c;因为步步都很清晰&#xff0c;堪称胎教式c制作&#xff0c;而且内容还包括如何部署在windows下。堪称值…

百分点科技获国际顶会NeurIPS LLM效率挑战赛冠军

近日&#xff0c;国际人工智能顶会NeurIPS在美国新奥尔良市举办&#xff0c;在同期举行的NeurIPS 2023大语言模型效率挑战赛中&#xff0c;百分点科技以领先第二名8分的显著优势夺得NVIDIA A100赛道冠军。 NeurIPS与ICML、ICLR并称机器学习领域国际三大顶会&#xff0c;代表着人…