Java应用程序的简单令牌认证

“我喜欢编写身份验证和授权代码。” 〜从来没有Web开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。

JSON Web令牌已Swift成为保护Web应用程序安全的标准,并取代了Cookie和会话等旧技术。 正确使用它们可以解决一系列安全问题,包括跨站点脚本攻击(XSS),中间人攻击(MITM)和跨站点请求伪造(CSRF)。 它们还为我们提供了可检查的元数据和强大的密码签名的好处。 在本文中,我将深入探讨JWT。 首先,我将介绍一些理论基础,解释它们如何工作。 之后,我将向您展示如何使用Okta配置Spring Boot应用程序以使用JWT身份验证。

JSON Web令牌是一个开放标准,并且有许多可用的库允许创建,验证和检查JWT。 您将使用Java JWT (又名JJWT),这是一个Java库,提供端到端JWT的创建和验证。 JJWT由Les Hazlewood创建, Les Hazlewood是Stormpath的前联合创始人兼CTO Apache Shiro的主要撰稿人,目前是Okta自己的高级架构师。 根据Apache 2.0许可,它是开源的。

了解JWT及其在身份验证中的作用

首先让我们研究一下authenticationtoken在这种情况下的含义。

身份验证证明用户就是他们所说的真实身份

令牌是一个独立的信息块。 它可能具有内在价值,也可能没有。 我将向您展示一种特定类型的令牌, 它确实具有内在价值,并通过会话ID解决了许多问题。

什么是JSON Web令牌? JWT是一种开放标准( RFC 7519 ),用于使用JSON在各方之间作为数字签名的字符串令牌传输信息。 可以使用HMAC算法或使用RSAECDSA的公用/专用密钥对对它们进行签名

换句话说:JWT是JSON令牌,是URL安全,紧凑且自包含的字符串。 通常,它们携带有关用户的已验证身份的信息。 它们通常经过编码和加密。 它们Swift成为网络上令牌实现的事实上的标准。 URL安全意味着令牌字符串可以在URL中使用,因为所有特殊字符都已被编码为简单的字母数字字符。 JWT也被认为是不透明的,因为字符串本身没有解码或解密就不会提供任何信息。

令牌通常被认为是一种授权机制,但是它们也可以用作在Web应用程序和服务器之间安全存储和传输信息的一种方式,与使用会话ID的方式非常相似。

将JWT与OAuth 2.0结合使用

许多OAuth 2.0实现都将JWT用于其访问令牌。 应该指出,OAuth 2.0和JWT规范是彼此完全独立的,彼此之间没有任何依赖关系。 将JWT用作OAuth 2.0的令牌机制会带来很多好处,如下所示。

无论使用哪种JWT实施,都必须将漂亮的Web令牌存储在某个地方。 Cookie和HTML5 Web存储是两个流行的选项。 两种选择都有好处和潜在的风险。 对此的讨论不在本文讨论范围之内,但是值得阅读上面提到的典型攻击:跨站点脚本攻击(XSS),中间人攻击(MITM)和跨站点请求伪造(CSRF)。 Okta使用HTML5网络存储。

无论将JWT存储在何处,都可以用JWT完全替换会话ID,并获得直接从会话ID / JWT访问元信息的额外好处。

看一下JWT的结构

那是很多首字母缩写词。 让我们看一下JWT。 在野外,JWT很害羞。 有些人甚至可能说他们太丑陋或无聊了(取决于您对206个字符串的感觉)。

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwOi8vdHJ1c3R5YXBwLmNvbS8iLCJleHAiOjEzMDA4MTkzODAsInN1YiI6InVzZXJzLzg5ODM0NjIiLCJzY29wZSI6InNlbGYgYXBpL2J1eSJ9.43DXvhrwMGeLLlP4P4izjgsBB2yrpo82oiUPhADakLs

就像生活中的大多数事情一样,请不要凭空判断JWT(请记住,它们是不透明的)。 如果仔细看,您会发现字符串中有两个句点。 这些界定了JWT的不同部分:

  1. 标头
  2. 有效载荷/主体(或要求)
  3. 密码签名。
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9
.
eyJpc3MiOiJodHRwOi8vdHJ1c3R5YXBwLmNvbS8iLCJleHAiOjEzMDA4MTkzODAsInN1YiI6InVzZXJzLzg5ODM0NjIiLCJzY29wZSI6InNlbGYgYXBpL2J1eSJ9
.
43DXvhrwMGeLLlP4P4izjgsBB2yrpo82oiUPhADakLs

窥视令牌头

我知道我说过有些人认为JWT很无聊。 甚至不透明。 但是,如果您知道如何与他们交谈,JWT非常有趣。 让我们解码示例​​JWT并查看其中的内容。

标头只是通过Base64Url编码的。 它告诉我们令牌的类型和使用的哈希算法,通常是HMAC SHA256或RSA。

{"typ": "JWT","alg": "HS256"
}

顺便说一下, jsonwebtoken.io是用于编码和解码JWT的出色在线工具。

查看有效载荷

令牌的第二部分是有效负载声明

{"iss": "http://trustyapp.com/","exp": 1300819380,"sub": "users/8983462","scope": "self api/buy"
}

有效负载包含声明 。 声明是有关实体(通常是用户)和任何其他数据的声明。 索赔有以下三种:

  1. 已注册的声明: RFC 7519规范中定义的一组建议的声明。 一些示例是issexpaud
  2. 公共声明:可由令牌用户定义但应遵循命名约定以避免冲突的用户定义声明(应在IANA JSON Web令牌注册表中定义,或定义为包含抗冲突名称空间的URI),因为它们在公共命名空间中。
  3. 私人声明:用于在达成协议的各方之间共享信息的任意自定义声明(不必担心名称冲突,因为它们是私有的)。

在上面的示例中:

  • iss是发行令牌的人。 这是已注册的索赔。
  • exp是令牌过期的时间。 也是已注册的索赔。
  • 是主题。 通常是一个用户标识符。 也是已注册的索赔。
  • scope是OAuth 2.0常用的自定义私人声明。

范围声明通常用于提供授权信息。 例如,让应用程序知道用户有权访问应用程序的哪一部分。 当然,这并不能免除服务器执行自己的授权检查的责任。 Web应用程序安全性的一般原则是冗余。 客户端应用程序提供一个检查点,服务器提供另一个检查点。

JSON数据经过Base64URL编码以创建编码的有效负载。 编码的标头和有效负载用于创建签名。

检查令牌签名

签名是JWT结构的最后一部分。 它获取标头,然后有效负载向哈希算法添加一个秘密,并吐出与JWT其余部分中未更改的数据相对应的哈希。 使用签名,客户端应用程序和服务器可以验证它们接收的令牌是原始的,未更改的令牌。

HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret
)

了解此签名不提供机密性是非常重要的。 此信息是公开可见的。 签名保证令牌未被篡改,但不会隐藏数据(小孩可以在叔叔的iPhone 4上解码Base64)。 如果要发送敏感信息,必须对JWT进行加密。

通常以从属权利要求的形式存储用户标识符的做法。 当JWT签名时,它称为JWS。 加密后,称为JWE。

无国籍是JWT的一大好处。 服务器不需要存储任何会话数据。 它可以全部存储在令牌中,并在应用程序和服务器之间来回传递。 这看似是一个奇怪的电子飞盘游戏,但此模型的伸缩性很好(只要会话状态相对较小,它应该确实如此)。 从JWT解码会话状态要比在每个请求上访问数据库仅从会话存储中检索一些基本用户状态信息快得多,并且性能更高。

使用Java创建和验证JWT

我已经提到过我们的JJWT项目吗? 查看其GitHub页面 。 这是针对Java的完全开源的JWT解决方案。

让我们看一个使用JJWT创建JWT的示例。

import io.jsonwebtoken.Jwts;  
import io.jsonwebtoken.SignatureAlgorithm;  byte[] key = getSignatureKey();  String jwt = Jwts.builder().setIssuer("http://trustyapp.com/")  .setSubject("users/1300819380")  .setExpiration(expirationDate)  .put("scope", "self api/buy")  .signWith(SignatureAlgorithm.HS256,key)  .compact();

该库使用了流畅的Builder API。 请注意用于设置声明的设置器。 标准声明具有预定义的设置器,例如setSubject("users/1300819380") ,而自定义声明使用键值put()方法。 例如范围声明, put("scope", "self api/buy")

验证JWT一样容易。

String subject = "HACKER";  try {  Jws jwtClaims = Jwts.parser().setSigningKey(key).parseClaimsJws(jwt);  subject = claims.getBody().getSubject();  // OK, you can trust this JWT  
} 
catch (SignatureException e) {  // don't trust this JWT!  
}

如果对JWT进行了任何篡改,则解析声明将引发SignatureException并且subject变量的值将保持HACKER 。 如果它是有效的JWT,则将从中提取subjectclaims.getBody().getSubject()

了解OAuth 2.0以Java进行令牌身份验证

稍后,您将使用Okta的OAuth 2.0实现来创建Spring Boot应用程序。 但是首先,您应确保了解什么是OAuth,什么不是OAuth。

简而言之,OAuth 2.0是“授权的行业标准协议”(来自OAuth.net网站 )。 授权意味着它为应用程序提供了一种方法,以确保用户有权执行操作或访问资源。 OAuth 2.0 不提供用于验证用户身份的工具。

那是身份验证。

还有另一个称为OpenID Connect或OIDC的协议层,通常与提供身份验证的OAuth 2.0配对。 OIDC建立在OAuth 2.0的基础上,并提供一种验证用户身份的方法,通常是让用户使用用户名和密码登录,或者使用许多社交登录选项之一。 因为OIDC 确实与OAuth 2.0一起验证用户的身份,所以它们一起为Web应用程序和服务器提供了完整的身份验证和授权协议。

记得:

  • OIDC是身份验证,还是我是谁?
  • OAuth是授权,还是该怎么办?

在Java中配置Okta OIDC应用程序以进行令牌认证

很快,您将像专家一样生成和验证JWT。 但是首先,您需要转到developer.okta.com并创建一个OpenID Connect(OIDC)应用程序。 如果尚未注册免费的开​​发者帐户。 我是否提到过它完全免费?

登录到Okta开发人员仪表板。 转到应用程序 ,然后单击添加应用程序按钮。

选择Web应用程序类型,然后单击“ 下一步”

令牌认证

在下一页上,您需要给新应用程序起一个易记的名称。 您可以随意命名。 您还需要选中“ 客户端凭据”复选框。 这将激活您将要使用的client_credentials授予类型。

令牌认证

单击完成

请注意下一页底部的客户端ID客户端密钥 。 稍后您将需要这些。

令牌认证

安装HTTPie

我们将使用一个很棒的命令行实用工具来运行一些示例:HTTPie。 如果尚未安装,请访问其网站并安装。

申请JWT

时机已到。 我知道你很兴奋 您终于要见识JWT。

我知道您很想离开,但是您还需要执行一个初步的步骤。 您需要对上述Okta OIDC应用程序中的客户端ID和客户端密钥进行编码,以便在HTTP基本授权标头中使用。

通用格式为:

Authorization: Basic Base64Encode(< your client id >:< your client secret >)

注意中间的: 。 获取您的客户ID,并使用冒号将其加入到您的客户秘密中。 Base64对结果字符串进行编码(提示:使用base64encode.org )。 然后将其包含在您的请求中。 它看起来像这样:

Authorization: Basic ABChZzU4NDg5YW1aTDCBCB4waDc6TUp3YWN4RU5WNzQ1bEdQNWJPdlFETV9iaDE5NGp1eHQ3SXJfdWEzQQ==

互联网上有各种实用程序可以为您完成此任务。 尽管这些对于教程和从头开始开发可能会有所帮助,但出于显而易见的原因,但使用它们来编码生产凭证并不是一个好主意。

接下来,您需要的是Okta OIDC应用程序的令牌请求URL。 这将是您的Okta授权服务器基本URL加/v1/token 。 从顶部菜单转到API ,然后选择“ 授权服务器” 。 查看默认服务器的Issuer URI 。 添加/v1/token

例如,类似于: https://{yourOktaDomain}/oauth2/default/v1/token

使用HTTPie,您的终端命令将如下所示:

http -f POST https://{yourOktaDomain}/oauth2/default/v1/token \
'Authorization: Basic MG9hZzU4NDg5YW1aTDBNRU4wa...' \
grant_type=client_credentials

这里发生了什么?

-f是表单标志。 Content-Type设置为application/x-www-form-urlencoded; charset=utf-8 application/x-www-form-urlencoded; charset=utf-8并使用key=value表示法分析命令行以获取表单数据。

POST是HTTP请求类型。

https://{yourOktaDomain}/oauth2/default/v1/token是令牌请求URL。

'Authorization: Basic ...'设置基本auth标头。

grant_type=client_credentials是一个表单值,它告诉Okta我们正在请求的授予类型。 一秒钟内将对此进行更多介绍。

如果运行此命令,请继续! –您将收到invalid scope错误。

HTTP/1.1 400 Bad Request
Cache-Control: no-cache, no-store
Connection: close
Content-Type: application/json;charset=UTF-8
...{"error": "invalid_scope","error_description": "The authorization server resource does not have any configured default scopes, 'scope' must be provided."
}

使用client_credentials授予类型实际上只是一种方便。 这是一种授予类型,它使我们无需遵循浏览器重定向即可请求JWT。 client_credentials通常用于API交互。

根据OAuth规范 ,“客户端使用客户端凭据授予类型来获取用户上下文之外的访问令牌。 客户端通常使用它来访问有关其自身的资源,而不是访问用户的资源。”

将Okta用作单一登录提供程序(一种更常见的用例)时,可以使用“ 授权代码授予” 。 这种授予类型(其中应用程序允许用户登录并交换访问令牌的授权代码),但是需要一系列重定向,而这些重定向将很难从命令行客户端(例如HTTPie)进行管理。 因此,本教程使用“客户端证书”授予类型来方便地演示一些基本的OAuth / JWT功能。

您希望能想到:“好极了,但是范围误差呢?”

很高兴你问!

范围提供了一种定义和限制令牌授予的访问权限的方法。 在对用户进行授权和身份验证时,通常会使用一系列范围,例如openid email profile 。 这些作用域告诉服务器,该应用程序希望访问用户的个人资料,电子邮件地址,并希望发出OpenID身份验证请求。

客户证书授予类型要求我们定义一个自定义范围。 这就是invalid scope错误所抱怨的。

让我们修复它!

添加自定义范围

返回至developer.okta.com 。 在顶部菜单中,转到API授权服务器

从服务器列表中单击默认服务器。

单击“ 作用域”选项卡,然后单击“ 添加作用域”按钮。

将范围命名为“ customScope”,对其进行描述,然后单击“ 创建” 。 您需要匹配的名称,但是描述是任意的。

令牌认证

再次运行令牌请求

重新运行请求,这次使用自定义范围。

http -f POST https://{yourOktaDomain}/oauth2/default/v1/token \
'Authorization: Basic MG9hZzU4NDg5YW1aTDBN...' \
grant_type=client_credentials \
scope=customScope

这次您将获得令牌!

HTTP/1.1 200 OK
Cache-Control: no-cache, no-store
Connection: Keep-Alive
Content-Type: application/json;charset=UTF-8
Pragma: no-cache
...
{"access_token": "eyJraWQiOiJldjFpay1DS3UzYjJXS3QzSVl1MlJZc3...","expires_in": 3600,"scope": "customScope","token_type": "Bearer"
}

注意Cache-ControlPragma标头。 您不希望此响应被缓存在任何地方。 access_token是浏览器在后续请求中将使用的内容。 请记住,不需要将JWT用作OAuth 2.0访问令牌。 它们非常方便,因为您可以在其中编码防篡改(并且可能是机密的)元数据。

使用您的访问令牌

要在请求中包含访问令牌,请使用类型为BearerAuthorization标头。 下面是一个示例GET请求。

GET /admin HTTP/1.1
Authorization: Bearer eyJraWQiOiJldjFpay1DS3UzYjJXS3QzSVl1MlJZc3...

输入Spring Boot以使用Java进行令牌认证

您准备好使用Java吗? 我已经准备好使用Java。

您要做的第一件事是从GitHub存储库克隆我们的示例应用程序 。

现在,使用以下终端命令检出start分支:

git clone -b start https://github.com/oktadeveloper/okta-spring-boot-token-auth-example.git

此应用程序非常简单。 至少,它看起来超级简单。 实际上,在后台,Spring Boot和Okta做出了相当大的努力,以为您提供功能齐全的REST资源服务器,该服务器具有使用OAuth 2.0和Okta OIDC应用程序进行的JWT令牌身份验证的功能。 AM!

唯一需要进行的配置是在src/main/resources/application.yml文件中。 您需要从上面创建的几个步骤的Okta OIDC应用程序中填写您的客户端ID客户端密钥 。 您使用这些来生成令牌。 它们大致(如果是斜视,则有点类似)对应于OIDC应用程序的用户名和密码。

server:  port: 8080  okta:  oauth2: issuer: https://{yourOktaDomain}/oauth2/default  clientId: {yourClientId}clientSecret: {yourClientSecret}

这就是您需要做的! 至此,您已经拥有了一个功能齐全(如果不是很令人兴奋的话)的Spring Boot资源服务器。

该应用程序的入口点位于Application.java文件中:

@EnableResourceServer  
@SpringBootApplication  
public class Application {  public static void main(String[] args) {  SpringApplication.run(Application.class, args);  }
}

您会注意到这是老式的main()方法所在的地方。 这些天感觉有点像遗物,但这就是所有魔力的开始。 在每个愚蠢的猫录像和Facebook激烈的政治辩论背后,都有一个main()方法开始了这一切。

您正在使用SpringApplication.run()方法来引导Spring框架,该框架将加载Application类。 这将拾取@EnableResourceServer@SpringBootApplication批注。 @SpringBootApplication告诉Spring加载Spring Boot。 @EnableResourceServer将Spring Boot应用程序配置为通过OAuth令牌(可能与OAuth 2.0单一登录相对)对请求进行身份验证。

@EnableResourceServer有几个含义,值得指出。 如果您看一下有关注释的文档 ,则会看到几个要点:如果要配置资源服务器,则需要定义ResourceServerConfigurerAdapter bean; 并以3的硬编码顺序添加了WebSecurityConfigurerAdapter bean。

你为什么要在乎呢? 因为在更复杂的Web应用程序中,您将要同时使用ResourceServerConfigurerAdapterWebSecurityConfigurerAdapter来配置权限。 与使用@EnableOAuth2Sso批注时所做的WebSecurityConfigurerAdapter ,这与简单地使用WebSecurityConfigurerAdapter @EnableOAuth2Sso ,所以我想警告您。 通常,资源服务器端点将以/api或其他内容开头,并由ResourceServerConfigurerAdapter进行配置和保护,而其他任何纯HTML端点将由WebSecurityConfigurerAdapter进行配置。 但是,您需要将@Order(Ordered.HIGHEST_PRECEDENCE)添加到WebSecurityConfigurerAdapter以使其优先于具有硬编码顺序的默认顺序。

如果要查看如何完成此操作的更具体示例,请查看full-config分支 。 您也可以在最后的链接中浏览Siva Tech文章。

除了这些,让我们看一下HelloController类。

@RestController
public class HelloController {  @RequestMapping("/")  public String home(java.security.Principal user) {  return "Hello " + user.getName();  }
}

@RestController批注是@Controller@ResponseBody批注的组合。

@Controller告诉Spring Boot此类是控制器类,并查找URL请求到内部方法的映射。

@ResponseBody指示控制器方法返回原始响应数据,并且不映射到模板名称。 这就是它返回简单字符串的方式,而不是使用Spring的模型和视图模板系统。

@RequestMapping("/")表示将home()方法映射到基本URL。

注意使用了依赖注入来获取java.security.Principal 。 这项工作需要大量自动调整。 Spring和Okta会根据OAuth 2.0和OpenID Connect规范共同验证令牌并进行来回通信,对用户进行身份验证,并提供JWT授权令牌,该令牌包含具有用户“名称”的元数据。

运行Spring Boot App

好的。 一起让它成为现实!

使用以下命令运行Spring Boot应用程序: ./gradlew bootRun

您应该看到很多文本以如下形式结尾:

...
[main] INFO org.springframework.jmx.export.annotation.AnnotationMBeanExporter - Registering beans for JMX exposure on startup
[main] INFO org.springframework.boot.web.embedded.tomcat.TomcatWebServer - Tomcat started on port(s): 8080 (http) with context path ''
[main] INFO com.okta.springboottokenauth.Application - Started Application in 21.209 seconds (JVM running for 21.709)
[2018-10-11 10:31:58.646] - 22235 INFO [http-nio-8080-exec-1] --- org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/]: Initializing Spring FrameworkServlet 'dispatcherServlet'
[http-nio-8080-exec-1] INFO org.springframework.web.servlet.DispatcherServlet - FrameworkServlet 'dispatcherServlet': initialization started
[http-nio-8080-exec-1] INFO org.springframework.web.servlet.DispatcherServlet - FrameworkServlet 'dispatcherServlet': initialization completed in 13 ms

使用JWT进行身份验证

现在运行Spring Boot应用程序,使用HTTPie运行不带令牌的GET请求:

http GET http://localhost:8080

您将获得401 /未经授权:

HTTP/1.1 401
Cache-Control: no-store
Content-Type: application/json;charset=UTF-8
...
{"error": "unauthorized","error_description": "Full authentication is required to access this resource"
}

重新运行它,这次包括您的令牌(取决于经过了多少时间,您可能需要请求一个新令牌):

http GET :8080 'Authorization: Bearer eyJraWQiOiJldjFpay1DS3UzYjJXS3QzSVl1...'

提示:如果收到显示“ Invalid JOSE Header kid”的invalid_token错误,则很有可能用不正确的值更新了application.yml

假设您的令牌仍然有效,您将获得一个HTTP 200:

HTTP/1.1 200
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Length: 26
Content-Type: text/plain;charset=UTF-8
...Hello 0oag58489amZL0MEN0h7

0oag58489amZL0MEN0h7将是您的客户ID。

请记住,您使用的是client_credentials授予类型,并且已将客户端ID客户端密钥作为凭据发送给服务器。 因此,授权服务器将您的客户ID作为您的“名称”发送回去。 在不同的情况下,例如使用授权码授予,这将是用户的名称(或者可能是他们的电子邮件地址或用户名)。

了解有关使用Java进行令牌身份验证和构建安全应用程序的更多信息

了解令牌身份验证对于构建现代Web应用程序至关重要。 有两种用于签名和加密令牌的主要方法:哈希和公钥/私钥。 两种方法都是互联网安全的基础。 在HMAC上查看Wikipedia页面 ,以继续学习JWT中使用的基于哈希的消息认证代码(HMAC)。 要了解公共/专用密钥加密, Red Hat进行了出色的介绍 。

一旦您对这两种技术真正感到满意,就可以看一下关于Medium的有关JWT的出色教程 。

您可能还需要查看RFC规范 。

在Spring结束时,我发现Siva Tech Lab的本教程对说明如何使用OAuth 2.0实施Spring Boot应用程序很有帮助。

以下是Okta博客的其他一些链接,可帮助您继续前进:

  • Spring Boot,OAuth 2.0和Okta入门
  • 确保Spring Boot应用程序安全的10种绝佳方法
  • 如果您的JWT被盗怎么办?
  • 使用Spring Boot 2.0和OAuth 2.0构建并保护微服务

如果您对此帖子有任何疑问,请在下面添加评论。 有关更多精彩内容, 请在Twitter上关注@oktadev , 在Facebook上关注我们,或订阅我们的YouTube频道 。

Java Apps的简单令牌身份验证最初于2018年10月16日发布在Okta开发人员博客上。

“我喜欢编写身份验证和授权代码。” 〜从来没有Web开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。

翻译自: https://www.javacodegeeks.com/2018/10/simple-token-authentication-java-apps.html

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

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

相关文章

matlab中rb代表什么意思,你知道“川藏线上”女游客举着“求RB”的牌子是啥意思吗?暗语啊!...

现在穷游好像一种旅行圈的时髦&#xff0c;很多人都想着穷游能够锻炼人的意志&#xff0c;能够促进人与人的交流与合作&#xff0c;能够在路上遇到不一样的精彩&#xff0c;能够发现人性与真善美。现在穷游的人不在少数&#xff0c;尤其是在川藏线上&#xff0c;想要穷游入藏的…

华为主题锁屏壁纸换不掉_华为手机总多出莫名的照片?那是因为这3个设置没关闭,赶紧自查...

随着华为在科技、5G以及数码领域的表现越来越好&#xff0c;使用华为手机的人也越来越多。不知道你在使用华为手机的过程中&#xff0c;有没有这样的感觉&#xff0c;华为手机总是多出莫名其妙的照片&#xff0c;即使删除了下次还会出现。如果有这样的情况&#xff0c;可能是手…

php nginx 域名重定向,Nginx默认虚拟主机、用户认证、域名重定向

Nginx默认虚拟主机定义默认虚拟主机配置文件,在http下面加入include vhost/*.conf在/usr/local/nginx/conf/下创建目录#mkdir vhost/ //创建vhost目录#cd vhost/ //进入目录#vim aaa.com.conf //编辑文件server{listen 80 default_server; // 有这个标记的就是默认虚拟主机serv…

Java:使用SingletonStream获得性能

仅具有一个元素的Java流有时会在应用程序中造成不必要的开销。 了解如何使用SingletonStream对象并为其中某些此类流获得十倍的性能&#xff0c;并了解如何同时简化代码。 背景 Java 8中的Stream库是有史以来Java语言最强大的功能之一。 一旦您开始了解它的多功能性和所产生的…

php调用pdf2html,php html2pdf

*安装composer运行html2pdf时&#xff0c;readme里面建议按照composer-setup.exe安装过程中出现openssl的问题&#xff0c;在php.ini中开启相应extension即可&#xff0c;路径写绝对路径&#xff0c;否则按默认路径找不到在html2pdf的文件路径下&#xff0c;cmd运行composer in…

JDK 11:新的默认收集方法toArray(IntFunction)

“ JDK 11 Early-Access发行说明 ”表明JDK 11的Early Access Build 20在Collection接口上包括一个新的默认方法 &#xff0c;该方法 “允许将集合的元素转移到所需运行时类型的新创建的数组中”。 这个新的默认方法 [ Collection.toArray&#xff08;IntFunction&#xff09; …

获取清空textarea的文字内容_运用|你会做 词云图(文字云) 吗?

词云图,也叫文字云,是对文本中出现频率较高的“关键词”予以视觉化的展现,词云图过滤掉大量的低频低质的文本信息,使得浏览者只要一眼扫过文本就可领略文本的主旨。今天&#xff0c;兰色就分享一下词云图的做法。制作步骤&#xff1a;1、打开词云图网站打开网页https://wordart…

如何在Spring Boot App中集成H2数据库

你好朋友&#xff0c; 在本教程中&#xff0c;我们将尝试探索如何在Spring Boot应用程序中与H2数据库集成。 在进行检查之前&#xff0c;让我们了解有关H2数据库的一些基础知识&#xff0c;如下所述&#xff0c;然后我们将讨论H2数据库与Spring Boot的集成。 什么是H2数据库…

python在路径里添加变量_想学Python?那就先从头开始吧!

作为人工智能和大数据时代最具竞争力的 Python 语言&#xff0c;越来越多的出现在各大编程热搜排行榜上。首先你要了解什么是python了解Python语言Python是一种解释型, 面向对象, 动态数据类型的高级程序设计语言.Python由Guido van Rossum&#xff08;荷兰&#xff09; 于1989…

ant 走马灯面板指示显示不出来_触摸屏报警信息显示设置方法

人机界面(HMI)是自动化设备中非常常用的器件&#xff0c;用于替代操作面板上的实体按钮或者显示指示。人机界面的适用极大的减小了设备操作面板的尺寸&#xff0c;提升了设备的整体美观度。随着自动化设备的自动化程度的提高&#xff0c;也对设备的报警信息提出了更高的要求。如…

oracle bbed 使用,Oracle BBED使用 四步快速启动Oracle BBED

Oracle BBED使用&#xff0c;四步快速启动Oracle BBED&#xff0c;环境&#xff1a;Oracle 10g RHEL 5.8&#xff0c;介绍&#xff1a;BBED全称为数据块浏览和编辑。用于对Oracle blo环境&#xff1a;Oracle 10g RHEL 5.8介绍&#xff1a;BBED全称为数据块浏览和编辑。用于对Or…

linux内核4.4和4.5,[图]Linux Kernel 4.5系列第4个维护版本发布

Greg Kroah-Hartman表示&#xff1a;“我今天宣布了Linux 4.5.4内核&#xff0c;所有Linux 4.5内核系列用户必须尽快升级。已经升级的4.5.y git tree能够在git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git linux-4.5.y中获取&#xff0c;也能通过访问h…

域名是如何被墙的_如何快速搭建属于自己的个性网站?

说明一直以来都是用GithubPage搭建的博客&#xff0c;因为服务器在国外&#xff0c;访问速度一直比较慢&#xff0c;再后来有一批服务器被墙掉了导致国内网络环境直接无法访问。这里可以多说一句&#xff0c;GithubPage跟Github用的可以不是同一IP地址服务器&#xff0c;被墙很…

python 对象锁_也许你对 Python GIL 锁的理解是 错的。

摄影&#xff1a;产品经理甜白与草莓更配~我刚到现在这个公司时&#xff0c;听到当时一个高级工程师(现已离职)大声地跟他旁边的同事说&#xff1a;Python 有 GIL 锁&#xff0c;所以它的多线程实际上是单线程&#xff0c;所以写多线程代码不用考虑线程冲突&#xff0c;不用加…

服务性服务–服务到服务的通话

在上一篇文章中&#xff0c;我介绍了如何使用Knative的 Serving功能来运行示例Java应用程序。 这篇文章将介绍部署两个应用程序的步骤&#xff0c;其中一个应用程序调用另一个。 样品细节 整个示例可在我的github存储库中找到– https://github.com/bijukunjummen/sleuth-webf…

linux cookie 地址,SYN Cookie原理及其在Linux内核中的实现

在目前以IPv4为支撑的网络协议上搭建的网络环境中&#xff0c;SYN Flood是一种非常危险而常见的DoS攻击方式。到目前为止&#xff0c;能够有效防范SYN Flood攻击的手段并不多&#xff0c;而SYN Cookie就是其中最著名的一种。SYN Cookie原理由D. J. Bernstain和 Eric Schenk发明…

用置换破坏您的JUnit5测试

编写JUnit测试可能是一个乏味而乏味的过程。 了解如何使用排列结合TestFactory方法和DynamicTest对象以最少的编码工作来改进测试类。 在本文中&#xff0c;我将使用Java流ORM Speedment&#xff0c;因为它包含一个现成的Permutation类&#xff0c;从而帮助我节省了开发时间。…

企业应用程序开发框架的分类

如果您使用的是“最佳Java框架”&#xff0c;那么您很可能会迷失本文 &#xff0c;它对Java Enterprise世界中的情况进行了很好的概述。 但是&#xff0c;从我的角度来看&#xff0c;它缺少一件非常重要的事情–对上述框架进行分类。 让我们看看这个生态系统的另一个角度&…

c语言中怎么定义的字符串,C语言中定义字符串的几种方式

1&#xff0c;什么是字符串&#xff1f;所谓字符串本质上就是以\0作为结尾的特殊字符数组&#xff1b;2&#xff0c;定义字符串的过程中有哪些注意点由于字符串本质上其实就是以\0作为结尾的特殊字符数组&#xff0c;所以定义字符串时&#xff0c;必须保证字符串存储的最后一个…

java8 linq4j_Java 8仍然需要LINQ吗? 还是比LINQ更好?

java8 linq4j长期以来&#xff0c; LINQ是.NET软件工程生态系统中发生的最好的事情之一。 通过在Visual Studio 2008中引入lambda表达式和monad &#xff0c;它使C&#xff03;语言跃居Java之前&#xff0c;Java在当时是版本6&#xff0c;但仍在讨论泛型类型擦除的优缺点。 这项…