认证学习3 - Digest摘要认证讲解、代码实现、演示

2023-05-16

文章目录

      • Digest摘要认证 - 密文
        • 讲解(Digest摘要认证)
        • 实现(Digest认证)
          • 代码(Digest认证)
            • 代码(Digest认证-客户端)
            • 演示(Digest认证-postman)


认证大全(想学习其他认证,请到此链接查看)

Digest摘要认证 - 密文

背景: 仅仅只是用来替代Basic认证,由于Basic认证使用明文账户、密码传输这得确保客户端、服务端传输之间不会被任何人截取报文,这就要求很高,我们都知道网络传输没有绝对的安全,为了不使得明文传输,RFC提出另一种认证方式即Digest认证,认证时仅传账户、密码的摘要,这就避免有人即是劫持报文获得认证信息也不会解析得到用户的账户、密码

在这里插入图片描述

讲解(Digest摘要认证)

参考文章: https://www.cnblogs.com/huey/p/5490759.html

官方规范(新-兼容老规范-必须看): https://datatracker.ietf.org/doc/html/rfc7616
官方规范(老规范-必须看): https://datatracker.ietf.org/doc/html/rfc2617

请求头字段规范: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Digest

好文1(强烈建议看-可以不用看好文2的实现看我的实现也可以): https://www.cnblogs.com/xiaoxiaotank/p/11078571.html
好文2(强烈建议看): https://www.cnblogs.com/xiaoxiaotank/p/11079024.html

优点
用户、密码非明文传输
防止对报文内容的篡改
防止重放攻击
响应码
400:认证失败,认证失败,认证必要的参数缺失
401:认证失败,客户端传过来的摘要跟服务器计算的不一致,需要用户重新输入用户名、密码再次进行认证

在这里插入图片描述

在这里插入图片描述

//响应头:WWW-Authenticate  或者 请求头:Authorization
Digest username="用户名", realm="角色描述", nonce="服务端随机数(Base64或十六进制编码)", uri="请求uri部分", response="摘要(客户端计算、到时服务端也会计算一份看是否一致)", algorithm="摘要算法", cnonce="客户端随机数(Base64或十六进制编码)", opaque="服务端给的信息原封不动换回去即可", nc="使用次数", qop="auth|auth-init"


//响应头WWW-Authenticate 必须提供
opaque、algorithm

//响应头WWW-Authenticate 提供
qop,则请求头Authorization将这个参数原封不动的还回去


//摘要公式  secret=密钥key  data=需要摘要的数据   两个参数都是根据规则由WWW-Authenticate里面的参数进行构建
//由于摘要算法无需密钥即可生成,故充分利用将secret也作为被摘要的部分数据
KD(secret, data)=摘要算法(concat(secret, ":", data))   
secret(也称A1)=摘要算法(摘要算法(<username>:<realm>:<password>):<nonce>:<cnonce>)
secret(也称A1-sess形式)=摘要算法(<username>:<realm>:<password>)
data=<nonce>:<nc>:<cnonce>:<qop>:摘要算法(A2)
A2=<request-method>:<uri>
原英文参数(请求头携带的参数名)作用
(响应头-认证失败)WWW-Authentication用来定义使用何种方式(Basic、Digest、Bearer等)去进行认证以获取受保护的资源、以及各种其他参数添加
digest-uriuri当前请求的uri
username即将认证的用户名
realm表示Web服务器中受保护文档的安全域(比如公司财务信息域和公司员工信息域),用来指示需要哪个域的用户名和密码
message-qopqop保护质量,包含 auth(默认的)和 auth-int(增加了报文完整性检测)以及 Token值 三种策略,(可以为空,但是)不推荐为空值
noncenonce服务端向客户端发送质询时附带的一个随机数,这个数会经常发生变化。客户端计算密码摘要时将其附加上去,使得多次生成同一用户的密码摘要各不相同,用来防止重放攻击 = 官方建议每次请求都不同
userhashuserhash(选填)是否支持用户名使用hash,默认false
opaque(选填)服务端给的数据一般是Base64或十六进制编码,客户端请求认证时原封不动的返回给服务端
(请求头-开始认证)Authorization认证类型以及用于携带客户端认证信息
nonce-countncnonce计数器,是一个16进制的数值,表示同一nonce下客户端发送出请求的数量。例如,在响应的第一个请求中,客户端将发送“nc=00000001”。这个指示值的目的是让服务器保持这个计数器的一个副本,以便检测重复的请求
cnonce客户端随机数,这是一个不透明的字符串值,由客户端提供,并且客户端和服务器都会使用,以避免用明文文本。这使得双方都可以查验对方的身份,并对消息的完整性提供一些保护
request-digestresponse这是由用户代理软件计算出的一个字符串,以证明用户知道口令 == 认证凭证(服务端校验)== 公式:MD5(MD5(A1):::::MD5(A2))
(响应头-认证成功) Authorization-Info用于返回一些与授权会话相关的附加信息
nextnonce下一个服务端随机数,使客户端可以预先发送正确的摘要
rspauth响应摘要,用于客户端对服务端进行认证 == 认证凭证(客户端校验) == 公式:MD5(MD5(A1):::::MD5(A2))
stale当密码摘要使用的随机数过期时,服务器可以返回一个附带有新随机数的401响应,并指定stale=true,表示服务器在告知客户端用新的随机数来重试,而不再要求用户重新输入用户名和密码了
algorithm摘要算法,由服务端(响应头)进行指定,默认MD5,支持MD5、MD5-sess、SHA-256、SHA-256-sess、SHA-512-256、SHA-512-256-sess、token值
//认证凭证生成算法=即参数response、rspauth
MD5(MD5(A1):<nonce>:<nc>:<cnonce>:<qop>:MD5(A2))

客户端生成用户凭证的参数内容

算法A1
MD5(默认)MD5(::)
MD5-sessMD5(::)::
qopA2
auth(默认):
auth-int::MD5()

服务端生成用户凭证的参数内容 == 无请求方式-参数变化即是少了请求方式而已

qopA2
auth(默认):
auth-int::MD5()

实现(Digest认证)

代码(Digest认证)
代码(Digest认证-客户端)

在这里插入图片描述


需要额外引入这两个依赖

<!-- 主要用于该工具类线程写好的 sha-512/256摘要算法 ->
<!-- https://mvnrepository.com/artifact/org.bouncycastle/bcprov-jdk15on -->
<dependency>
    <groupId>org.bouncycastle</groupId>
    <artifactId>bcprov-jdk15on</artifactId>
    <version>1.70</version>
</dependency>

<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.8.5</version>
</dependency>   


DigestAuthInterceptor.java

package work.linruchang.qq.mybaitsplusjoin.config.interceptor;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.text.CharPool;
import cn.hutool.core.util.StrUtil;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import work.linruchang.qq.mybaitsplusjoin.config.interceptor.algorithm.digest.DigestAlgorithmUtil;
import work.linruchang.qq.mybaitsplusjoin.config.interceptor.algorithm.digest.WWWAuthenticate;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 作用:Basic认证
 *
 * @author LinRuChang
 * @version 1.0
 * @date 2022/08/04
 * @since 1.8
 **/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class DigestAuthInterceptor implements HandlerInterceptor {


    @AllArgsConstructor
    @Getter
    enum AuthErrorEnum {

        INVALID_REQUEST(400, "invalid_request", "参数异常"),
        INVALID_DIGEST(401, "invalid_digest", "摘要不一致");


        Integer errorCode;
        String error;
        String errorDescription;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {


        boolean authStatusFlag = false;
        String authorization = request.getHeader("Authorization");
        AuthErrorEnum authErrorEnum = AuthErrorEnum.INVALID_DIGEST;

        if (StrUtil.isNotBlank(authorization)) {
            String[] splitInfos = authorization.split(StrUtil.COMMA + StrUtil.SPACE);
            splitInfos[0] = StrUtil.removePrefix(splitInfos[0], "Digest ");

            //解析认证参数
            Map<String, String> splitInfosMap = Stream.of(splitInfos)
                    .map(StrUtil::trim)
                    .map(splitInfo -> StrUtil.removeAll(splitInfo, CharPool.DOUBLE_QUOTES))
                    .collect(Collectors.toMap(splitInfo -> {
                        return splitInfo.split("=")[0];
                    }, splitInfo -> {
                        return splitInfo.split("=")[1];
                    }));
            WWWAuthenticate wwwAuthenticate = BeanUtil.toBean(splitInfosMap, WWWAuthenticate.class);
            Dict userInfo = getUserInfo(wwwAuthenticate.getUsername());
            if (userInfo != null) {
                wwwAuthenticate.setPassword(userInfo.getStr("password"));
                wwwAuthenticate.setRequestMethod(request.getMethod());
                String serverResponse = DigestAlgorithmUtil.result(wwwAuthenticate);
                if (StrUtil.equals(serverResponse, wwwAuthenticate.getResponse())) {  //摘要一致
                    authStatusFlag = true;
                }
            } else {
                authErrorEnum = AuthErrorEnum.INVALID_REQUEST;
            }
        }

        //认证失败
        if (!authStatusFlag) {
            response.setHeader("WWW-Authenticate", StrUtil.format("Digest realm=\"rights of administrators\", nonce=\"{}\", qop=\"auth\"", UUID.randomUUID().toString(true)));
            response.setHeader("content-type", "text/plain;charset=utf-8");
            response.setStatus(authErrorEnum.getErrorCode());
            response.getWriter().write("认证失败");
            return false;
        }

        return authStatusFlag;
    }


    public Dict getUserInfo(String userName) {
        if (StrUtil.equals(userName, "admin")) {
            return Dict.create()
                    .set("userName", "admin")
                    .set("password", "admin123");

        }
        return null;
    }
}
     


DigestAuthInterceptor.java

@Configuration
public class MyConfig implements WebMvcConfigurer {
    @Autowired
    DigestAuthInterceptor digestAuthInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(digestAuthInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/js/**","/user*/**","/user*/**");
    }
}


DigestAlgorithm.java

public interface DigestAlgorithm {

    /**
     * 计算摘要结果
     * 摘要算法(摘要算法(A1):<nonce>:<nc>:<cnonce>:<qop>:摘要算法(A2))
     *  A1(sess形式):  摘要算法(<username>:<realm>:<password>):<nonce>:<cnonce>
     *  A1(非sess形式):  <username>:<realm>:<password>
     *
     *  A2:<request-method>:<uri>
     * @param wwwAuthenticate
     * @return
     */
    String result(WWWAuthenticate wwwAuthenticate);

}


MD5DigestAlgorithm.java

 **/
public class MD5DigestAlgorithm implements DigestAlgorithm{
    @Override
    public String result(WWWAuthenticate wwwAuthenticate) {
        String A1Digest = null;
        String A2Digest = null;

        //MD5-sess
        if(StrUtil.containsIgnoreCase(wwwAuthenticate.getAlgorithm(),"sess")) {
            A1Digest = SecureUtil.md5(StrUtil.format("{}:{}:{}", SecureUtil.md5(StrUtil.format("{}:{}:{}", wwwAuthenticate.getUsername(), wwwAuthenticate.getRealm(), wwwAuthenticate.getPassword())), wwwAuthenticate.getNonce(), wwwAuthenticate.getCnonce()));
            A2Digest = SecureUtil.md5(StrUtil.format("{}:{}", wwwAuthenticate.getRequestMethod(), wwwAuthenticate.getUri()));
        }else { //MD5
            A1Digest = SecureUtil.md5(StrUtil.format("{}:{}:{}", wwwAuthenticate.getUsername(), wwwAuthenticate.getRealm(), wwwAuthenticate.getPassword()));
            A2Digest = SecureUtil.md5(StrUtil.format("{}:{}", wwwAuthenticate.getRequestMethod(), wwwAuthenticate.getUri()));
        }
        String serverResponse = SecureUtil.md5(StrUtil.format("{}:{}:{}:{}:{}:{}", A1Digest, wwwAuthenticate.getNonce(), wwwAuthenticate.getNc(), wwwAuthenticate.getCnonce(), wwwAuthenticate.getQop(), A2Digest));
        return serverResponse;
    }
}


SHA256DigestAlgorithm.java

public class SHA256DigestAlgorithm implements DigestAlgorithm{
    @Override
    public String result(WWWAuthenticate wwwAuthenticate) {
        String A1Digest = null;
        String A2Digest = null;

        //SHA256-sess
        if(StrUtil.containsIgnoreCase(wwwAuthenticate.getAlgorithm(),"sess")) {
            A1Digest = SecureUtil.sha256(StrUtil.format("{}:{}:{}", SecureUtil.md5(StrUtil.format("{}:{}:{}", wwwAuthenticate.getUsername(), wwwAuthenticate.getRealm(), wwwAuthenticate.getPassword())), wwwAuthenticate.getNonce(), wwwAuthenticate.getCnonce()));
            A2Digest = SecureUtil.sha256(StrUtil.format("{}:{}", wwwAuthenticate.getRequestMethod(), wwwAuthenticate.getUri()));
        }else { //SHA256
            A1Digest = SecureUtil.sha256(StrUtil.format("{}:{}:{}", wwwAuthenticate.getUsername(), wwwAuthenticate.getRealm(), wwwAuthenticate.getPassword()));
            A2Digest = SecureUtil.sha256(StrUtil.format("{}:{}", wwwAuthenticate.getRequestMethod(), wwwAuthenticate.getUri()));
        }
        String serverResponse = SecureUtil.sha256(StrUtil.format("{}:{}:{}:{}:{}:{}", A1Digest, wwwAuthenticate.getNonce(), wwwAuthenticate.getNc(), wwwAuthenticate.getCnonce(), wwwAuthenticate.getQop(), A2Digest));
        return serverResponse;
    }
}


SHA512256DigestAlgorithm.java

public class SHA512256DigestAlgorithm implements DigestAlgorithm{
    @Override
    public String result(WWWAuthenticate wwwAuthenticate) {
        String A1Digest = null;
        String A2Digest = null;
        Digester digester = DigestUtil.digester("sha-512/256");
        //SHA-512/256-sess
        if(StrUtil.containsIgnoreCase(wwwAuthenticate.getAlgorithm(),"sess")) {
            A1Digest = digester.digestHex(StrUtil.format("{}:{}:{}", digester.digestHex(StrUtil.format("{}:{}:{}", wwwAuthenticate.getUsername(), wwwAuthenticate.getRealm(), wwwAuthenticate.getPassword())), wwwAuthenticate.getNonce(), wwwAuthenticate.getCnonce()));
            A2Digest = digester.digestHex(StrUtil.format("{}:{}", wwwAuthenticate.getRequestMethod(), wwwAuthenticate.getUri()));
        }else { //SHA-512/256
            A1Digest = digester.digestHex(StrUtil.format("{}:{}:{}", wwwAuthenticate.getUsername(), wwwAuthenticate.getRealm(), wwwAuthenticate.getPassword()));
            A2Digest = digester.digestHex(StrUtil.format("{}:{}", wwwAuthenticate.getRequestMethod(), wwwAuthenticate.getUri()));
        }
        String serverResponse =digester.digestHex(StrUtil.format("{}:{}:{}:{}:{}:{}", A1Digest, wwwAuthenticate.getNonce(), wwwAuthenticate.getNc(), wwwAuthenticate.getCnonce(), wwwAuthenticate.getQop(), A2Digest));
        return serverResponse;
    }
}


DigestAlgorithmUtil.java

public class DigestAlgorithmUtil {

    private final static ConcurrentHashMap<String, DigestAlgorithm> digestAlgorithmMap = new ConcurrentHashMap<>();

    /**
     * 计算摘要结果
     *
     * @param wwwAuthenticate
     * @return
     */
    @SneakyThrows
    public static String result(WWWAuthenticate wwwAuthenticate) {

        String packageName = ClassUtil.getPackage(DigestAlgorithmUtil.class);
        String algorithm = StrUtil.removeAll(StrUtil.split(wwwAuthenticate.getAlgorithm(), "-sess").get(0), StrUtil.DASHED);

        DigestAlgorithm digestAlgorithm = Optional.ofNullable(digestAlgorithmMap.get(algorithm))
                .orElseGet(() -> {
                    DigestAlgorithm currentDigestAlgorithm = null;
                    try {
                        Class<?> digestAlgorithmClass = Class.forName(StrUtil.format("{}.{}DigestAlgorithm", packageName, algorithm));
                        currentDigestAlgorithm = (DigestAlgorithm) ReflectUtil.newInstance(digestAlgorithmClass);
                        digestAlgorithmMap.put(algorithm, currentDigestAlgorithm);
                    } catch (ClassNotFoundException e) {
                    }
                    return currentDigestAlgorithm;
                });
        Assert.notNull(digestAlgorithm, "【{}】摘要算法找不到,请检查", algorithm);


        return digestAlgorithm.result(wwwAuthenticate);
    }

    @SneakyThrows
    public static void main(String[] args) {
        Class<?> md5DigestAlgorithm = Class.forName("MD5DigestAlgorithm");

        Console.log(md5DigestAlgorithm);

    }

}


WWWAuthenticate.java

@Data
public class WWWAuthenticate {
    String qop;
    String nc;
    String realm;
    String cnonce;
    String uri;
    String nonce;
    String algorithm;
    String username;
    String response;


    /**
     * 用于计算摘要
     */
    String password;
    String requestMethod;
}


ArticleCategoryController.java

@RestController
@RequestMapping("article-category")
public class ArticleCategoryController {
    @GetMapping("/one/{id}")
    public CommonHttpResult<ArticleCategory> findById(@PathVariable("id") String id) {
        return CommonHttpResult.success(articleCategoryService.getById(id));
    }
}
演示(Digest认证-postman)

理由: 为什么使用postman,因为只要输入账号、密码,发现第一个请求认证失败,返回的nonce等信息,postman自动帮你计算好摘要,然后重新发送,如果再次认证认证失败,则不会在帮你重新发送,所以postman最多帮你发送两遍。

在这里插入图片描述

发送错误的用户名或密码
在这里插入图片描述

在这里插入图片描述



发送正确的用户名或密码

在这里插入图片描述

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

认证学习3 - Digest摘要认证讲解、代码实现、演示 的相关文章

  • Http auth认证的两种方式Basic方式和 Digest认证

    Http Basic Auth 方式 当访问一个Http Basic Auth 网站的时候需要提供用户名 xff0c 密码 xff0c 否则会返回401 without authoration Http Basic Authenticati
  • 检查HTTP 的 Digest 认证代码示例-JSP

    检查HTTP 的 Digest 认证 since http1 1 代码如下所示 xff1a 此代码还不完善 RFC2617算法未实现 lt 64 page pageEncoding 61 34 UTF 8 34 contentType 61
  • http 登录Digest认证相关知识

    Digest access authentication https en wikipedia org wiki Digest access authentication Digest access authentication is on
  • HTTP Digest Auth 及HTTP长连接 Libcurl c++实现

    1 HTTP Digest Auth 由于HTTP Auth的安全性差 xff0c 所以出现了 HTTP Digest Auth 顾名思义 xff0c HTTP Digest Auth 就是对账密等信息生成摘要进行对比来验证的 xff0c
  • php curl digest,php curl with digest返回两个响应

    如果对标头使用 I选项 则看起来curl具有相同的行为 xff1a curl I digest u root somepassword http localhost digest test 收益 xff1a HTTP 1 1 401 Aut
  • HTTP的认证方式之DIGEST 认证(摘要认证)

    核心步骤 xff1a 步骤 1 xff1a 请求需认证的资源时 xff0c 服务器会随着状态码 401Authorization Required xff0c 返回带WWW Authenticate 首部字段的响应 该字段内包含质问响应方式
  • ADRC的simulink仿真实现与m代码实现

    本文章以最简单的二阶系统为例 xff0c 介绍其simulink仿真实现和m代码实现 案例中的二阶系统如下所示 经典ADRC的基本结构如下 xff1a 本案例中的simulink仿真整体结构 xff08 为便于理解 xff0c 结构图与上述
  • 一种多源信息融合方法及其应用(Matlab代码实现)

    x1f352 x1f352 x1f352 欢迎关注 x1f308 x1f308 x1f308 x1f4dd 个人主页 xff1a 我爱Matlab x1f44d 点赞 评论 收藏 61 61 养成习惯 xff08 一键三连 xff09 x1
  • http请求digest auth认证

    1 post请求 public static String postMethod String url String query String host throws IOException String content 61 null 认
  • 以摘要认证(Digest Authentication)方式伪登录某摄像头

    本文部分摘自ASP NET Web API xff08 三 xff09 xff1a 安全验证之使用摘要认证 digest authentication 密码已知 分析发现 xff0c 该摄像头Web登录采用了Digest Authentic
  • Http Digest认证协议

    http blog csdn net htjoy1202 article details 7067287 其认证的基本框架为挑战认证的结构 xff0c 如下图所示 xff1a xfeff xfeff 1 客户端希望取到服务器上的某个资源 x
  • php getdigest,http digest

    HTTP digest 摘要访问认证是一种协议规定的Web服务器用来同网页浏览器进行认证信息协商的方法 它在密码发出前 xff0c 先对其应用哈希函数 xff0c 这相对于HTTP基本认证发送明文而言 xff0c 更安全 从技术上讲 xff
  • C# HttpClient Digest 摘要认证 Cookie设置

    C HttpClient Digest 摘要认证 Cookie设置 1 创建凭证信息集 2 创建HttpClientHandler 3 创建HttpClient 4 发生请求 span class token comment 创建凭证信息集
  • http digest认证过程分析及例子

    验证过程 xff1a 步骤一 客户端向服务器申请数据 Request GET auth HTTP 1 1 r n Accept r n Host 192 168 1 15 r n Content Length 0 r n r n r n 步
  • digest鉴权

    摘要 式认证 xff08 Digest authentication xff09 是一个简单的认证机制 xff0c 最初是为HTTP协议开发的 xff0c 因而也常叫做HTTP摘要 xff0c 在RFC2671中描述 其身份验证机制很简单
  • HttpGet Digest授权认证

    工具类 xff1a compile com burgstaller okhttp digest 1 13 import android span class hljs preprocessor content span span class
  • Digest来验证

    Apache默认使用basic模块验证 xff0c 但它只是明文验证 Digest验证 xff0c 是用md5摘要值进行对比 httpRequest getAuthType 方法 xff0c 可以得到网页的验证方式request BASIC
  • 处理https中的Digest authentication鉴权

    问题 xff1a RESTful 的传输协议类型为 HTTPS xff0c 鉴权方式为 Digest SHA256 xff08 即DIGEST摘要认证 xff09 时 xff0c 接口调用问题 参考资料 xff1a 认识HTTP摘要认证 x
  • 我可以序列化 ruby​​ Digest::SHA1 实例对象吗?

    大家好 我正在 ruby sinatra 中重新实现现有的自定义文件上传服务 并使用 redis 作为后备存储 客户 计算 SHA1 哈希并启动上传 上传最多 64K 块直至完成 服务器 将块附加到文件 计算完整文件的 SHA1 哈希值以验
  • 在 Ruby 中创建数字、字符串、数组或哈希的 md5 哈希

    我需要在 Ruby 中为变量创建签名字符串 其中变量可以是数字 字符串 哈希值或数组 哈希值和数组元素也可以是这些类型中的任何一种 该字符串将用于比较数据库 在本例中为 Mongo 中的值 我的第一个想法是创建 JSON 编码值的 MD5

随机推荐

  • C++ Mutable

    1 mutable 含义及常规使用 mutable 英文中表示 xff0c 易变的 xff0c 不定的 xff1b 性情不定的 xff0c 而在代码中表示 可变数据成员 由前面整理的 const详解 知道 xff0c 由const修饰的成员
  • 牛吃草问题

    1 概述 最近碰到一个面试题 xff0c 讲的是牛吃草的问题 xff0c 当时时间短 xff0c 脑袋出现了短路 xff0c 没有给出答案 回来特意查了一下答案 xff0c 发现了一篇比较好的文章 xff0c 现在重新抄写一份 xff0c
  • 开始记录学习中的点滴

    随着年龄的增长 xff0c 除了去了很多地方之外 xff0c 感觉个人没有特别明显的成长 xff0c 对于未来充满了更多的迷茫与困惑 对于程序员的我来说更是感觉到了自己的瓶颈 xff0c 知识储备没有增加多少 xff0c 随着时间的流逝 x
  • C++中Struct与Class的区别与比较

    概述 之前只知道在C 43 43 中类和结构体的区别只有默认的防控属性 xff08 访问控制 xff09 不同 xff0c struct是public的 xff0c 而class是private的 但经过上网查资料才发现 xff0c 除了这
  • 函数调用约定的详解

    概述 在工作的过程中 xff0c 我们总是需要调用底层函数或者使用第三方的库 xff0c 在使用的过程中我就发现了有一些函数前面总有一些 stdcall xff0c 之初我只知道那是调用约定 xff0c 但别人问我什么是调用约定 xff0c
  • #pragma的常用方法讲解

    概述 我们在写代码时 xff0c 总会遇到头文件多次包含的情况 xff0c 刚开始时我们使用宏定义进行控制 xff0c 之后发现有 pragma once这样简单的东西 xff0c 当时是很兴奋 xff0c 以为 pragma就这一种用法
  • C++数组的详细解析

    概述 数组在写程序时经常用到 xff0c 但是对于它和指针的关系 xff0c 自己经常搞混 xff0c 所有抽点时间对数组进行整理 1 数组的概念和使用 数组是用来存储相同类型的变量的顺序集合 所有的数组都是由连续的内存位置组成 最低的地址
  • 华为荣耀9升降级系统 | 华为荣耀9变砖后如何救砖 | 华为荣耀9获取BL解锁码以及如何解BL锁 | 华为荣耀9如何通过写ramdisk.img来获取root

    文章目录 1 按2 通过官方华为手机助手升降级以及修复系统和安装驱动3 使用百分之五模式刷高维禁用包355来安装指定的系统版本8 0 0 3554 故意 xff08 或意外 xff09 刷错包把手机变砖5 使用救砖模式刷高维禁用包355来安
  • C++指针详解

    概述 C C 43 43 语言之所以强大 xff0c 以及其自由性 xff0c 很大部分体现在其灵活的指针运用上 因此 xff0c 说指针是C C 43 43 语言的灵魂一点都不为过 有好的一面 xff0c 必然会有坏的一面 xff0c 指
  • C++ lambda表达式及其原理

    概述 C 43 43 11中引入了新的lamdba表达式 xff0c 使用也很简单 xff0c 我最喜欢的是不用给函数取名称 xff0c 每次给函数取名称都感觉自己读书太少 1 lambda表达式 lambda表达式可以理解为一个匿名的内联
  • GIT 修改用户名和密码

    1 概述 如果你使用GIT的SSH 方式连接远端 xff0c 并且设置了一个没有口令的秘钥 xff0c 这样就可以砸不输入用户名和密码的情况下安全地传输数据 然而 xff0c 这对 HTTP 协议来说是不可能的 每一个连接都是需要用户名和密
  • bmi055 标定_Kalibr tutorials

    Kalibr installation tutorial I was confused about installing Kalibr but there is no even one hint in README md I just pu
  • python上位机例程_python 上位机通信实例

    34 moduleinfo 34 34 card count 34 34 count phone 34 1 34 count 34 1 34 search count 34 34 count phone 34 6 34 count 34 6
  • linux post请求_Linux C++网络编程

    img 前言 要想找一份Linux c 43 43 方面的好工作 xff0c 在面试过程中游刃有余 xff0c 那么这篇文章就是为你定制的 因为作为一个校招的学生 xff0c 我在学习和面试过程中的经历总这个体系的文章 xff0c 希望可以
  • 200826-C语言打印文件中的文本内容

    1 Description 在桌面上创建一个txt文件 xff0c 输入一些文本内容 xff0c 我们的任务是把文本内容打印出来 在编程之前 xff0c 关于一些函数的定义我们需要了解下 fopen fopen的函数原型为 xff1a FI
  • matlab设置使用vs2008编译器,64位操作系统下如何将matlab与vs2008的c编译器

    在windows sever 2008 操作系统上分别装了 matlab2009 xff0c vs2008 xff0c 想把 m 文件编译成 exe 文件 xff0c 但matlab找不到c的编译器 如下 xff0c 请教如何解决 gt g
  • 用c语言实现https通信,C/C++实现HTTPS通信

    include 34 afxinet h 34 CInternetSession mysession CHttpConnection myconn CString VoidText CString strSentence strGetSen
  • iar stm32_详解STM32单片机的堆栈

    学习STM32单片机的时候 xff0c 总是能遇到 堆栈 这个概念 分享本文 xff0c 希望对你理解堆栈有帮助 对于了解一点汇编编程的人 xff0c 就可以知道 xff0c 堆栈是内存中一段连续的存储区域 xff0c 用来保存一些临时数据
  • 猎人华为单机离线版(一键启动增强版+扩展工具箱2022) | 猎人维修大师免加密狗单机永久版 | 华为线刷工具(MRT HW Flash Tool) | 华为工具(MRT HW Tool_V3.3)

    文章目录 1 按2 资源下载3 打开说明3 1 华为线刷工具 xff08 MRT HW Flash Tool xff09 3 2 华为工具 xff08 MRT HW Tool V3 3 xff09 4 使用说明4 1 怎么进入刷机模式4 1
  • 认证学习3 - Digest摘要认证讲解、代码实现、演示

    文章目录 Digest摘要认证 密文讲解 xff08 Digest摘要认证 xff09 实现 xff08 Digest认证 xff09 代码 xff08 Digest认证 xff09 代码 xff08 Digest认证 客户端 xff09