Asp-Net-Core学习笔记:身份认证入门

前言

过年前我又来更新了~

我就说了最近不是在偷懒吧,其实这段时间还是有积累一些东西的,不过还没去整理……

所以只能发以前没写完的一些笔记出来

就当做是温习一下啦

PS:之前说的红包封面我还没搞,得抓紧时间了

最近在准备搞一个我之前做的开源项目代码合集来做一期分享

两种常见的认证方式

先来看看两种常见的认证方式:基于token的认证和传统的session认证的区别。

session认证

我们知道,http协议本身是一种无状态的协议,而这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再一次进行用户认证才行,因为根据http协议,我们并不能知道是哪个用户发出的请求,所以为了让我们的应用能识别是哪个用户发出的请求,我们只能在服务器存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器,告诉其保存为cookie,以便下次请求时发送给我们的应用,这样我们的应用就能识别请求来自哪个用户了,这就是传统的基于session认证。

但是这种基于session的认证使应用本身很难得到扩展,随着不同客户端用户的增加,独立的服务器已无法承载更多的用户,而这时候基于session认证应用的问题就会暴露出来。

弊端

Session: 每个用户经过我们的应用认证之后,我们的应用都要在服务端做一次记录,以方便用户下次请求的鉴别,通常而言session都是保存在内存中,而随着认证用户的增多,服务端的开销会明显增大。

扩展性: 用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这意味着用户下次请求还必须要请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡器的能力。这也意味着限制了应用的扩展能力。

CSRF: 因为是基于cookie来进行用户识别的, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。

基于token的认证

基于token的鉴权机制类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。

流程上是这样的:

  • 用户使用用户名密码来请求服务器

  • 服务器进行验证用户的信息

  • 服务器通过验证发送给用户一个token

  • 客户端存储token,并在每次请求时附送上这个token值

  • 服务端验证token值,并返回数据

这个token必须要在每次请求时传递给服务端,它应该保存在请求头里, 另外,服务端要支持CORS(跨来源资源共享)策略,一般我们在服务端这么做就可以了Access-Control-Allow-Origin: *

OAuth2.0与OpenID

OAuth2.0OpenID Connect是标准验证框架

OAuth(Open Authorization,即开放授权)是一个用于代理授权的标准协议。它允许应用程序在不提供用户密码的情况下访问该用户的数据。

OpenID Connect 是在 OAuth2.0 协议之上的标识层。它拓展了 OAuth2.0,使得认证方式标准化。

OAuth 不会立即提供用户身份,而是会提供用于授权的访问令牌。OpenID Connect 使客户端能够通过认证来识别用户,其中,认证在授权服务端执行。它是这样实现的:在向授权服务端发起用户登录和授权告知的请求时,定义一个名叫openid的授权范围。在告知授权服务器需要使用 OpenID Connect 时,openid是必须存在的范围。

来看一看OpenID Connect的架构图,可以看到,JWT是作为它的底成实现支持。所以,对于了解JWT来说是必要的。

285c30a9a09a78bf7606eacf57044d41.png

那么我们继续了解接下来的JWT。

JWT

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519)。该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

对于我们常用的JWT,是采用了JWS的签名式加密方案。所以结构就是 "A.B.C"的样子,用Header来描述了签名加密所用的算法,该描述遵循了JWA,而使用Playload来包含咱们所需要的东西,在JWT里面,它们叫做JWT Claims Set,而JWT提出了很多内置的Claim规范,下面我们会看到。最后是Signature,这就是基于JWS所得到的内容。

JWT规范定义了七个可选的、已注册的声明(Claim),并允许将公共和私人声明包括在令牌中,这七个已登记的声明是:

Claim描述
iss (Issuer)确定了签发JWT的主体(发行者)。一般是STRING或者URI,比如"http://my.identityServer.com/5000"
sub (Subject)JWT所代表的主题。主题值必须限定为在发行者的上下文中是本地唯一的,或者是全局唯一的。所以你会在某些例子中看到它保存了用户的ID等。一般是STRING或者URI
aud (Audience)JWT的受众(该单词我也不知道该如何翻译比较合适)。一般是STRING或者URI,比如"http://my.clientiIp.com/5000"
exp (expire)JWT的过期时间
nbf (not-before)JWT的生效时间
iat ((issued-at)JWT的颁发时间
jti (expire)JWT的唯一标识符(JWT ID)

当然,仅仅靠这些值我们一般是无法处理完整业务逻辑的,比如我们往往需要将用户邮箱等信息放入Token中,所以我们可以在荷载中放入我们自定义的一些项,只要保证不要和内置的命名冲突就行啦。

具体要怎么写,下面有代码例子~

Bearer Token

BearerHTTP Authorization的类型规范,而JWT是一个数据结构的规范

在HTTP 1.0中提出了Authorization: <type> <credentials>这样的格式。如果Basic类型的验证是Authorization : Basic,那Bearer类型就是 Authorization : Bearer <token>

关于Bearer,它是伴随OAuth2.0所提出,该规范仅仅定义了Bearer Token的格式(也就是需要带上Bearer关键字在header中),并没有说过Token一定要使用JWT格式。

再捋一遍

前面介绍了这么多的概念之后,可能同学们已经有点晕晕的了,没事,接下来重新捋一遍

用户登录,首先要在客户端请求服务端的登录接口,把用户名和密码发给服务器;

然后服务器把用户名和密码拿去数据库里比对,如果正确的话,那就根据JWT标准生成一个JWT token返回给客户端;

客户端拿到了token,就能以Bearer token的形式将token放在HTTP请求头中,去请求那些需要登录才能访问的接口~

就是这么简单~

AspNetCore中的认证授权

在开始写代码之前,必须要了解一下AspNetCore中关于认证与授权的基础概念~

认证

身份认证处理程序是实现身份认证操作的核心类,身份认证处理程序派生自接口IAuthenticationHandler。该接口定义了以下三种操作:身份认证(AuthenticateAsync)、挑战(ChallengeAsync)和禁止(ForbidAsync)。其中,身份认证是主要的操作。

身份认证返回AuthenticateResult来表明该请求的身份认证是否成功,AuthenticateResult可以返回三种类型的结果:失败(Fail)、无结果(NoResult)和成功(Success)。如果验证成功,将会通过AuthenticateResult返回AuthenticationTicketAuthenticationTicket将会封装用户信息,以便于在后续的授权中使用。

挑战是指当前请求访问的资源要求身份认证,但是当前请求未通过身份认证,那么后续的授权阶段就需要通过指定的身份认证方案中的身份认证处理程序来提供挑战方法,以便发起挑战。如果没有指定身份认证方案,就会使用默认身份认证方案。举个例子来说,如果我们因为长时间没有操作而导致系统登录会话超时失效,那么再次对系统进行操作时,系统一般会将页面重定向到登录页面,这个重定向的操作就是一种挑战。

禁止是指已经通过身份认证的用户尝试访问其无权访问的资源时而进入授权阶段所要执行的操作。比如某站点的普通用户想要使用VIP用户的功能,如果该用户没有登录,那么本次请求就是匿名访问,这时授权阶段需要发起挑战操作;如果该用户已经登录,但是授权阶段发现该用户没有权限访问该资源,那么系统可能会返回HTTP 403状态码,这种返回HTTP 403状态码的操作就是一种禁止。

用户信息模型

身份认证通过后,身份认证处理程序会返回身份认证票根,即AuthenticationTicket

AuthenticationTicket是ASP.NET Core封装认证信息的类。

AuthenticationTicket又包含了ClaimsPrincipalClaimsPrincipal可以理解为用户主体,由一组ClaimIdentity组成。

ClaimsIdentity可以理解为身份证明,一个用户主体可以有多个身份证明,就好比身份证、驾驶证都可以代表唯一具体的人一样。

ClaimsIdentity包含了一组ClaimClaim就是好比身份证上的姓名、性别、籍贯等信息。一个用户通过身份认证后,就会用以上类来组织用户信息。后续的授权等其他中间件就可以使用这些信息来进行功能设计。

结构示例如下:

  • AuthenticationTicket (身份认证票根,其中封装了认证信息)

    • ClaimIdentity (身份证明)

    • ClaimIdentity

    • ClaimIdentity

    • Claim

    • Claim

    • Claim

    • ClaimsPrincipal (用户主体)

授权

授权(Authorization)决定了一个用户在系统里能干什么。对于ASP.NET Core应用来说,授权决定了一个用户能够访问哪些资源路径。授权与7.1节讲的身份认证是依赖和被依赖的关系,ASP.NETCore将身份认证与授权设计成了相对独立的两个功能模块,两个模块的职责分工非常明确,前者解决用户是谁的问题,后者解决用户能干什么的问题。从功能上来看,授权是基于身份认证的结果而做出的,从逻辑上来说,只有知道用户是谁才能确定用户能干什么。

ASP.NET Core提供了简单授权、基于角色的授权、基于策略的授权,多样的授权方式在通过简单的Attribute修饰就能满足大部分应用场景。授权中重要的两个Attribute就是AuthorizeAttributeAllowAnonymousAttribute,所有的授权配置都离不开这两个Attribute。同时,ASP.NET Core对授权方案的扩展也非常方便,在本节的最后会介绍如何自定义授权处理程序来实现自定义授权逻辑。

授权有这三种类型

  • 简单授权:只要登录就能访问,在Controller或者Action上加个[Authorize]就行

  • 基于角色的授权:特定角色能访问

  • 基于策略的授权:顾名思义

基于角色的授权

基于角色的授权简单来说就是一个资源必须要指定角色的用户才能够访问。基于角色的授权必须在Controller或Action上指定哪些角色可以访问该资源。

AuthorizeAttribute有一个公开的string类型的属性Roles。通过这个属性可以指定哪些角色可以访问特定资源。认证用户是否属于某个角色可以通过ClaimsPrincipal类的IsInRole方法进行验证,ASP.NET Core基于角色的授权就是通过这个方法来确定当前用户是否属于某个角色用户的。当前用户属于角色属性如何设置呢?很简单,ClaimsIdentity的属性RoleClaimType会告诉ASP.NET Core哪个Claim存储了用户的角色信息。

比如某个Controller需要管理员角色才能访问:

[Authorize(Roles="管理员")]

可以指定多个角色都可以访问,多个角色间用逗号分隔:

[Authorize(Roles="人力经理,财务")]

如果用多个[Authorize(Roles='SomeRole')]修饰ControllerAction,那么访问的用户必须是所有指定角色的成员,下面的例子必须同时是“销售”和“经理”才能访问

[Authorize(Roles="销售")]
[Authorize(Roles="经理")]

基于策略的授权

基于策略的授权是更灵活的授权方式,我们先来了解ASP.NET Core的授权模型。与身份认证相似,ASP.NET Core由授权处理程序、授权需求、授权方案、授权服务构成。其中,授权服务同身份认证服务一样,作为授权服务接口对外提供授权能力。授权方案是组织授权机制的概念,一个授权方案可以包含多个授权需求,只有满足了所有授权需求才算通过了授权方案,而授权需求可以关联多个授权处理程序,任意一个授权处理程序返回授权成功,则表示该授权方案下的授权需求被满足了。

ASP.NET Core提供了一个授权策略,实现了建造者模式,通过AuthorizationPolicyBuilder可以方便地构建AuthorizationPolicy。基于AuthorizationPolicyBuilder,可以方便地设置授权策略的授权需求。

services.AddAuthorization(config => {config.AddPolicy("RequireAdmin", builder => builder.RequireRole("管理员"));
});

除了AuthorizeAttribute上可以设置的角色外,还可以设置Claim需求。

该授权策略需要当前认证用户姓"赵":

services.AddAuthorization(config => {config.AddPolicy("RequireZhao", builder => builder.RequireClaim("姓", "赵"));
});

如果被授权的姓氏规则比较复杂,不利于枚举出来,那么推荐使用RequireAssertion来实现。比如上面的功能还可以用如下方式来实现:

services.AddAuthorization(config => {config.AddPolicy("RequireZhao", builder => builder.RequireAssertion(context => context.User.FindFirst("姓").Value=="赵"));
});

除此之外,还可以通过实现了IAuthorizationRequirement的授权需求来关联自定义的授权处理程序来实现更灵活的授权规则设计。

IdentityServer4

IdentityServer4是ASP.NET Core平台下的一个OAuth 2.0以及OpenID Connect的实现。它非常方便地提供了身份认证、授权以及第三方认证服务对接,并且支持自定义方式来满足开发者不同场景下各式各样的需求。IdentityServer4作为一个成熟的认证授权框架,是受到OpenID Connect官方认证的服务端实现。IdentityServer开源且免费,在重视知识产权的今天,我们可以放心地基于IdentityServer4搭建认证平台开发商业应用。

IdentityServer通过IdentityResource、ApiScope、ApiResource、Client这些概念来实现身份的认证和资源的权限控制。

IdentityResource是指用户ID、姓名、手机号等用户信息,比如OpenID Connect规范就定义了一组标准的IdentityResource。除此之外,我们也可以自定义IdentityResource,这些概念很像ASP.NETCore中身份认证的Claim,定义了程序能访问到的用户信息。

ApiScope可以认为是API的一种标签,而ApiResource就是对API在授权场景下的抽象。如果需要对客户端能否访问某个API进行控制,就要定义ApiScope和ApiResource。

Client通过Request Token限制了哪些应用可以访问对应的API资源。每个Client都会有一个唯一的Client ID,通过设置一个秘钥可以加强用户信息安全性,关键的是通过设置AllowedApiScopes,框架就可以控制这个Client可以访问哪些ApiResource(Resource是和Scope相关联的)。

开始编码!

OK,终于到了激动人心的写代码环节,书读百遍不如实践一次,开始吧!

首先根据JWT标准,我们需要先定义这几个信息:

  • Issuer:签发JWT的主体

  • Audience:JWT的受众

  • Key:用来加密的秘钥

本例子中我们写一个最简单的单站点登录认证,所以Audience可以写死在配置文件里。

定义配置类

为了方便的映射appsettings.json配置文件,我们定义一个类~~(误,是两个)~~

public class SecuritySettings {public Token Token { get; set; }
}
public class Token {public string Issuer { get; set; }public string Audience { get; set; }public string Key { get; set; }
}

然后注册服务

services.Configure<SecuritySettings>(configuration.GetSection(nameof(SecuritySettings)));

添加认证服务和中间件

添加认证服务

services.AddAuthentication(options => {options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options => {// 这里用到我们之前定义好的配置类var secSettings = configuration.GetSection(nameof(SecuritySettings)).Get<SecuritySettings>();// 设置jwt token的各种信息用于验证options.TokenValidationParameters = new TokenValidationParameters {ValidateAudience = true,ValidateLifetime = true,ValidateIssuer = true,ValidateIssuerSigningKey = true,ValidIssuer = secSettings.Token.Issuer,ValidAudience = secSettings.Token.Audience,IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secSettings.Token.Key)),ClockSkew = TimeSpan.Zero};});

添加中间件

app.UseEndpoints前面添加这三行代码

app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();

用户实体类

很简单,不多说了

public class LoginUser {public string Username { get; set; }public string Password { get; set; }
}

登录接口

在Controller里写一个用户登录接口

[HttpPost]
public ActionResult<LoginToken> Login(LoginUser loginUser) {var user = _authService.GetUser(loginUser.Username);if (user == null) return NotFound();var md5Pwd = loginUser.Password.MDString();if (md5Pwd != user.Password) return Unauthorized();return _authService.GenerateLoginToken(user);
}

这里面我封装了一个AuthService服务,专门用于处理跟用户认证有关的操作

其中的GetUser方法不用多介绍了,就是数据库读取操作而已。

我们主要看GenerateLoginToken这个方法。

生成token的关键代码

GenerateLoginToken方法的代码如下

public LoginToken GenerateLoginToken(User user) {// 构造JWT中的claims信息var claims = new List<Claim> {new("username", user.Name),new(JwtRegisteredClaimNames.Name, user.Id), // User.Identity.Namenew(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), // JWT ID};// 从配置文件里读取信息var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_secSettings.Token.Key));var signCredential = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);var jwtToken = new JwtSecurityToken(issuer: _secSettings.Token.Issuer,  // 颁发者信息audience: _secSettings.Token.Audience, // 接受者信息claims: claims,       // 要放进JWT中的claims信息expires: DateTime.Now.AddDays(7),  // 过期时间signingCredentials: signCredential); // 签名// 最后返回一个 LoginToken 对象,其中包含JWT token和过期时间两个字段return new LoginToken {Token = new JwtSecurityTokenHandler().WriteToken(jwtToken),Expiration = TimeZoneInfo.ConvertTimeFromUtc(jwtToken.ValidTo, TimeZoneInfo.Local)};
}

这个代码的意义我都写在注释里面了,最后的LoginToken是我定义的一个类,代码很简单:

public class LoginToken {public string? Token { get; set; }public DateTime Expiration { get; set; }
}

效果

完成之后,访问登录接口,提交正确的用户名密码,就可以得到客户端要的JWT token,大概是下面这样的形式

{"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ5ZXpzIiwibmFtZSI6InllenMiLCJwaG9uZV9udW1iZXIiOiIxNTYwMjc3NzMwMCIsImV4cCI6MTY0MzMxMzc3OSwiaXNzIjoiZGVtb19pc3N1ZXIiLCJhdWQiOiJkZW1vX2F1ZGllbmNlIn0.7x8zfpcWWbCH6SwXOUnQKCfXRWsyUiWoB5jSxYSIq-Q","expiration": "2022-01-28T04:02:59+08:00"
}

在需要登录的接口方法或者Controller类上加一个[Authorize]特性,就OK了

访问的时候如果不带上HTTP头Authorization : Bearer <token>,就会报401 Unauthorized错误。

大功告成!

SignalR中如何使用JWT Token?

接下来是一点扩展的东西

AspNetCore除了可以做WebApi这种基于HTTP的接口,还可以实现像websocket这样的实时通信,比如SignalR技术

那通过SignalR的请求能不能也加上身份验证呢?答案是肯定的

和controller一样,只需要在Hub类或者Hub类里面的方法加上[Authorize]特性,即可实现身份验证。

但是客户端访问的时候要怎么提交token呢?这可不是HTTP,没有header的

别急,来看看以下两种方法,都是要在前面添加服务那里配置。

首先确定要添加配置的地方:

services.AddAuthentication(...).AddJwtBearer(options => {options.TokenValidationParameters = new TokenValidationParameters {...};options.Events = new JwtBearerEvents {// 等会要添加的配置代码放在这里...};});

官方文档的方法

OnMessageReceived = context => {var accessToken = context.Request.Query["access_token"];var path = context.HttpContext.Request.Path;// If the request is for our hubif (!string.IsNullOrEmpty(accessToken) && path.StartsWithSegments("/hub")) {// Read the token out of the query stringcontext.Token = accessToken;}return Task.CompletedTask;
}

简书网友的方法

OnMessageReceived = context => {var accessToken = context.Request.Query["access_token"];if (!string.IsNullOrEmpty(accessToken) &&(context.HttpContext.WebSockets.IsWebSocketRequest || context.Request.Headers["Accept"] == "text/event-stream")){context.Token = context.Request.Query["access_token"];}return Task.CompletedTask;
}

点评一下,官方文档的方法有点硬编码,是根据请求的路径判断的,但如果我们的项目里不止一个hub,那就麻烦了,要多写点代码;

简书网友的方法是根据请求的方式来判断,我们知道SignalR和普通的HTTP请求是不一样的,所以感觉简书网友的这个方法更优雅一点~

客户端使用

差点把这个忘了

放上JavaScript代码~

let loginToken = "xxx"
let connection = new signalR.HubConnectionBuilder().withUrl("/hub/hub_name", {accessTokenFactory: () => loginToken}).build()

在建立连接的时候,带上accessTokenFactory参数即可~

后记

呼~

终于搞定了

没想到这篇博客写了这么长这么久

授权与认证包括好多要学的东西,我目前也只是做了最基础的登录验证,还没有搞身份那些

所以这篇作为基础入门,接下来的博客会继续深入这方面,冲!

参考资料

  • (推荐)客官,来看看AspNetCore的身份验证吧:https://www.cnblogs.com/uoyo/p/13209685.html

  • OAuth 2.0 与 OpenID Connect 协议的完整指南:https://www.infoq.cn/article/euvhttyf3jmfakmm8cmn

  • 身份验证和授权 ASP.NET CoreSignalR:https://docs.microsoft.com/zh-cn/aspnet/core/signalr/authn-and-authz?view=aspnetcore-6.0

  • NET CORE SignalR JWT授权认证:https://www.jianshu.com/p/19a0efdc01d1

  • 什么是 JWT -- JSON WEB TOKEN:https://www.jianshu.com/p/576dbf44b2ae

  • JSON Web Token 入门教程:https://www.ruanyifeng.com/blog/2018/07/json_web_token-tutorial.html

  • 如何在 ASP.NET Core 3 使用 Token-based 身分驗證與授權 (JWT):https://blog.miniasp.com/post/2019/12/16/How-to-use-JWT-token-based-auth-in-aspnet-core-31

往期推荐

记一次CTF比赛过程与解题思路-MISC部分

2021-11-05

bf635480d88600d96667e5250a9a8aa5.png

使用Flutter设计一个好看的"我"页面

2021-06-18

a0fe94fefa4bc1b2c01982a18dcf0ae5.png

PyQt5开发实践(一、准备篇)

2021-05-05

51e632b88d8b312aadc552d2ef4dc8ff.png

比Django官方实现更好的分页组件+Bootstrap整合

2021-03-29

ab8774a0d7ca9a704739084d16f032c3.png


(准备要新年快乐啦!)

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

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

相关文章

第1章 大数据挖掘及应用概论

《大数据挖掘及应用》学习笔记。 第1章 大数据挖掘及应用概论 数据挖掘是数据分析的提升。 1.1 大数据智能分析处理的普及和应用 1.1.1 云计算(cloud computing) 云计算是一种按使用量付费的模式&#xff0c;这种模式提供可用的、便捷的、按需的网络访问&#xff0c;进入可配…

浮点型数据的输出格式

2019独角兽企业重金招聘Python工程师标准>>> float的占位符为f%,默认输出六位小数&#xff0c;如果要限制位数的输出&#xff0c;可以用%.2f这样的格式&#xff0c;double同上。 如果是浮点型转换成整型不会进行四舍五入&#xff0c;浮点型的输出如果截取了位数进行…

linux网络编程之用socket实现简单客户端和服务端的通信(基于TCP)

一、介绍基于TCP协议通过socket实现网络编程常用API 1、读者如果不是很熟悉,可以先看我之前写的几篇博客,有socket,地址结构的理解,更加方便读者理解 地址分别是: 1)、http://blog.csdn.net/u011068702/article/details/56479927 2)、http://blog.csdn.net/u01106870…

VS2010下Boost1.55.0配置

为什么80%的码农都做不了架构师&#xff1f;>>> 打开程序菜单&#xff0c;选择Visual Studio Tools里面的 Visual Studio 命令提示。转到解压后的Boost所在目录&#xff0c;输入Bootstrap&#xff0c;执行完毕会生成b2.exe。输入&#xff08;目录下的bjam.exe和b2.…

Linux信号实践(3) --信号内核表示

信号在内核中的表示执行信号的处理动作称为信号递达&#xff08;Delivery&#xff09;&#xff0c;信号从产生到递达之间的状态&#xff0c;称为信号未决&#xff08;Pending&#xff09;。进程可以选择阻塞&#xff08;Block&#xff09;某个信号。被阻塞的信号产生时将保持在…

第2章 数据认知与预处理

《大数据挖掘及应用》学习笔记。 第2章 数据认知与预处理 2.1 数据分析的定义和流程 数据分析(data analysis)是指用适当的统计分析方法对收集来的大量数据进行分析和解释&#xff0c;提取出有用的信息形成结论&#xff0c;从而对数据加以详细研究和概括总结的过程。 2.1.1 如…

9 C++ Boost 多线程,线程同步

线程的创建 boost_thread,boost_system 多线程的创建 线程的参数传递 线程的创建方式 线程的join 加入join,回收线程线程中断 线程中断2, 线程组 boost 线程的死锁 boost 线程递归锁 线程互斥锁,线程同步 unique_lock 锁,离开作用域自动释放 unique_lock 锁 示例 2,可以显式的释…

命令注入_命令注入绕过方式总结

前言命令注入是web中常见的漏洞之一&#xff0c;由于web应用程序未对用户提交的数据做严格的过滤&#xff0c;导致用户输入可以直接被linux或windows系统当成命令执行&#xff0c;一般都会造成严重的危害。常用符号分号(;)多条语句顺序执行时的分割符号。1cmd1;cmd2管道符(|)cm…

集合的结构示意图

转载于:https://blog.51cto.com/8467007/1364724

第1章 数据分析概述

《Python数据分析基础教程》学习笔记。 第1章 数据分析概述 1.1 数据的性质 1.1.1 数据的概念 所谓数据就是描述事物的符号&#xff0c;是对客观事物的性质、状态和相互关系等进行记载的物理符号或者是这些物理符号的组合。 在计算机系统中&#xff0c;各种文字、字母、数字符…

Android之通过adb shell getprop、netstat命令看dns、ip

1、查看dns 1)、输入adb shell 2 )、输入getprop ,查看配置 3)、getprop | grep dns 过滤dns 4) 、getprop | grep dns 输出dns 5) 、修改dns 需要root ,然后输入 adb shell 然后输

Cache占用过多内存导致Linux系统内存不足问题排查

问题描述Linux服务器内存使用量超过阈值&#xff0c;触发报警。问题排查首先&#xff0c;通过free命令观察系统的内存使用情况&#xff0c;显示如下&#xff1a;total used free shared buffers cached Mem: 24675796 24587144 88652 …

linux之ip route命令

1.基础知识 1.1 路由 &#xff08;Routing&#xff09; 1.1.1 路由策略 &#xff08;使用 ip rule 命令操作路由策略数据库&#xff09; 基于策略的路由比传统路由在功能上更强大&#xff0c;使用更灵活&#xff0c;它使网络管理员不仅能够根据目的地址而且能够根据报文大小、应…

违反Apache 2.0许可证再分发被指控,火山引擎回应

文 | 白开水不加糖出品 | OSC开源社区&#xff08;ID&#xff1a;oschina2013&#xff09;针对有关违反 Apache 2.0 许可证&#xff0c;重新发行 SkyWalking 的指控&#xff0c;火山引擎方面作出回应称&#xff1a;火山引擎相关负责人表示&#xff0c;火山引擎接到社区反馈后&a…

linux网络编程之IP协议首部格式与其配套使用的四个协议(ARP,RARP,ICMP,IGMP)和TCP、UDP协议头结构总结

首先声明,这篇博客是几篇博客转载然后总结在一起的,只当是学习笔记,不在意是什么原创和转载了,学到东西就好。 1、IP协议首部格式(IP协议处余网络层) IP数据报首部图片格式: 最高位在左边,记为0 bit;最低位在右边,记为31 bit 头部代码结构如下 //定义IP首部typede…

无线安全***--启程

无线安全将来会成为一个值得重视的领域&#xff0c;现在无线的普及大大的方便我们的生活&#xff0c;同时在带来的便利的同时也会给我带来新的威胁&#xff01;下面我来通过cdlinux以及BT5来演示现在比较常见的无线***之战。攻破解我们都知道现在的个人无线局域网基本都会使用w…

Java读取word文件,字体,颜色

在Android读取Word文件时&#xff0c;在网上查看时可以用tm-extractors&#xff0c;但好像没有提到怎么读取Word文档中字体的颜色&#xff0c;字体&#xff0c;上下标等相关的属性。但由于需要&#xff0c;要把doc文档中的内容&#xff08;字体&#xff0c;下划线&#xff0c;颜…

.NET 20周年软件趋势随想

从2000年微软启动.NET战略时&#xff0c;我还是一位大学生&#xff0c;当年著名的黑客Miguel de Icaza , Miguel 为了寻找GNOME项目开发框架经过充分的调研启动了一个志存高远的项目&#xff1a;Mono&#xff0c;一个Microsoft .NET Framework的自由GNU/Linux实现&#xff0c;我…

c++ console 取实时输入_灵活使用 console 让 js 调试更简单

译者&#xff1a;前端小智原文&#xff1a; https://medium.com/mattburgess/beyond-console-log-2400fdf4a9d8https://medium.freecodecamp.org/10-tips-to-maximize-your-javascript-debugging-experience-b69a75859329Web开发最常用的高度就是 console.log &#xff0c;虽然…

windows之DNS7种资源记录和flushdns命令清除DNS缓存以及nslookup解析域名和ipconfig/all命令查看网络配置使用总结

1、DNS7种资源记录 DNS分为正向查找区域和反向查找区域&#xff0c;然后在分为&#xff0c;主要&#xff0c;辅助&#xff0c;存根区域&#xff0c;在这些区域里&#xff0c;又存在着很多的记录&#xff0c;今天&#xff0c;就让我们来看看这些记录&#xff1a;1&#xff0c;A记…