springboot3 集成spring-authorization-server (一 基础篇)

news2024/9/20 5:36:46

官方文档

Spring Authorization Server

环境介绍

java:17

SpringBoot:3.2.0

SpringCloud:2023.0.0

引入maven配置

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-authorization-server</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

AuthorizationServerConfig认证中心配置类

package com.auth.config;

import com.jilianyun.exception.ServiceException;
import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
import com.nimbusds.jose.jwk.source.JWKSource;
import com.nimbusds.jose.proc.SecurityContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.core.AuthorizationGrantType;
import org.springframework.security.oauth2.core.ClientAuthenticationMethod;
import org.springframework.security.oauth2.jwt.JwtDecoder;
import org.springframework.security.oauth2.server.authorization.client.JdbcRegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClient;
import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configuration.OAuth2AuthorizationServerConfiguration;
import org.springframework.security.oauth2.server.authorization.config.annotation.web.configurers.OAuth2AuthorizationServerConfigurer;
import org.springframework.security.oauth2.server.authorization.settings.AuthorizationServerSettings;
import org.springframework.security.oauth2.server.authorization.settings.ClientSettings;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.MediaTypeRequestMatcher;

import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.UUID;

/**
 * <p>认证中心配置类</p>
 *
 * @author By: chengxuyuanshitang
 * Ceate Time 2024-05-07 11:42
 */

@Slf4j
@EnableWebSecurity
@Configuration(proxyBeanMethods = false)
public class AuthorizationServerConfig {

    /**
     * Security过滤器链,用于协议端点
     *
     * @param http HttpSecurity
     * @return SecurityFilterChain
     */
    @Bean
    public SecurityFilterChain authorizationServerSecurityFilterChain (HttpSecurity http) throws Exception {
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity (http);
        http.getConfigurer (OAuth2AuthorizationServerConfigurer.class)
                //启用OpenID Connect 1.0
                .oidc (Customizer.withDefaults ());
        http
                // 未从授权端点进行身份验证时重定向到登录页面
                .exceptionHandling ((exceptions) -> exceptions
                        .defaultAuthenticationEntryPointFor (
                                new LoginUrlAuthenticationEntryPoint ("/login"),
                                new MediaTypeRequestMatcher (MediaType.TEXT_HTML)
                        )
                )
                //接受用户信息和/或客户端注册的访问令牌
                .oauth2ResourceServer ((resourceServer) -> resourceServer
                        .jwt (Customizer.withDefaults ()));

        return http.build ();
    }

    /**
     * 用于认证的Spring Security过滤器链。
     *
     * @param http HttpSecurity
     * @return SecurityFilterChain
     */
    @Bean
    public SecurityFilterChain defaultSecurityFilterChain (HttpSecurity http) throws Exception {
        http.authorizeHttpRequests ((authorize) -> authorize
                        .requestMatchers (new AntPathRequestMatcher ("/actuator/**"),
                                new AntPathRequestMatcher ("/oauth2/**"),
                                new AntPathRequestMatcher ("/**/*.json"),
                                new AntPathRequestMatcher ("/**/*.css"),
                                new AntPathRequestMatcher ("/**/*.html")).permitAll ()
                        .anyRequest ().authenticated ()
                )
                .formLogin (Customizer.withDefaults ());
        return http.build ();
    }

    /**
     * 配置密码解析器,使用BCrypt的方式对密码进行加密和验证
     *
     * @return BCryptPasswordEncoder
     */
    @Bean
    public PasswordEncoder passwordEncoder () {
        return new BCryptPasswordEncoder ();
    }

    @Bean
    public UserDetailsService userDetailsService () {
        UserDetails userDetails = User.withUsername ("chengxuyuanshitang")
                .password (passwordEncoder ().encode ("chengxuyuanshitang"))
                .roles ("admin")
                .build ();
        return new InMemoryUserDetailsManager (userDetails);
    }

    /**
     * RegisteredClientRepository 的一个实例,用于管理客户端
     *
     * @param jdbcTemplate    jdbcTemplate
     * @param passwordEncoder passwordEncoder
     * @return RegisteredClientRepository
     */
    @Bean
    public RegisteredClientRepository registeredClientRepository (JdbcTemplate jdbcTemplate, PasswordEncoder passwordEncoder) {
        RegisteredClient registeredClient = RegisteredClient.withId (UUID.randomUUID ().toString ())
                .clientId ("oauth2-client")
                .clientSecret (passwordEncoder.encode ("123456"))
                // 客户端认证基于请求头
                .clientAuthenticationMethod (ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
                // 配置授权的支持方式
                .authorizationGrantType (AuthorizationGrantType.AUTHORIZATION_CODE)
                .authorizationGrantType (AuthorizationGrantType.REFRESH_TOKEN)
                .authorizationGrantType (AuthorizationGrantType.CLIENT_CREDENTIALS)
                .redirectUri ("https://www.baidu.com")
                .scope ("user")
                .scope ("admin")
                // 客户端设置,设置用户需要确认授权
                .clientSettings (ClientSettings.builder ().requireAuthorizationConsent (true).build ())
                .build ();
        JdbcRegisteredClientRepository registeredClientRepository = new JdbcRegisteredClientRepository (jdbcTemplate);
        RegisteredClient repositoryByClientId = registeredClientRepository.findByClientId (registeredClient.getClientId ());
        if (repositoryByClientId == null) {
            registeredClientRepository.save (registeredClient);
        }
        return registeredClientRepository;
    }


    /**
     * 用于签署访问令牌
     *
     * @return JWKSource
     */
    @Bean
    public JWKSource<SecurityContext> jwkSource () {
        KeyPair keyPair = generateRsaKey ();
        RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic ();
        RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate ();
        RSAKey rsaKey = new RSAKey.Builder (publicKey)
                .privateKey (privateKey)
                .keyID (UUID.randomUUID ().toString ())
                .build ();
        JWKSet jwkSet = new JWKSet (rsaKey);
        return new ImmutableJWKSet<> (jwkSet);
    }

    /**
     * 创建RsaKey
     *
     * @return KeyPair
     */
    private static KeyPair generateRsaKey () {
        KeyPair keyPair;
        try {
            KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance ("RSA");
            keyPairGenerator.initialize (2048);
            keyPair = keyPairGenerator.generateKeyPair ();
        } catch (Exception e) {
            log.error ("generateRsaKey Exception", e);
            throw new ServiceException ("generateRsaKey Exception");
        }
        return keyPair;
    }

    /**
     * 解码签名访问令牌
     *
     * @param jwkSource jwkSource
     * @return JwtDecoder
     */
    @Bean
    public JwtDecoder jwtDecoder (JWKSource<SecurityContext> jwkSource) {
        return OAuth2AuthorizationServerConfiguration.jwtDecoder (jwkSource);
    }

    @Bean
    public AuthorizationServerSettings authorizationServerSettings () {
        return AuthorizationServerSettings.builder ().build ();
    }

}

详细介绍

SecurityFilterChain authorizationServerSecurityFilterChain (HttpSecurity http) 

Spring Security的过滤器链,用于协议端点

SecurityFilterChain defaultSecurityFilterChain (HttpSecurity http)
 Security的过滤器链,用于Security的身份认证

PasswordEncoder passwordEncoder ()
 配置密码解析器,使用BCrypt的方式对密码进行加密和验证

UserDetailsService userDetailsService ()

用于进行用户身份验证

RegisteredClientRepository registeredClientRepository (JdbcTemplate jdbcTemplate, PasswordEncoder passwordEncoder)
用于管理客户端

JWKSource<SecurityContext> jwkSource () 
用于签署访问令牌

 KeyPair generateRsaKey ()
创建RsaKey

 JwtDecoder jwtDecoder (JWKSource<SecurityContext> jwkSource)
解码签名访问令牌

 AuthorizationServerSettings authorizationServerSettings () 

配置Spring Authorization Server的AuthorizationServerSettings实例

初始化自带的数据表

自带的表在spring-security-oauth2-authorization-server-1.2.0.jar 中 下面是对应的截图

对应的SQL

-- 已注册的客户端信息表
CREATE TABLE oauth2_registered_client
(
    id                            varchar(100)                            NOT NULL,
    client_id                     varchar(100)                            NOT NULL,
    client_id_issued_at           timestamp     DEFAULT CURRENT_TIMESTAMP NOT NULL,
    client_secret                 varchar(200)  DEFAULT NULL,
    client_secret_expires_at      timestamp     DEFAULT NULL,
    client_name                   varchar(200)                            NOT NULL,
    client_authentication_methods varchar(1000)                           NOT NULL,
    authorization_grant_types     varchar(1000)                           NOT NULL,
    redirect_uris                 varchar(1000) DEFAULT NULL,
    post_logout_redirect_uris     varchar(1000) DEFAULT NULL,
    scopes                        varchar(1000)                           NOT NULL,
    client_settings               varchar(2000)                           NOT NULL,
    token_settings                varchar(2000)                           NOT NULL,
    PRIMARY KEY (id)
);

-- 认证授权表
CREATE TABLE oauth2_authorization_consent
(
    registered_client_id varchar(100)  NOT NULL,
    principal_name       varchar(200)  NOT NULL,
    authorities          varchar(1000) NOT NULL,
    PRIMARY KEY (registered_client_id, principal_name)
);
/*
IMPORTANT:
    If using PostgreSQL, update ALL columns defined with 'blob' to 'text',
    as PostgreSQL does not support the 'blob' data type.
*/
-- 认证信息表
CREATE TABLE oauth2_authorization
(
    id                            varchar(100) NOT NULL,
    registered_client_id          varchar(100) NOT NULL,
    principal_name                varchar(200) NOT NULL,
    authorization_grant_type      varchar(100) NOT NULL,
    authorized_scopes             varchar(1000) DEFAULT NULL,
    attributes                    blob          DEFAULT NULL,
    state                         varchar(500)  DEFAULT NULL,
    authorization_code_value      blob          DEFAULT NULL,
    authorization_code_issued_at  timestamp     DEFAULT NULL,
    authorization_code_expires_at timestamp     DEFAULT NULL,
    authorization_code_metadata   blob          DEFAULT NULL,
    access_token_value            blob          DEFAULT NULL,
    access_token_issued_at        timestamp     DEFAULT NULL,
    access_token_expires_at       timestamp     DEFAULT NULL,
    access_token_metadata         blob          DEFAULT NULL,
    access_token_type             varchar(100)  DEFAULT NULL,
    access_token_scopes           varchar(1000) DEFAULT NULL,
    oidc_id_token_value           blob          DEFAULT NULL,
    oidc_id_token_issued_at       timestamp     DEFAULT NULL,
    oidc_id_token_expires_at      timestamp     DEFAULT NULL,
    oidc_id_token_metadata        blob          DEFAULT NULL,
    refresh_token_value           blob          DEFAULT NULL,
    refresh_token_issued_at       timestamp     DEFAULT NULL,
    refresh_token_expires_at      timestamp     DEFAULT NULL,
    refresh_token_metadata        blob          DEFAULT NULL,
    user_code_value               blob          DEFAULT NULL,
    user_code_issued_at           timestamp     DEFAULT NULL,
    user_code_expires_at          timestamp     DEFAULT NULL,
    user_code_metadata            blob          DEFAULT NULL,
    device_code_value             blob          DEFAULT NULL,
    device_code_issued_at         timestamp     DEFAULT NULL,
    device_code_expires_at        timestamp     DEFAULT NULL,
    device_code_metadata          blob          DEFAULT NULL,
    PRIMARY KEY (id)
);

application.yml中数据库配置

spring:
  profiles:
    active: dev

  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.0.1:3306/auth?characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true
    username: auth
    password: 12345

启动AuthServerApplication

启动完成后查看数据库的oauth2_registered_client表中有一条数据;

查看授权服务配置

地址:http://127.0.0.1:8801/.well-known/openid-configuration

访问/oauth2/authorize前往登录页面

地址:ip/端口/oauth2/authorize?client_id=app-client&response_type=code&scope=user&redirect_uri=https://www.baidu.com

实例:

http://127.0.0.1:8801/oauth2/authorize?client_id=app-client&response_type=code&scope=user&redirect_uri=https://www.baidu.com

浏览器跳转到:http://127.0.0.1:8801/login

输入上面配置的密码和账号。我这里都是:chengxuyuanshitang 点击提交。跳转

跳转到

网址栏的地址:https://www.baidu.com/?code=S73PUvl26OSxBc-yBbRRPJMTzcvE2x-VFZGXFPjpvOXHrecbY3Thsj6aOxPdN31H4a6GUgujSc1D4lj9D1ApIUAfZi55YJLqiRLpCivb-Is_4h3grILgR8H8M9UWyhJt

code的值就是=后面的

code=S73PUvl26OSxBc-yBbRRPJMTzcvE2x-VFZGXFPjpvOXHrecbY3Thsj6aOxPdN31H4a6GUgujSc1D4lj9D1ApIUAfZi55YJLqiRLpCivb-Is_4h3grILgR8H8M9UWyhJt

获取token

请求地址:http://127.0.0.1:8801/oauth2/token?grant_type=authorization_code&redirect_uri=https://www.baidu.com&code=S73PUvl26OSxBc-yBbRRPJMTzcvE2x-VFZGXFPjpvOXHrecbY3Thsj6aOxPdN31H4a6GUgujSc1D4lj9D1ApIUAfZi55YJLqiRLpCivb-Is_4h3grILgR8H8M9UWyhJt

用postman请求

添加header参数

header中的 Authorization参数:因为我们用的客户端认证方式 为  client_secret_basic ,这个需要传参,还有一些其他的认证方式,
client_secret_basic: 将 clientId 和 clientSecret 通过 : 号拼接,并使用 Base64 进行编码得到一串字符,再在前面加个 注意有个 Basic   前缀(Basic后有一个空格), 即得到上面参数中的 Basic 。

我的是:app-client:123456

Base64 进行编码:YXBwLWNsaWVudDoxMjM0NTY=

返回:

{
    "access_token": "eyJraWQiOiI2ZTJmYTA5ZS0zMmYzLTQ0MmQtOTM4Zi0yMzJjNDViYTM1YmMiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJjaGVuZ3h1eXVhbnNoaXRhbmciLCJhdWQiOiJhcHAtY2xpZW50IiwibmJmIjoxNzE1MDcxOTczLCJzY29wZSI6WyJ1c2VyIl0sImlzcyI6Imh0dHA6Ly8xMjcuMC4wLjE6ODgwMSIsImV4cCI6MTcxNTA3MjI3MywiaWF0IjoxNzE1MDcxOTczLCJqdGkiOiI0MWI4ZGZmZS03MTI2LTQ4NWYtODRmYy00Yjk4OGE0N2ZlMzUifQ.VxP2mLHt-eyXHZOI36yhVlwC2UQEdAtaRBKTWwJn1bFup0ZjGbZfgxENUb1c03yjcki2H-gCW4Jgef11BMNtjyWSnwMHVWLB9fcT3rRKDQWwoWqBYAcULS8oC5n8qTZwffDSrnjepMEbw4CblL3oH7T9nLProTXQP326RIE1RczsUYkteUCkyIvKTSs3ezOjIVR1GyCs_Cl1A_3OllmkGnSO2q-NKkwasrQjMuuPTY3nhDyDGiefYlfDEcmzz1Yk_FE42P7PEeyqmZwAj7vUnE4brQuNqipaMsS7INe_wTE1kJv-arfbnUo_zQdipHxIhsDgoLaPlSSecQ31QgwEHA",
    "refresh_token": "TqJyWbLWe5Yww6dOV89zDbO0C3YEBA__0TJU_GclmQTAH92SSQ2OvdMChIdln97u1WsA7G7n3BqzNZBjPRU7xmkRooa5ifsMBJ-d3C4kPmuPQI-Bmbq20pck-QEk0Dqt",
    "scope": "user",
    "token_type": "Bearer",
    "expires_in": 300
}

访问接口/userinfo

请求地址:http://127.0.0.1:8801/userinfo

添加header参数:Authorization: Bearer +空格+ ${access_token}




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

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

相关文章

ComfyUI的图像调色处理

可知这个节点可以让一张图片根据另外一张图片进行调色&#xff0c;我上传其他图片再来看看效果&#xff0c;如下 【保姆级教程】ComfyUI中常见的十几种多图处理节点&#xff0c;包括图像填充、图像拼接、图像混合等等 工作流链接 更多好玩且实用AIGC工作流和节点 星球号&#…

java中的变量、数据类型、人机交互

变量 变量要素 1、类型&#xff1b;每一个变量都需要定义类型&#xff08;强类型&#xff09;其它语言有弱类型&#xff08;js&#xff09; 2、变量名&#xff1b; 3、存储的值&#xff1b; 声明方式&#xff1a; 数据类型 变量名 变量值&#xff1b; public static vo…

最好用的长线预警指标Lon 一键导入QMT

长线指标&#xff08;LON)是一种加权的量价指标&#xff0c;其作用在于测量近期资金动向。属于中长线趋势类指标。 LON长线指标表现形式类似平滑异同移动平均线&#xff08;MACD&#xff09;和三重指数平滑移动平均指标&#xff08;TRIX&#xff09;等趋势型指标&#xff0c;但…

RTSP/Onvif安防监控系统EasyNVR级联视频上云系统EasyNVS报错“Login error”的原因排查与解决

EasyNVR安防视频云平台是旭帆科技TSINGSEE青犀旗下支持RTSP/Onvif协议接入的安防监控流媒体视频云平台。平台具备视频实时监控直播、云端录像、云存储、录像检索与回看、告警等视频能力&#xff0c;能对接入的视频流进行处理与多端分发&#xff0c;包括RTSP、RTMP、HTTP-FLV、W…

Day_2

1. 菜品管理 新增菜品 接口设计 1. 根据类型查询分类&#xff08;分类管理已完成&#xff09; 查看接口文档即可 2. 文件上传 创建Bucket 采用的是阿里云的OSS对象存储服务 新增AccessKey 3. 菜品的新增逻辑 代码开发 1. 文件上传接口开发 为了提高代码的解耦性&#…

虚拟机文件夹共享操作(本地访问)

新建一个文件夹 右击文件夹点击属性 找到共享 点击共享 选择本地用户共享就可以了 本地winr 输入我们图片中的格式&#xff08;IP前加 “\\” &#xff09; 会弹一个窗口&#xff0c;输入虚拟机的入户名和密码就可以共享了&#xff08;一般默认用户名都是administrator&am…

C# winform 连接mysql数据库(navicat)

1.解决方案资源管理器->右键->管理NuGet程序包->搜索&#xff0c; 安装Mysql.Data 2.解决方案资源管理器->右键->添加->引用->浏览-> C:\Program Files (x86)\MySQL\MySQL Installer for Windows ->选择->MySql.Data.dll 3.解决方案资源管理器…

揭秘 IEEE/ACM Trans/CCF/SCI,谁才是科研界的王者?

会议之眼 快讯 在学术探索的浩瀚星海中&#xff0c;每一篇论文都像是一颗璀璨的星辰&#xff0c;而那些被顶级期刊或会议收录的论文&#xff0c;则无疑是最耀眼的几颗。 在众多评价标准中&#xff0c;IEEE/ACM Transactions、CCF推荐期刊和会议、SCI分区期刊&#xff0c;它们…

共价连接dPEG可作为PC和ADMET性能改良剂

共价连接 dPEG 可作为 PC 和 ADMET 性能改良剂 抗体片段&#xff08;Antibody fragments&#xff09; 工程抗体片段的 PEG 化通常使用较大的多分散 PEG&#xff08;Cimzia、Dapirolizumab Pegol 等&#xff09;来延长小分子量蛋白的半衰期。最近&#xff0c;Genentech公司的研究…

AI去衣技术在动画制作中的应用

随着科技的发展&#xff0c;人工智能&#xff08;AI&#xff09;已经在各个领域中发挥了重要作用&#xff0c;其中包括动画制作。在动画制作中&#xff0c;AI去衣技术是一个重要的工具&#xff0c;它可以帮助动画师们更加高效地完成工作。 AI去衣技术是一种基于人工智能的图像…

CUDA-共享内存法实现矩阵乘法(比常规方案提速一倍)

作者&#xff1a;翟天保Steven 版权声明&#xff1a;著作权归作者所有&#xff0c;商业转载请联系作者获得授权&#xff0c;非商业转载请注明出处 共享内存是什么&#xff1f; 共享内存是在多个处理单元之间共享数据的一种内存区域。在计算机体系结构中&#xff0c;共享内存通…

dPEG与传统PEG以及其他烷基交联剂产品的优势

作为Linker的dPEG 研究证明&#xff0c;通过交联剂将不同物质结合在一起的能力已被证明是诊断和药物输送系统中非常有用的一项技术。由多分散PEG组成的交联剂已被用于制备多种多聚物以及将靶向配体偶联到纳米颗粒上。这通常用于需要非常大的尺寸以提供良好的DMPK性能并且受多分…

GPU术语

SP(Streaming Processor)流处理器 流处理器是GPU最基本的处理单元&#xff0c;在fermi架构开始被叫做CUDA core。 SM(Streaming MultiProcessor) 一个SM由多个CUDA core组成。SM还包括特殊运算单元(SFU)&#xff0c;共享内存(shared memory)&#xff0c;寄存器文件(Register …

抖音短视频矩阵系统技术源头/源代码开发部署/SaaS贴牌/源码api代开发

抖音短视频矩阵系统技术源头/源代码开发部署/SaaS贴牌/源码官方平台api授权代开发 一、短视频矩阵系统源码开发步骤 短视频矩阵系统的源头开发步骤通常包括以下几个关键阶段&#xff1a; 1.需求分析&#xff1a;明确系统的目标用户、功能需求、性能要求等。 2.系统设计&…

加密技术在保护企业数据中的应用

加密技术是企业数据保护的核心&#xff0c;对于维护信息安全至关重要。透明加密技术使文件加密后不改变用户对文件的使用习惯&#xff0c;内部文件打开自动解密&#xff0c;存储自动加密&#xff0c;一旦离开使用环境&#xff0c;加密文件将无法正常读取&#xff0c;从而保护文…

【算法】唯一分解定理及最lcm和gcd关系 宝石组合

前言 今天在做一道宝石组合的题目时了解到了这个定理&#xff0c;还是蛮有意思的。 思想 唯一分解定理&#xff1a; 对于任何正整数n&#xff0c;有 n p 1 a 1 p 2 a 2 . . . p k a k n p_1^{a1} \times p_2^{a2} \times ... \times p_k^{ak} np1a1​p2a2​...pkak​ …

【最大公约数 并集查找 调和级数】1998. 数组的最大公因数排序

本文涉及知识点 最大公约数 并集查找 调和级数 LeetCode1998. 数组的最大公因数排序 给你一个整数数组 nums &#xff0c;你可以在 nums 上执行下述操作 任意次 &#xff1a; 如果 gcd(nums[i], nums[j]) > 1 &#xff0c;交换 nums[i] 和 nums[j] 的位置。其中 gcd(nums…

【JVM】类加载机制及双亲委派模型

目录 一、类加载过程 1. 加载 2. 连接 a. 验证 b. 准备 c. 解析 3. 初始化 二、双亲委派模型 类加载器 双亲委派模型的工作过程 双亲委派模型的优点 一、类加载过程 JVM的类加载机制是JVM在运行时&#xff0c;将 .class 文件加载到内存中并转换为Java类的过程。它…

Android 桌面小组件 AppWidgetProvider

Android 桌面小组件 AppWidgetProvider 简介 小组件就是可以添加到手机桌面的窗口。点击窗口可以进入应用或者进入应用的某一个页面。 widget 组件 如需创建 widget&#xff0c;您需要以下基本组件&#xff1a; AppWidgetProviderInfo 对象 描述 widget 的元数据&#xff0…

Linux基础配置(镜像挂载,FQDN)

CentOS基础配置&#xff1a; 以下是appsrv的基础配置脚本&#xff0c;CentOS系统只需要把appsrv改成需要的主机名即可&#xff08;因为Linux基础配置都差不多&#xff0c;写脚本是最省时间的做法&#xff0c;IP地址的配置一般用nmtui图形化界面工具&#xff09; #!/bin/bash …