当前位置: 首页 > article >正文

基于Spring Security 6的OAuth2 系列之十五 - 高级特性--客户端认证方式

之所以想写这一系列,是因为之前工作过程中使用Spring Security OAuth2搭建了网关和授权服务器,但当时基于spring-boot 2.3.x,其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0,结果一看Spring Security也升级为6.3.0。无论是Spring Security的风格和以及OAuth2都做了较大改动,里面甚至将授权服务器模块都移除了,导致在配置同样功能时,花费了些时间研究新版本的底层原理,这里将一些学习经验分享给大家。

注意由于框架不同版本改造会有些使用的不同,因此本次系列中使用基本框架是 spring-boo-3.3.0(默认引入的Spring Security是6.3.0),JDK版本使用的是19,本系列OAuth2的代码采用Spring Security6.3.0框架,所有代码都在oauth2-study项目上:https://github.com/forever1986/oauth2-study.git

目录

  • 1 客户端认证原理
  • 2 基础代码
  • 3 不同的认证
    • 3.1 基于client_secret_basic认证
      • 3.1.1 原理
      • 3.1.2 代码实现
    • 3.2 基于client_secret_post认证
      • 3.2.1 原理
      • 3.2.2 代码实现
    • 3.3 基于client_secret_jwt和private_key_jwt认证
      • 3.3.1 原理
      • 3.3.2 代码实现
    • 3.4 基于none认证
    • 3.5 基于tls_client_auth和self_signed_tls_client_auth认证

从本章开始,就会讲解一些高级的特性,这些非必须的,看你项目是否有需要。这一章讲一下客户端认证的方式。我们来看一下lesson02子模块的yaml文件一个配置,client-authentication-methods配置了client_secret_basic,如下图:
在这里插入图片描述

这是配置的客户端认证的方式,在我们执行获取token的时候,需要在Authorization 配置,这就是client_secret_basic的认证模式,如下图:
在这里插入图片描述

为了传输的安全性,OAuth2提供了多种不同的客户端认证方式,包括client_secret_basic、client_secret_post、client_secret_jwt、private_key_jwt、none、tls_client_auth和self_signed_tls_client_auth。下面我们先讲一下原理,再一一讲解这些不同的认证方式:

1 客户端认证原理

在《系列之八 - 授权服务器–Spring Authrization Server的基本原理》中,我们知道客户端的认证通过OAuth2ClientAuthenticationFilter过滤器来,我们下面看看源代码:

在这里插入图片描述

从上图中,我们看到有三部分比较重要:

  • 1)匹配请求认证的URL:主要拦截/oauth2/token、/oauth2/introspect、/oauth2/revoke
  • 2)使用authenticationConverter从请求中获取客户端信息:主要有client_secret_basic、client_secret_post、client_secret_jwt、private_key_jwt、none、tls_client_auth和self_signed_tls_client_auth不同认证方式
  • 3)对客户端进行认证:对应不同的认证方式,采用不同的AuthenticationProvider来做认证操作

其中第二步中,authenticationConverter是一个代理的Converter,由以下图不同转换器组成,可以匹配OAuth2规定的不同认证方式,这就是不同认证方式获取的方式,下面我们就开始对不同转换器进行解读和演示。

在这里插入图片描述

其中第三步,AuthenticationProvider是一个代理,由以下图不同的AuthenticationProvider组成:

在这里插入图片描述

这样通过不同AuthenticationProvider和authenticationConverter就可以匹配OAuth2规定的不同认证方式,因此我们知道有3个关键的点决定客户端认证:

  • client-authentication-methods:其配置用于支持哪种客户端认证方式
  • authenticationConverter:就是为了解析参数不同客户端认证传入的参数
  • AuthenticationProvider:不同客户端的认证

以下是不同认证方式的汇总:

认证方式说明
client_secret_basic、client_secret_post采用客户端名称+密码的方式,两种方式是传递方式不同,一种通过请求头(Authorization),一种是通过Body参数
client_secret_jwt、private_key_jwt采用jwt格式的token
none结合PKCE的认证
tls_client_auth、self_signed_tls_client_auth结合证书的认证

下面我们开始验证不同客户端认证:

2 基础代码

本次演示代码以lesson09子模块为授权服务器,使用Postman进行访问,注意:这里为了方便使用客户端模式,而非授权码模式,后面各种认证方式都是基于lesson09子模块进行改进。

1)新建lesson09子模块,pom引入如下:

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

2)配置yaml文件,主要配置端口和security的用户密码

server:port: 9000logging:level:org.springframework.security: tracespring:security:# 使用security配置授权服务器的登录用户和密码user:name: userpassword: 1234

3)在config包下,配置SecurityConfig

@Configuration
public class SecurityConfig {// 自定义授权服务器的Filter链@Bean@Order(Ordered.HIGHEST_PRECEDENCE)SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)// oidc配置.oidc(withDefaults());// 异常处理http.exceptionHandling((exceptions) -> exceptions.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")));return http.build();}// 自定义Spring Security的链路。如果自定义授权服务器的Filter链,则原先自动化配置将会失效,因此也要配置Spring Security@Bean@Order(SecurityProperties.BASIC_AUTH_ORDER)SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http) throws Exception {http.authorizeHttpRequests((authorize) -> authorize.requestMatchers("/jwt").permitAll().anyRequest().authenticated()).formLogin(withDefaults());return http.build();}@Beanpublic RegisteredClientRepository registeredClientRepository() {RegisteredClient registeredClient3 = RegisteredClient.withId(UUID.randomUUID().toString())// 客户端id.clientId("oidc-client")// 客户端密码.clientSecret("{noop}secret")// 客户端认证方式.clientAuthenticationMethods(methods ->{methods.add(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);})// 这里为了方便采用客户端模式,而非授权码模式.authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS)// 回调地址.redirectUri("http://localhost:8080/login/oauth2/code/oidc-client").postLogoutRedirectUri("http://localhost:8080/")// 授权范围.scopes(scopes->{scopes.add(OidcScopes.OPENID);scopes.add(OidcScopes.PROFILE);}).build();return new InMemoryRegisteredClientRepository(registeredClient3 );}}

4)配置启动类Oauth2Lesson09ServerApplication,并启动项目

3 不同的认证

3.1 基于client_secret_basic认证

将 clientId 和 clientSecret 拼接并编码放到请求头(Authorization)去请求授权服务器,如果使用postman工具,则会自动完成这过程(clientId 和 clientSecret 通过 ‘:’ 号拼接,并使用 Base64 进行编码得到一个字符串)

3.1.1 原理

参数转换:ClientSecretBasicAuthenticationConverter
认证处理:ClientSecretAuthenticationProvider

client_secret_basic的认证方式是基于ClientSecretBasicAuthenticationConverter转换器来获取请求传过来的客户端信息,如下图:

在这里插入图片描述

3.1.2 代码实现

1)客户端配置的client-authentication-methods中增加client_secret_basic认证方式

在这里插入图片描述

2)在请求token时,在header的Authorization字段配置客户端即可,如下图:

参数:Authorization字段,设置为Basic Auth,并填写客户端信息的Username和Password
在这里插入图片描述

在这里插入图片描述

3.2 基于client_secret_post认证

该认证方法和client_secret_basic基本上一样,采用同一个ClientSecretAuthenticationProvider进行认证,唯一不同的是将 clientId 和 clientSecret 放到Body中参数去请求授权服务器

3.2.1 原理

参数转换:ClientSecretPostAuthenticationConverter
认证处理:ClientSecretAuthenticationProvider

client_secret_post的认证方式是基于ClientSecretPostAuthenticationConverter转换器来获取请求传过来的客户端信息,如下图:

在这里插入图片描述

3.2.2 代码实现

1)客户端配置的client-authentication-methods中增加client_secret_post认证方式

在这里插入图片描述

2)在请求token时,在参数配置客户端信息即可,如下图:

参数:Body字段,设置客户端信息的client_id和client_secret

在这里插入图片描述

3.3 基于client_secret_jwt和private_key_jwt认证

这两个一起讲其实是因为这2个实现方式一模一样,就是将客户端信息通过加密生成jwt的字符串,将jwt放入body参数client_assertion中发给授权服务器,授权服务器通过解析这个jwt字符串进行解密。唯一不同的是:

  • client_secret_jwt是对称加密,通过clientSecret进行加密
  • private_key_jwt是非对称加密,就是客户端发布自己的密钥,将公钥给授权服务器。

3.3.1 原理

参数转换:JwtClientAssertionAuthenticationConverter
认证处理:JwtClientAssertionAuthenticationProvider

client_secret_jwt的认证方式是基于JwtClientAssertionAuthenticationConverter转换器来获取请求传过来的客户端信息,如下图:

在这里插入图片描述

从源代码可以看到,是基于请求参数通过JWT方式来传递客户端信息,因此我们只需要先在client-authentication-methods配置client_secret_jwt,然后在请求token时,在参数配置client_assertion_type、client_assertion(JWT方式加密的客户端信息)以及client_id。我们还需要看一下JwtClientAssertionAuthenticationProvider如何解密JWT的客户端信息,如下图:

在这里插入图片描述

从上图我们知道,是通过JwtClientAssertionDecoderFactory,而JwtClientAssertionDecoderFactory是通过客户端配置的ClientSettings来配置JWT的加密方式进行解密,会判断对称或者非对称加密,如下图:

在这里插入图片描述

3.3.2 代码实现

我们这里就演示一个非对称加密方式private_key_jwt,以SignatureAlgorithm.RS256加密方式,密钥采用lesson08子模块的demo.jks。关于对称加密采用MacAlgorithm.HS256即可。
注意:从源代码看,其实你无论配置private_key_jwt或者client_secret_jwt都无所谓,对不对称关键在于ClientSettings的配置,如果配置SignatureAlgorithm.RS256就是非对称加密,配置MacAlgorithm.HS256就是对称加密

1)将lesson08子模块的resources目录下的demo.jks拷贝到lesson09子模块的resources目录下

2)在config包下SecurityConfig,进行客户端配置的client-authentication-methods中增加private_key_jwt认证方式以及密钥的配置

在这里插入图片描述

3)在config包下SecurityConfig,配置/jwt可以无权限访问

在这里插入图片描述

4)在controller包下,现在JwtController,包括发布jwt接口以及加载本地demo.jks

@RestController
public class JwtController {/*** 返回公钥* @return*/@GetMapping("/jwt")public String jwt(){JWKSet jwkSet;try {JWKSelector jwkSelector = new JWKSelector(new JWKMatcher.Builder().build());jwkSet = new JWKSet(jwkSource().get(jwkSelector, null));}catch (Exception ex) {throw new IllegalStateException("Failed to select the JWK(s) -> " + ex.getMessage(), ex);}return jwkSet.toString();}private static String UUID_STR = "b07b297d-a1e3-4a86-a8fe-632ebd61545b";// Jwt加密private static JwtEncoder jwtEncoder() {NimbusJwtEncoder jwtEncoder = new NimbusJwtEncoder(jwkSource());return jwtEncoder;}// Jwt解密private static JwtDecoder jwtDecoder() {NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withPublicKey((RSAPublicKey)generateRsaKey().getPublic()).build();return jwtDecoder;}// 获取JWKSourceprivate static 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_STR).build();JWKSet jwkSet = new JWKSet(rsaKey);return new ImmutableJWKSet<>(jwkSet);}// 获取本地的demo.jksprivate static KeyPair generateRsaKey() {KeyStoreKeyFactory factory = new KeyStoreKeyFactory(new ClassPathResource("demo.jks"), "linmoo".toCharArray());KeyPair keyPair = factory.getKeyPair("demo", "linmoo".toCharArray());return keyPair;}public static void main(String[] args) {String clientId = "oidc-client";// 至少以下四项信息JwtClaimsSet.Builder claimsBuilder = JwtClaimsSet.builder();claimsBuilder// 发布者.issuer(clientId)// 对象.subject(clientId)// 授权服务器地址.audience(Collections.singletonList("http://localhost:9000"))// 发布时间.issuedAt((new Timestamp(System.currentTimeMillis())).toInstant())// 过期时间.expiresAt((new Date(System.currentTimeMillis() + 1000 * 60 * 10)).toInstant()).id(UUID.randomUUID().toString());JwsHeader.Builder jwsHeaderBuilder = JwsHeader.with(SignatureAlgorithm.RS256);JwsHeader jwsHeader = jwsHeaderBuilder.build();JwtClaimsSet claims = claimsBuilder.build();Jwt jwt = jwtEncoder().encode(JwtEncoderParameters.from(jwsHeader, claims));String token = jwt.getTokenValue();System.out.println(token);Jwt newjwt =jwtDecoder().decode(token);System.out.println(newjwt);}
}

5)运行JwtController的main函数,生成一个token,将token放到postman的client_assertion参数

在这里插入图片描述

6)在请求token时,在参数配置client_id、client_assertion_type和client_assertion即可,如下图:

参数:Body字段,设置客户端信息的client_id、client_assertion_type和client_assertion

在这里插入图片描述

3.4 基于none认证

none方式一开始看还以为是不需要认证,其实不是,我们知道客户端一般需要保存Secrets,但是有时候客户端可能只是一个前端应用,其Secrets有可能暴露在代码中,OAuth2为了防止这种情况,采用了PKCE方式。而这个PKCE方式就是采用none认证方式。这一部分我们下一章再讲,请耐心等待《系列之十六 - 高级特性–PKCE》

3.5 基于tls_client_auth和self_signed_tls_client_auth认证

这部分涉及到https以及证书认证的基础知识,相对会复杂一些,因此我们单独开两章来讲,放在后续讲,请耐心等待《系列之二十二 - 高级特性–TLS客户端认证方法之一》和《系列之二十三 - 高级特性–TLS客户端认证方法之二》中来讲

结语:本章讲了授权服务器对客户端认证的几种不同方式及其原理,并使用代码演示一遍。下一章我们继续讲述这一部分内容,也就是none方式的客户端认证,但是会有一个新的扩展-PKCE扩展,这是OAuth2.1版本才有的,说明Spring Security 6 还是走在比较前面。

相关文章:

基于Spring Security 6的OAuth2 系列之十五 - 高级特性--客户端认证方式

之所以想写这一系列&#xff0c;是因为之前工作过程中使用Spring Security OAuth2搭建了网关和授权服务器&#xff0c;但当时基于spring-boot 2.3.x&#xff0c;其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0&#xff0c;结果一看Spring Security也升级…...

bug-ant下拉框解决下拉框跟随表单容器(指定下拉框挂载容器):getPopupContainer=“p=>p.parentNode“

1.前言 getPopupContainer是Ant Design Vue&#xff08;简称Antd&#xff09;的<a-select>组件的一个属性&#xff0c;用于指定下拉框的挂载容器。默认情况下&#xff0c;下拉框会挂载到body元素上&#xff0c;但有时你可能需要将下拉框挂载到其他元素上&#xff0c;例如…...

驱动开发系列35 - Linux Graphics GEM Buffer Object 介绍

一:概述 在 Linux 内核中,DRM(Direct Rendering Manager)模块 是用于管理显示硬件和图形渲染的核心框架。它负责协调用户空间应用程序(例如 X Server、Wayland Compositors、Mesa 等)和 GPU 硬件之间的通信,是 Linux 图形子系统的重要组成部分。 GEM (Graphics Executio…...

网络安全检测思路

对于主机的安全检测&#xff0c;我们通常直接采用nmap或者类似软件进行扫描&#xff0c;然后针对主机操作系统及其 开放端口判断主机的安全程度&#xff0c;这当然是一种方法&#xff0c;但这种方法往往失之粗糙&#xff0c;我仔细考虑了一下&#xff0c;觉 得按下面的流程进行…...

vue error Expected indentation of 2 spaces but found 4 indent

问题的原因在于eslint的风格样式缩进检测&#xff0c;eslint给出的规则是2个缩进&#xff0c;但我们通常是4个缩进&#xff0c;这就造成了报错。 关闭eslint的缩进不同报错&#xff1a;.eslintrc.js indent:off, 全部配置&#xff1a; module.exports {root: true,parserOpt…...

回环地址127.0.0.1跟自身IP有什么区别?

区别比较显著&#xff1a; 1.从定义上看&#xff1a; 127.0.0.1&#xff1a;这个地址被称为回环地址&#xff08;Loopback Address&#xff09;&#xff0c;是用于本地通信的特殊IP地址&#xff0c;指向计算机自身。它用于测试和调试网络应用程序&#xff0c;无论设备是否连接…...

SQL CASE表达式的用法

SQL CASE表达式的用法 一、CASE表达式的基础语法简单CASE表达式搜索CASE表达式 二、简单CASE表达式的应用示例三、搜索CASE表达式的应用示例四、CASE表达式在聚合函数中的应用五、嵌套CASE表达式的应用 今天在也无力用到了CASE表达式&#xff0c;于是有了这篇博客&#xff0c;C…...

排序合集之快排详解(二)

摘要&#xff1a;快速排序是一种在实践中广泛使用的高效排序算法。它基于分治策略&#xff0c;平均时间复杂度为O(n log n)&#xff0c;使其成为处理大型数据集的理想选择。本文将深入探讨快速排序的各种实现方式、优化技巧以及非递归实现&#xff0c;并通过C语言代码示例进行详…...

前缀树算法篇:前缀信息的巧妙获取

前缀树算法篇&#xff1a;前缀信息的巧妙获取 那么前缀树算法是一个非常常用的算法&#xff0c;那么在介绍我们前缀树具体的原理以及实现上&#xff0c;我们先来说一下我们前缀树所应用的一个场景&#xff0c;那么在一个字符串的数据集合当中&#xff0c;那么我们查询我们某个字…...

shell脚本自动安装MySQL8

环境&#xff1a;centos7版本&#xff1a;8.0.28安装包&#xff1a;mysql-8.0.28-linux-glibc2.12-x86_64.tar.xz 二进制包要求&#xff1a;安装包和shell脚本在同一目录下执行方式&#xff1a;sudo ./install_mysql8.sh #!/bin/bash# 定义MySQL安装目录和压缩包名称MYSQL_DIR…...

当没有OpenGL时,Skia如何绘制?

Skia 是可以在没有 OpenGL 的情况下进行图形绘制的&#xff0c;但是具体能否成功绘制图形&#xff0c;取决于 Skia 是如何配置的&#xff0c;以及平台上是否提供了其他的底层图形 API。 Skia 的底层依赖 Skia 的目标是提供一种跨平台的 2D 图形绘制接口。为了加速图形渲染&…...

大数据系列 | 白话讲解大数据技术生态中Hadoop、Hive、Spark的关系介绍

大数据属于数据管理系统的范畴&#xff0c;数据管理系统无非就两个问题&#xff1a;数据怎么存、数据怎么算    现在的信息爆炸时代&#xff0c;一台服务器数据存不下&#xff0c;可以找10台服务器存储&#xff0c;10台存储不下&#xff0c;可以再找100台服务器存储。但是这1…...

华为云函数计算FunctionGraph部署ollma+deepseek

1 概述 ollama和deepseek如果需要多实例&#xff0c;一种方式是部署在kubernetes集群中&#xff0c;一种是使用云厂商的云函数服务。云函数服务是按量付费&#xff0c;并且底层支持GPU&#xff0c;不需要维护kubernetes集群。本文介绍使用华为云函数计算FunctionGraph来部署ol…...

尚硅谷爬虫note001

一、模板设置 file——setting——editor——code style——file and code template——python script # _*_ coding : utf-8 _*_ # Time : ${DATE} ${TIME} # Author : 20250206-里奥 # File : ${NAME} # Project : ${PROJECT_NAME} 二、数据类型 2-1. 数字 整型int 浮点型f…...

35~37.ppt

目录 35.张秘书-《会计行业中长期人才发展规划》 题目​ 解析 36.颐和园公园&#xff08;25张PPT) 题目​ 解析 37.颐和园公园&#xff08;22张PPT) 题目 解析 35.张秘书-《会计行业中长期人才发展规划》 题目 解析 插入自定义的幻灯片&#xff1a;新建幻灯片→重用…...

FPGA简介|结构、组成和应用

Field Programmable Gate Arrays&#xff08;FPGA&#xff0c;现场可编程逻辑门阵列&#xff09;&#xff0c;是在PAL、GAL、CPLD等可编程器件的基础上进一步发展的产物&#xff0c; 是作为专用集成电路&#xff08;ASIC&#xff09;领域中的一种半定制电路而出现的&#xff0c…...

4. React 中的 CSS

用例中的干净的脚手架的创建可以参考另一篇文章&#xff1a;3.React 组件化开发React官方并没有给出在React中统一的样式风格&#xff1a; 由此&#xff0c;从普通的css&#xff0c;到css modules&#xff0c;再到css in js&#xff0c;有几十种不同的解决方案&#xff0c;上百…...

django中间件,中间件给下面传值

1、新建middleware.py文件 # myapp/middleware.py import time from django.http import HttpRequest import json from django.http import JsonResponse import urllib.parse from django.core.cache import cache from comm.Db import Db class RequestTimeMiddleware:def …...

【论文阅读】Revisiting the Assumption of Latent Separability for Backdoor Defenses

https://github.com/Unispac/Circumventing-Backdoor-Defenses 摘要和介绍 在各种后门毒化攻击中&#xff0c;来自目标类别的毒化样本和干净样本通常在潜在空间中形成两个分离的簇。 这种潜在的分离性非常普遍&#xff0c;甚至在防御研究中成为了一种默认假设&#xff0c;我…...

Python基于Django的微博热搜、微博舆论可视化系统(V3.0)【附源码】

博主介绍&#xff1a;✌Java老徐、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&…...

集成学习(一):从理论到实战(附代码)

一、引言 在机器学习领域&#xff0c;打造一个独立、强大的算法是解决问题的关键。然而&#xff0c;集成学习提供了一种不同的视角&#xff1a;通过组合多个“弱”学习器来创建一个更强大的模型。本文探讨集成学习的思想、方法及其应用。 二、机器学习 vs 集成学习思想 传统…...

不小心删除服务[null]后,git bash出现错误

不小心删除服务[null]后&#xff0c;git bash出现错误&#xff0c;如何解决&#xff1f; 错误描述&#xff1a;打开 git bash、msys2都会出现错误「bash: /dev/null: No such device or address」 问题定位&#xff1a; 1.使用搜索引擎搜索「bash: /dev/null: No such device o…...

【云安全】云原生- K8S kubeconfig 文件泄露

什么是 kubeconfig 文件&#xff1f; kubeconfig 文件是 Kubernetes 的配置文件&#xff0c;用于存储集群的访问凭证、API Server 的地址和认证信息&#xff0c;允许用户和 kubectl 等工具与 Kubernetes 集群进行交互。它通常包含多个集群的配置&#xff0c;支持通过上下文&am…...

【工业场景】用YOLOv8实现火灾识别

火灾识别任务是工业领域急需关注的重点安全事项,其应用场景和背景意义主要体现在以下几个方面: 应用场景:工业场所:在工厂、仓库等工业场所中,火灾是造成重大财产损失和人员伤亡的主要原因之一。利用火灾识别技术可以及时发现火灾迹象,采取相应的应急措施,保障人员安全和…...

(2025)深度分析DeepSeek-R1开源的6种蒸馏模型之间的逻辑处理和编写代码能力区别以及配置要求,并与ChatGPT进行对比(附本地部署教程)

(2025)通过Ollama光速部署本地DeepSeek-R1模型(支持Windows10/11)_deepseek猫娘咒语-CSDN博客文章浏览阅读1k次&#xff0c;点赞19次&#xff0c;收藏9次。通过Ollama光速部署本地DeepSeek-R1(支持Windows10/11)_deepseek猫娘咒语https://blog.csdn.net/m0_70478643/article/de…...

【自然语言处理】TextRank 算法提取关键词、短语、句(Python源码实现)

文章目录 一、TextRank 算法提取关键词 [工具包]二、TextRank 算法提取关键短语[工具包]三、TextRank 算法提取关键句[工具包]四、TextRank 算法提取关键句&#xff08;Python源码实现&#xff09; 一、TextRank 算法提取关键词 [工具包] 见链接 【自然语言处理】TextRank 算法…...

记一次Self XSS+CSRF组合利用

视频教程在我主页简介或专栏里 &#xff08;不懂都可以来问我 专栏找我哦&#xff09; 目录&#xff1a;  确认 XSS 漏洞 确认 CSRF 漏洞 这个漏洞是我在应用程序的订阅表单中发现的一个 XSS 漏洞&#xff0c;只能通过 POST 请求进行利用。通常情况下&#xff0c;基于 POST 的…...

人生的转折点反而迷失了方向

就像我老婆说的&#xff0c;我是抽空结了一个婚。今天是上班的第三天&#xff0c;不知道是出于何种原因&#xff0c;自己反而陷入了深深的困境&#xff0c;没有了斗志&#xff0c;原因也找不出来&#xff0c;白天在公司没有很大量的产出&#xff0c;晚上回去是想学一学&#xf…...

Deepseek PHP API调用指南

本文将介绍如何通过 PHP 调用 Deepseek API&#xff0c;并通过简易代码展示如何与 Deepseek 的 AI 模型进行交互&#xff0c;帮助开发者更好地在自己的项目中应用这一强大的工具。我们将提供一个基本的 PHP 示例&#xff0c;帮助你快速了解如何通过 Deepseek API 进行调用。 以…...

网络安全事件分级

对网络安全事件进行必要分级&#xff0c;是做好应急响应工作的前提。网络安全事件分级要统筹考虑诸多因素&#xff0c;直观展示信息安全事件的风险程度&#xff0c;为后续处置工作提供重要参考。 一、网络安全事件的分级要素 对网络安全事件的分级主要考虑3个要素&#xff1a…...