JwtAccessConverterJwtTokenStorejdbc建表结构

news2025/1/11 2:52:14

文章目录

  • JWT实现
    • Mac
      • TestMacSigner
    • Rsa
      • 生成jks证书
        • 需要先安装openssl
        • keytool生成jks (Java Key Store) 文件
        • 测试密钥
  • JwtTokenStore
    • InMemoryTokenStore&RedisTokenStore&JdbcTokenStore&JwtTokenStore图解
    • JwtTokenStore详解
  • jdbc实现
    • 表结构说明1
      • oauth_client_details
      • oauth_access_token
      • oauth_refresh_token
    • 表结构说明2
      • oauth_client_details&oauth_client_token&oauth_access_token&oauth_refresh_token&oauth_code 表介绍
    • 表结构说明3
      • 官网sql(HSQL)
      • mysql版本

Vue – token/refresh_token 使用机制

JWT实现

Mac

TestMacSigner

public class TestMacSigner {

    public static void main(String[] args) {

        // 创建1个MacSigner
        MacSigner macSigner = new MacSigner("abc123");

        // 使用 macSigner 对 "data" 进行签名
        byte[] signedBytes = macSigner.sign("data".getBytes());
        // macSigner 对 "data" 签名 的内容进行输出(直接转为字符串会乱码)
        System.out.println(Arrays.toString(signedBytes));

        // macSigner 对 "data" 签名 的内容 进行 base64 编码
        String based64Str = Base64.getEncoder().encodeToString(signedBytes);
        // 将签名的字节 以 base64编码 输出
        System.out.println(based64Str);
        // 将签名的字节 进行 base64编码 得到的字符串, 使用 base64解码 得到的内容 输出, 查看与原内容是否相同
        System.out.println(Arrays.toString(Base64.getDecoder().decode(based64Str)));

        // 使用macSigner 对 内容 与 签名 进行验签
        // (其实就是对 提供的内容 再一次签名 得到签名结果, 与 提供的签名 比较是否相同。
        //   如果相同, 说明使用的是同样的密钥, 如果不同, 说明使用的是不同的密钥。进而说明一定是拥有密钥的人通过签名颁发的此令牌)
        macSigner.verify("data".getBytes(), signedBytes);

    }

}

Rsa

使用jwt(非对称加密)
可参考:https://www.cnblogs.com/hellxz/p/12044340.html

生成jks证书

需要先安装openssl

https://slproweb.com/products/Win32OpenSSL.html下载对应的openssl版本,只需要一直点下一步即可,安装完毕后,将它的bin目录配置到环境变量
在这里插入图片描述

keytool生成jks (Java Key Store) 文件

首先使用keytool生成jks (Java Key Store) 证书,每个证书包含公钥和私钥`

keytool -genkeypair -alias my-auth -keyalg RSA -keypass 123456 -keystore my-auth.jks -storepass 123456
  • alias: 秘钥别名
  • keyalg: 使用的hash算法
  • keypass: 秘钥访问密码
  • keystore: 秘钥库文件名,生成证书文件
  • storepass: 证书的访问密码

在这里插入图片描述

在my-auth.jks同目录下,执行命令导出公钥,需要输入口令:123456

keytool -list -rfc --keystore my-auth.jks | openssl x509 -inform pem -pubkey

在这里插入图片描述

测试密钥
package com.zzhua;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;
import org.springframework.core.io.ClassPathResource;
import org.springframework.security.jwt.Jwt;
import org.springframework.security.jwt.JwtHelper;
import org.springframework.security.jwt.crypto.sign.RsaSigner;
import org.springframework.security.jwt.crypto.sign.RsaVerifier;
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;

import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class TestJwt {

    @Test
    public void test_encodeJWT() throws JsonProcessingException, NoSuchAlgorithmException, InvalidKeySpecException {

        // (这里读取jks文件的流程可以参考:
        //		ResourceServerTokenServicesConfiguration$JwtKeyStoreConfiguration#accessTokenConverter()的源码处理过程)
        /*
        	// 这个bean只有在JwtKeyStoreCondition条件满足时,才会生效
        	// (亦即:只要配置了security.oauth2.resource.jwt.key-store就会生效)
        	@Bean
			public JwtAccessTokenConverter accessTokenConverter() {

				// security.oauth2.resource.jwt.key-store
				// security.oauth2.resource.jwt.key-store-password
				// security.oauth2.resource.jwt.key-alias
				// 如果提供了key-store, 则以上三个不能为空
				Assert.notNull(this.resource.getJwt().getKeyStore(), "keyStore cannot be null");
				Assert.notNull(this.resource.getJwt().getKeyStorePassword(), "keyStorePassword cannot be null");
				Assert.notNull(this.resource.getJwt().getKeyAlias(), "keyAlias cannot be null");

				JwtAccessTokenConverter converter = new JwtAccessTokenConverter();

				// 拿到jks证书
				Resource keyStore = this.context.getResource(this.resource.getJwt().getKeyStore());
				// 证书访问密码
				char[] keyStorePassword = this.resource.getJwt().getKeyStorePassword().toCharArray();
				KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(keyStore, keyStorePassword);

				// 秘钥别名
				String keyAlias = this.resource.getJwt().getKeyAlias();
				// 密钥访问密码 ,先获取秘钥访问密码,如果没有提供,则使用证书访问密码(所以最好这2个保持一致)
				char[] keyPassword = Optional.ofNullable(
						this.resource.getJwt().getKeyPassword())
						.map(String::toCharArray).orElse(keyStorePassword);

				 // 这个setKeyPair方法在下面有解释
				 converter.setKeyPair(keyStoreKeyFactory.getKeyPair(keyAlias, keyPassword));

			return converter;
		}


		*/
        //加载证书(参数:jks证书文件名)
        ClassPathResource classPathResource = new ClassPathResource("my-auth.jks");

        //密钥库(第二个参数:证书的访问密码)
        KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(classPathResource, "123456".toCharArray());

        //获取秘钥对(第一个参数: 密钥别名;第二个参数:证书里面的密钥的访问密码)
        KeyPair keyPair = keyStoreKeyFactory.getKeyPair("my-auth", "123456".toCharArray());

        //获取私钥 , 私钥加密,公钥验证,是谓签名
        RSAPrivateKey privateKey = (RSAPrivateKey)keyPair.getPrivate();

        // 获取公钥 (与通过命令获取的公钥一致,只不过没有换行符,一样的效果)
        byte[] decode = Base64.getEncoder().encode(keyPair.getPublic().getEncoded());
        String s = new String(decode);
        System.out.println(s);
        // MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgdlyFwN0MWeLGvqrXbdZsvgHbtTWWpr/bzTlydZt5w0S1TUHwhwZiMXuMWvJU2wtlrw0AlftRbsqEy11sFECwtZ50/V7aEd1O1nHHCrVXgUjjktKBW02mmqF5AjlIMqTeS0QFB2iOI3Zs0YcbIIMP8DQFG5laKg4/C3F0LzSDqLOk1GH14+p+EdJ+fgvu0ip9s6eDA2mVF6Og5PlXdYjnvQwQDduZd/zxzXXxT9ZP4kQDRULjNxleJKljRwIa/mEJokWR4Xmu41uFetBpIjYtLV9teaKEB0GT0XVYmMSmonkqB4pHx8VUknNs7AQgQgniNBLX0nuuqiVx1q2wNxvIQIDAQAB

        //准备载荷数据
        Map<String,Object> data = new HashMap<>();
        data.put("id",1L);
        data.put("username","zzhua");
        data.put("role","admin");
        String content = new ObjectMapper().writeValueAsString(data);
        System.out.println(content); // {"role":"admin","id":1,"username":"zzhua"}

        //创建令牌
        Jwt jwt = JwtHelper.encode(content, new RsaSigner(privateKey));
        //获取创建的令牌
        String token = jwt.getEncoded();

        System.out.println(token);
        // eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.
        // eyJyb2xlIjoiYWRtaW4iLCJpZCI6MSwidXNlcm5hbWUiOiJ6emh1YSJ9.
        // Yw-qmMtW6qqIkrj-8i_3m9QxIMOL9Xb7BKHGUIy7V4sTfkmJ7jAVTD6ij_vAHg_nNBrUtxWxcUnOLWCZGAiMKzjGl4yms8ThFQCpM5LNdH0crZi1fRZHKM0LbMSnPKO7IsuogiTbXNYdk-W3zcmk2zWoNiKMRtbflWlrKJMJEOjv5CPJwxBoWw6v0YIbFDGYC8YijnJ_b-U9YchSlpshEAiAO96l3OfwcTN99nXvMnQoGA-iOQaVNXMU_0Qa-A6xxfL8NtpqLX76ucLr6CcgmJky-VT4SyDOlA7AwiM2nsXwllBkA84T8AtFA9xSvlzN6yKPeAu_PKbJucTg8O51dw


        // 在上面的过程中, 我们把公钥的字节转成了Base64编码后的字符串,
        // 并且注意到编码后的字符串和使用命令获取的公钥是一致的。
        // 既然公钥可以这样玩,那么私钥是不是也可以这样玩呢?
        // 如果可以这样玩的话,那在后面的处理过程中就可以舍弃掉这个jks文件了,直接使用公钥和私钥的字符串就行了
        // (只是说可以这样玩,但是这样玩私钥就以明文的方式暴露了)
        // 私钥以base64字符串编码的形式暴露出去后,该怎么使用呢?
        byte[] encoded = privateKey.getEncoded(); // 获取到私钥的字节数据
        byte[] encoded2 = Base64.getEncoder().encode(encoded);// 对私钥的字节进行base64编码
        String s1 = new String(encoded2); // 获取到私钥进行base64编码后的字符串(这个就可以暴露给外界了, 使用base64编码的好处是,不会出现乱码的情况)

        byte[] decode1 = Base64.getDecoder().decode(s1.getBytes()); // 使用外界暴露的私钥字符串,获取到base64编码后的字节,然后对这些字节数据解码,来获取原始的字节数据

        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(decode1);
        RSAPrivateKey generatePrivate = (RSAPrivateKey) keyFactory.generatePrivate(keySpec); // 强转成RSAPrivateKey
        Jwt jwt2 = JwtHelper.encode(content, new RsaSigner(generatePrivate)); // 使用新的私钥对象
        //获取创建的令牌
        String token2 = jwt2.getEncoded();
        System.out.println(token2); // 生成的token与前面完全一致
        // eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.
        // eyJyb2xlIjoiYWRtaW4iLCJpZCI6MSwidXNlcm5hbWUiOiJ6emh1YSJ9.
        // Yw-qmMtW6qqIkrj-8i_3m9QxIMOL9Xb7BKHGUIy7V4sTfkmJ7jAVTD6ij_vAHg_nNBrUtxWxcUnOLWCZGAiMKzjGl4yms8ThFQCpM5LNdH0crZi1fRZHKM0LbMSnPKO7IsuogiTbXNYdk-W3zcmk2zWoNiKMRtbflWlrKJMJEOjv5CPJwxBoWw6v0YIbFDGYC8YijnJ_b-U9YchSlpshEAiAO96l3OfwcTN99nXvMnQoGA-iOQaVNXMU_0Qa-A6xxfL8NtpqLX76ucLr6CcgmJky-VT4SyDOlA7AwiM2nsXwllBkA84T8AtFA9xSvlzN6yKPeAu_PKbJucTg8O51dw

        // 既然私钥以base64编码的方式暴露出去了,那么公钥也以这种方式暴露出去,该怎么用呢?
        RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
        byte[] encode = Base64.getEncoder().encode(rsaPublicKey.getEncoded());
        String s2 = new String(encode); // 暴露给外界的公钥字符串

        // 解析暴露给外界的公钥字符串,以获取RSA公钥对象
        X509EncodedKeySpec keySpec2 = new X509EncodedKeySpec(Base64.getDecoder().decode(s2.getBytes()));
        RSAPublicKey rsaPublicKey2 = (RSAPublicKey) keyFactory.generatePublic(keySpec2);
        String JWTToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYWRtaW4iLCJpZCI6MSwidXNlcm5hbWUiOiJ6emh1YSJ9.Yw-qmMtW6qqIkrj-8i_3m9QxIMOL9Xb7BKHGUIy7V4sTfkmJ7jAVTD6ij_vAHg_nNBrUtxWxcUnOLWCZGAiMKzjGl4yms8ThFQCpM5LNdH0crZi1fRZHKM0LbMSnPKO7IsuogiTbXNYdk-W3zcmk2zWoNiKMRtbflWlrKJMJEOjv5CPJwxBoWw6v0YIbFDGYC8YijnJ_b-U9YchSlpshEAiAO96l3OfwcTN99nXvMnQoGA-iOQaVNXMU_0Qa-A6xxfL8NtpqLX76ucLr6CcgmJky-VT4SyDOlA7AwiM2nsXwllBkA84T8AtFA9xSvlzN6yKPeAu_PKbJucTg8O51dw";
        Jwt decodedJwt = JwtHelper.decodeAndVerify(JWTToken, new RsaVerifier(rsaPublicKey2));
        //获取载荷数据
        String claims = decodedJwt.getClaims();
        System.out.println(claims);
        //{"role":"admin","id":1,"username":"zzhua"}
    }

    // 注意一下,下面的校验只会校验签名是否正确(即: 被签名的内容有没有被篡改),不会校验jwt令牌是否过期
    @Test
    public void test_decodeJWT() {
        //JWT的token
        String JWTToken = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYWRtaW4iLCJpZCI6MSwidXNlcm5hbWUiOiJ6emh1YSJ9.Yw-qmMtW6qqIkrj-8i_3m9QxIMOL9Xb7BKHGUIy7V4sTfkmJ7jAVTD6ij_vAHg_nNBrUtxWxcUnOLWCZGAiMKzjGl4yms8ThFQCpM5LNdH0crZi1fRZHKM0LbMSnPKO7IsuogiTbXNYdk-W3zcmk2zWoNiKMRtbflWlrKJMJEOjv5CPJwxBoWw6v0YIbFDGYC8YijnJ_b-U9YchSlpshEAiAO96l3OfwcTN99nXvMnQoGA-iOQaVNXMU_0Qa-A6xxfL8NtpqLX76ucLr6CcgmJky-VT4SyDOlA7AwiM2nsXwllBkA84T8AtFA9xSvlzN6yKPeAu_PKbJucTg8O51dw";
        //公钥验证,通过 ‘keytool -list -rfc --keystore whale.jks | openssl x509 -inform pem -pubkey’ 得到公钥
        String publicKey = "-----BEGIN PUBLIC KEY-----\n" +
                "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAgdlyFwN0MWeLGvqrXbdZ\n" +
                "svgHbtTWWpr/bzTlydZt5w0S1TUHwhwZiMXuMWvJU2wtlrw0AlftRbsqEy11sFEC\n" +
                "wtZ50/V7aEd1O1nHHCrVXgUjjktKBW02mmqF5AjlIMqTeS0QFB2iOI3Zs0YcbIIM\n" +
                "P8DQFG5laKg4/C3F0LzSDqLOk1GH14+p+EdJ+fgvu0ip9s6eDA2mVF6Og5PlXdYj\n" +
                "nvQwQDduZd/zxzXXxT9ZP4kQDRULjNxleJKljRwIa/mEJokWR4Xmu41uFetBpIjY\n" +
                "tLV9teaKEB0GT0XVYmMSmonkqB4pHx8VUknNs7AQgQgniNBLX0nuuqiVx1q2wNxv\n" +
                "IQIDAQAB\n" +
                "-----END PUBLIC KEY-----";
        //解密和验证令牌(在这里,我们可以看到公钥就是一个字符串,可以直接封装到RsaVerifier中,
        //             所以只要暴露了这个公钥字符串, 资源服务器拿着这个公钥字符串,就可以校验签名了)
        Jwt jwt = JwtHelper.decodeAndVerify(JWTToken, new RsaVerifier(publicKey));
        //获取载荷数据
        String claims = jwt.getClaims();
        System.out.println(claims);
        //{"role":"admin","id":1,"username":"zzhua"}

    }
}

JwtTokenStore

InMemoryTokenStore&RedisTokenStore&JdbcTokenStore&JwtTokenStore图解

在这里插入图片描述

JwtTokenStore详解

在JwtTokenStore的图解中

jdbc实现

表结构说明1

OAuth2 oauth_client_details,oauth_access_token,oauth_refresh_token表结构

oauth_client_details

在这里插入图片描述

oauth_access_token

在这里插入图片描述

oauth_refresh_token

在这里插入图片描述

表结构说明2

oauth_client_details&oauth_client_token&oauth_access_token&oauth_refresh_token&oauth_code 表介绍

来源:OAuth2相关数据表字段的详细说明

在这里插入图片描述

表结构说明3

官网sql(HSQL)

-- used in tests that use HSQL
create table oauth_client_details (
  client_id VARCHAR(256) PRIMARY KEY,
  resource_ids VARCHAR(256),
  client_secret VARCHAR(256),
  scope VARCHAR(256),
  authorized_grant_types VARCHAR(256),
  web_server_redirect_uri VARCHAR(256),
  authorities VARCHAR(256),
  access_token_validity INTEGER,
  refresh_token_validity INTEGER,
  additional_information VARCHAR(4096),
  autoapprove VARCHAR(256)
);

create table oauth_client_token (
  token_id VARCHAR(256),
  token LONGVARBINARY,
  authentication_id VARCHAR(256) PRIMARY KEY,
  user_name VARCHAR(256),
  client_id VARCHAR(256)
);

create table oauth_access_token (
  token_id VARCHAR(256),
  token LONGVARBINARY,
  authentication_id VARCHAR(256) PRIMARY KEY,
  user_name VARCHAR(256),
  client_id VARCHAR(256),
  authentication LONGVARBINARY,
  refresh_token VARCHAR(256)
);

create table oauth_refresh_token (
  token_id VARCHAR(256),
  token LONGVARBINARY,
  authentication LONGVARBINARY
);

create table oauth_code (
  code VARCHAR(256), authentication LONGVARBINARY
);

create table oauth_approvals (
	userId VARCHAR(256),
	clientId VARCHAR(256),
	scope VARCHAR(256),
	status VARCHAR(10),
	expiresAt TIMESTAMP,
	lastModifiedAt TIMESTAMP
);


-- customized oauth_client_details table
create table ClientDetails (
  appId VARCHAR(256) PRIMARY KEY,
  resourceIds VARCHAR(256),
  appSecret VARCHAR(256),
  scope VARCHAR(256),
  grantTypes VARCHAR(256),
  redirectUrl VARCHAR(256),
  authorities VARCHAR(256),
  access_token_validity INTEGER,
  refresh_token_validity INTEGER,
  additionalInformation VARCHAR(4096),
  autoApproveScopes VARCHAR(256)
);

mysql版本

oauth2表语句及解释

CREATE TABLE `oauth_access_token` (
  `create_time` timestamp NOT NULL DEFAULT current_timestamp(),
  `token_id` varchar(255) DEFAULT NULL,
  `token` blob DEFAULT NULL,
  `authentication_id` varchar(255) DEFAULT NULL,
  `user_name` varchar(255) DEFAULT NULL,
  `client_id` varchar(255) DEFAULT NULL,
  `authentication` blob DEFAULT NULL,
  `refresh_token` varchar(255) DEFAULT NULL,
  UNIQUE KEY `authentication_id` (`authentication_id`),
  KEY `token_id_index` (`token_id`),
  KEY `authentication_id_index` (`authentication_id`),
  KEY `user_name_index` (`user_name`),
  KEY `client_id_index` (`client_id`),
  KEY `refresh_token_index` (`refresh_token`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='授权成功token';

CREATE TABLE `oauth_client_details` (
  `client_id` varchar(255) NOT NULL,
  `resource_ids` varchar(255) DEFAULT NULL,
  `client_secret` varchar(255) DEFAULT NULL,
  `scope` varchar(255) DEFAULT NULL,
  `authorized_grant_types` varchar(255) DEFAULT NULL,
  `web_server_redirect_uri` varchar(255) DEFAULT NULL,
  `authorities` varchar(255) DEFAULT NULL,
  `access_token_validity` int(11) DEFAULT NULL,
  `refresh_token_validity` int(11) DEFAULT NULL,
  `additional_information` text DEFAULT NULL,
  `create_time` timestamp NOT NULL DEFAULT current_timestamp(),
  `archived` tinyint(1) DEFAULT 0,
  `trusted` tinyint(1) DEFAULT 0,
  `autoapprove` varchar(255) DEFAULT 'false',
  PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='客户端详情';

CREATE TABLE `oauth_code` (
  `create_time` timestamp NOT NULL DEFAULT current_timestamp(),
  `code` varchar(255) DEFAULT NULL,
  `authentication` blob DEFAULT NULL,
  KEY `code_index` (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='授权code';

CREATE TABLE `oauth_refresh_token` (
  `create_time` timestamp NOT NULL DEFAULT current_timestamp(),
  `token_id` varchar(255) DEFAULT NULL,
  `token` blob DEFAULT NULL,
  `authentication` blob DEFAULT NULL,
  KEY `token_id_index` (`token_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COMMENT='更新token';

-- Add indexes
create index token_id_index on oauth_access_token (token_id);
create index authentication_id_index on oauth_access_token (authentication_id);
create index user_name_index on oauth_access_token (user_name);
create index client_id_index on oauth_access_token (client_id);
create index refresh_token_index on oauth_access_token (refresh_token);
 
create index token_id_index on oauth_refresh_token (token_id);
 
create index code_index on oauth_code (code);

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

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

相关文章

Win10系统自带输入法英文变大的问题

现在习惯使用Windows自带的五笔输入法了&#xff0c;但一直以来总会遇到输入时突然英文字母变大了&#xff0c;相隔空间也变大了的情况。 &#xff41;&#xff53;&#xff44;&#xff46;&#xff47;&#xff48;&#xff4b;&#xff4c; asdfghkl 后来知道这是输入法变…

如何在Linux虚拟机服务器上配置和部署Java项目?

在Linux虚拟机上配置和部署Java项目&#xff0c;通常涉及以下步骤&#xff1a; 1. 准备Linux虚拟机 选择合适的Linux发行版 &#xff1a;根据项目需求和个人熟悉程度&#xff0c;选择如Ubuntu LTS、CentOS Stream或Debian等发行版。 安装虚拟机软件 &#xff1a;在宿主机&#…

css图片适配,不随屏幕的大小变化

.carimg {width: 100%;height: 100%;max-width: 100%;max-height: 100%;object-fit: cover; } <img class"carimg" :src"item.imageUrl" alt"" /> 效果&#xff1a; 全屏时 屏幕变小时

985找工作都这么难了吗

经历如下 也不知道自己适合干啥 好想找份实习入门啊

无人机RTMP推流EasyDSS直播平台推流成功,不显示直播按钮是什么原因?

互联网视频云平台/视频点播直播/视频推拉流EasyDSS支持HTTP、HLS、RTMP等播出协议&#xff0c;并且兼容多终端&#xff0c;如Windows、Android、iOS、Mac等。为了便于用户集成与二次开发&#xff0c;我们也提供了API接口供用户调用和集成。在无人机场景上&#xff0c;可以通过E…

Allegro铺铜以及分割操作

Allegro铺铜以及分割操作 一、铺铜全局设置 点击Shape–>Global Dynamic Shape Parameters&#xff0c;在Shape fill中选择Smooth&#xff0c;其他不用管&#xff0c;这个是在铺铜的时候自动避让不同网络&#xff0c;在Void controls中一般填写如下参数&#xff0c;即避让…

cocos creator3.7版本拖拽事件处理

前言&#xff1a;网上能找到的资料都太落后了&#xff0c;导致哥们用AI去写&#xff0c;全是瞎B写&#xff0c;版本都不对。贴点实际有用的。别老捣鼓你那破convertToNodeSpaceAR或者convertToNodeSpace了。 核心代码 touch.getDeltaX() touch.getDeltaY() 在cocoscreator3…

windows系统下安装fnm

由于最近做项目要切换多个node版本&#xff0c;查询了一下常用的有nvm和fnm这两种&#xff0c;对比了一下选择了fnm。 下载fnm 有两种方式&#xff0c;目前最新版本是1.37.0&#xff1a; 1.windows下打开powershell&#xff0c;执行以下命令下载fnm winget install Schniz.f…

Linux上手实验七:网络配置与管理

lab 2.3 网络配置与管理 1、实验背景&#xff1a; 做为服务器操作系统的企业版 CentOS 7 的网络性能及网络管理是非常重要&#xff0c;往往在部署重要应用的先决条件就是&#xff0c;配置好网络参数及测试好网络的联通性。 作为 Linux 管理员&#xff0c;对于系统的网络配置和…

PNAS | 工作记忆中大脑节律的因果功能图

摘要 工作记忆是一个涉及大脑中多个功能解剖节点的关键认知过程。尽管有大量与工作记忆结构相关的神经影像学证据&#xff0c;但我们对控制整体表现的关键中枢的理解并不完整。因果解释需要在对特定功能解剖节点进行安全、暂时和可控的神经调节后进行认知测试。随着经颅交流电…

velocity:允许赋值语句赋值null:#set( $var = ...)

velocity的模板中赋值语句#set( $var ....)默认是不允许对变量设置为null的。 参见velocity官方文档说明&#xff1a;https://velocity.apache.org/engine/devel/vtl-reference.html#set-establishes-the-value-of-a-reference 因为不能赋值null&#xff0c;在循环语句中&…

uni-app加持下的Vue开发:效率与功能的双赢

文章目录 一、Vue.js简介二、uni-app简介三、Vue与uni-app混合开发的优势四、Vue与uni-app混合开发的实践《Vue.js核心技术解析与uni-app跨平台实战开发》编辑推荐内容简介作者简介目录前言/序言 在当今的前端开发领域&#xff0c;Vue.js以其简洁的API、灵活的组件系统和响应式…

小白学Linux | 日志排查

一、windows日志分析 在【运行】对话框中输入【eventvwr】命令&#xff0c;打开【事件查看器】窗 口&#xff0c;查看相关的日志 管理员权限进入PowerShell 使用Get-EventLog Security -InstanceId 4625命令&#xff0c;可获取安全性日志下事 件 ID 为 4625&#xff08;失败登…

一分钟使用Java实现socket消息传递

一、目的 本程序旨在模拟航空器与塔台之间的实时消息传递&#xff0c;展示其在实际航空通讯中的应用。通过使用 Java 的 JFrame 进行图形用户界面&#xff08;GUI&#xff09;的设计&#xff0c;以及 socket 编程实现网络通信&#xff0c;该程序能够提供一个直观的界面来显示航…

Java(蓝桥杯)一维二维数组应用

介绍&#xff1a; 一维数组&#xff0c;用来熟悉代码&#xff0c;主要考察二维数组&#xff1a; 二维数组存储行、列数据&#xff0c;遍历&#xff0c;输出结果 二维数组的旋转 二维数组数据的找规律。等等 二维数组问题&#xff0c;不难&#xff0c;但是比较繁琐。需要细…

java程序在运行过程各个内部结构的作用

一&#xff1a;内部结构 一个进程对应一个jvm实例&#xff0c;一个运行时数据区&#xff0c;又包含多个线程&#xff0c;这些线程共享了方法区和堆&#xff0c;每个线程包含了程序计数器、本地方法栈和虚拟机栈接下来我们通过一个示意图介绍一下这个空间。 如图所示,当一个hell…

在Linux中进行Redis的yum安装与配置

redis安装在IP为x.x.x.x的服务器上 redis是使用内存作为主存&#xff0c;使用硬盘来实现数据持久化&#xff0c;而且redis是周期性的将数据写到硬盘上。这就意味着一旦服务器出现断电、重启之类的情况&#xff0c;很可能会出现数据丢失的情况&#xff0c;因此不建议使用redis来…

直播美颜插件详解:美颜SDK技术探讨

今天&#xff0c;小编将深入讲解美颜插件与美颜SDK技术&#xff0c;对其原理和应用进行详细解析。 一、美颜SDK技术简介 美颜SDK专门用于实现美颜功能。其核心技术包括图像处理算法和人工智能技术。美颜SDK可以实时捕捉摄像头画面&#xff0c;识别人脸&#xff0c;然后对人脸…

【附带源码】机械臂MoveIt2极简教程(三)、URDF/SRDF介绍

系列文章目录 【附带源码】机械臂MoveIt2极简教程(一)、moveit2安装 【附带源码】机械臂MoveIt2极简教程(二)、move_group交互 【附带源码】机械臂MoveIt2极简教程(三)、URDF/SRDF介绍 目录 系列文章目录1. URDF1.1 URDF相关资源1.2 小技巧1.2.1 关节名称1.2.2 安全限制…

云计算-期末复习题-选择/判断/填空/简答(1)

目录 填空题/简答题 单选题 多选题 判断题 云计算期末复习部分练习题&#xff0c;下一章会补全。祝大家好好复习&#xff0c;顺利通过课程。 填空题/简答题 >保障云基本安全的对策包括&#xff08;&#xff09;、&#xff08;&#xff09;和&#xff08;&#xff09; &…