一、回顾SIP Register的认证过程

  1. Client(通常是话机)向REG Server(一般是OpenSIPS或Freeswitch)发起REGISTER注册请求(注:此时发送的请求里,只有一些用户名、客户端类型之类的普通信息)
  2. REG Server收到请求后,发现里面没有Digest等安全相关的摘要信息,直接返回401(未授权),同时会附加额外的安全信息(比如:realm/nonce/algorithm/qop)
  3. Client收到401拒绝返回后,根据服务端返回的realm/nonce/algorithm/qop信息,结合自己的password,计算出一个最终的response digiest(注:是一个md5值),重新发起第2次REGISTER,并附带上response digest等认证相关信息。
  4. REG Server根据Client发过来的Authorization认证信息进行校验,如果校验通过,则返回200 OK,认证通过

二、认证过程中的SIP信令(报文)

这里介绍二种查看REGISTER过程SIP信令的方法:

2.1 打开FreeSwitch的SIP trace功能

sofia profile internal siptrace on|off

在FreeSwitch控制台中,输入上面的命令行(on为打开,off为关闭),然后用Client(比如:免费开源软电话MicroSIP)注册,此时FreeSwitch中会输出4段SIP报文,分别对应认证过程中的4个阶段,类似下面这样:

第1段 REGISTER(Client → FreeSwitch)

recv 647 bytes from tcp/[10.32.26.25]:51696 at 02:14:58.914917:
------------------------------------------------------------------------
REGISTER sip:10.32.26.25:5070;transport=tcp SIP/2.0
Via: SIP/2.0/TCP 10.32.26.25:51696;rport;branch=z9hG4bKPj8d4db68b24754f539dbf3b563a44fe55;alias
Max-Forwards: 70
From: <sip:1000@10.32.26.25>;tag=89aefb1f3fc0413283a453eda5407f60
To: <sip:1000@10.32.26.25>
Call-ID: 1e7af0e67a5044658fc7f6716d329642
CSeq: 36850 REGISTER
User-Agent: MicroSIP/3.20.3
Supported: outbound, path
Contact: <sip:1000@10.32.26.25:51696;transport=TCP;ob>;reg-id=1;+sip.instance="<urn:uuid:00000000-0000-0000-0000-000011058e7e>"
Expires: 300
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Content-Length:  0

第2段 401 Unauthorized(FreeSwitch → Client)

send 670 bytes to tcp/[10.32.26.25]:51696 at 02:14:58.918913:
------------------------------------------------------------------------
SIP/2.0 401 Unauthorized
Via: SIP/2.0/TCP 10.32.26.25:51696;rport=51696;branch=z9hG4bKPj8d4db68b24754f539dbf3b563a44fe55;alias
From: <sip:1000@10.32.26.25>;tag=89aefb1f3fc0413283a453eda5407f60
To: <sip:1000@10.32.26.25>;tag=Q0m1g96BS3vpa
Call-ID: 1e7af0e67a5044658fc7f6716d329642
CSeq: 36850 REGISTER
User-Agent: FreeSWITCH-mod_sofia/1.6.18+git~20170612T211449Z~6e79667c0a~64bit
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE
Supported: timer, path, replaces
WWW-Authenticate: Digest realm="10.32.26.25", nonce="bee3366b-cf59-476e-bc5e-334e0d65b386", algorithm=MD5, qop="auth"
Content-Length: 0

第3段  REGISTER (第2次 Client → FreeSwitch)

recv 921 bytes from tcp/[10.32.26.25]:51696 at 02:14:58.925916:
------------------------------------------------------------------------
REGISTER sip:10.32.26.25:5070;transport=tcp SIP/2.0
Via: SIP/2.0/TCP 10.32.26.25:51696;rport;branch=z9hG4bKPj414de93b6fd34f21a9c453d81117fee2;alias
Max-Forwards: 70
From: <sip:1000@10.32.26.25>;tag=89aefb1f3fc0413283a453eda5407f60
To: <sip:1000@10.32.26.25>
Call-ID: 1e7af0e67a5044658fc7f6716d329642
CSeq: 36851 REGISTER
User-Agent: MicroSIP/3.20.3
Supported: outbound, path
Contact: <sip:1000@10.32.26.25:51696;transport=TCP;ob>;reg-id=1;+sip.instance="<urn:uuid:00000000-0000-0000-0000-000011058e7e>"
Expires: 300
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Authorization: Digest username="1000", realm="10.32.26.25", nonce="bee3366b-cf59-476e-bc5e-334e0d65b386", uri="sip:10.32.26.25:5070;transport=tcp", response="7a8049557b2e77602625fa9ee7d8f088", algorithm=MD5, cnonce="c3606b3f70544096a7e17fcdb4670795", qop=auth, nc=00000001
Content-Length:  0

第4段 200 Ok(FreeSwitch → Client)

 send 646 bytes to tcp/[10.32.26.25]:51696 at 02:14:58.933914:
   ------------------------------------------------------------------------
   SIP/2.0 200 OK
   Via: SIP/2.0/TCP 10.32.26.25:51696;rport=51696;branch=z9hG4bKPj414de93b6fd34f21a9c453d81117fee2;alias
   From: <sip:1000@10.32.26.25>;tag=89aefb1f3fc0413283a453eda5407f60
   To: <sip:1000@10.32.26.25>;tag=r9Dtj4QFpcK9N
   Call-ID: 1e7af0e67a5044658fc7f6716d329642
   CSeq: 36851 REGISTER
   Contact: <sip:1000@10.32.26.25:51696;transport=TCP;ob>;expires=300
   Date: Mon, 06 Sep 2021 02:14:58 GMT
   User-Agent: FreeSWITCH-mod_sofia/1.6.18+git~20170612T211449Z~6e79667c0a~64bit
   Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE
   Supported: timer, path, replaces
   Content-Length: 0

  

2.2 采用WireShark抓包

参考上图,启动WireShark,指定网卡以及抓包的协议为sip后,本机用Client注册登录1次,就能抓到这4个阶段的SIP信令(注:上图的REG Server是OpenSIPS),跟FreeSwith做为REG Server对比,可以发现OpenSIPS第3阶段,返回的Authorization里,少了cnounce、 qop、nc这3个值,这一点要注意一下。

三、Response Digest的计算过程

通过观察SIP报文发现,整个注册过程中Client始终没有发送过任何password的明文,相对还是很安全的。Client第2次发起REGISTER时,附带的Response值是关键!REG Server将校验这个值的正确性,校验通过才会注册成功。

整个计算过程,分成三步:

3.1 计算HA1

规则如下:

algorithm 
HA1

MD5(或未指定)

MD5(username:realm:password)

MD5-sess

MD5(MD5(username:realm:password):nonce:cnonce)

    注:MD5计算出来的值为32位小写,password为密码,只有Client自己知道。

例1(FreeSwitch充当REG Server):

Client第2次提交的REGISTER请求中,Authorization信息为:

Authorization: Digest username="1000", realm="10.32.26.25", nonce="bee3366b-cf59-476e-bc5e-334e0d65b386", uri="sip:10.32.26.25:5070;transport=tcp", response="7a8049557b2e77602625fa9ee7d8f088", algorithm=MD5, cnonce="c3606b3f70544096a7e17fcdb4670795", qop=auth, nc=00000001

则HA1 = MD5("1000:10.32.26.25:1234") = 6a5e40ec8a6cbac75b9914b271516a47 (假设password为1234)

例2(OpenSIPS充当REG Server):

第2阶段,FreeSwitch返回的Authorization如下:

Authorization: Digest username="440444", realm="10.2.60.171", nonce="6135e48401ea0109021093850f9c5db2bf101786", uri="sip:10.2.60.171:5060", response="885f45ae2179c9d8ce2bc1cbd8e4bb9f"

则HA1 = MD5("440444:10.2.60.171:440444") = 109cf921db79c57e146cd8d46429312d (假设password与username相同,都为440444)

3.2 计算HA2

规则如下:

qop
HA2

auth(或未指定)

MD5(method:digestURI)

auth-int

MD5(method:digestURI:MD5(entityBody))

注:digestURI为SIP信令Authorization节点中的uri值,对于注册来说,method即为固定值REGISTER

例1(FreeSwitch充当REG Server):

Client第2次提交的REGISTER请求中,Authorization信息为:

Authorization: Digest username="1000", realm="10.32.26.25", nonce="bee3366b-cf59-476e-bc5e-334e0d65b386", uri="sip:10.32.26.25:5070;transport=tcp", response="7a8049557b2e77602625fa9ee7d8f088", algorithm=MD5, cnonce="c3606b3f70544096a7e17fcdb4670795", qop=auth, nc=00000001

则HA2 = MD5("REGISTER:sip:10.32.26.25:5070;transport=tcp") = c0a1637fb943febd38e69c2087d58fe9

例2(OpenSIPS充当REG Server):

第2阶段,FreeSwitch返回的Authorization如下:

Authorization: Digest username="440444", realm="10.2.60.171", nonce="6135e48401ea0109021093850f9c5db2bf101786", uri="sip:10.2.60.171:5060", response="885f45ae2179c9d8ce2bc1cbd8e4bb9f"

则HA2 = MD5("REGISTER:sip:10.2.60.171:5060") = 9f5c90dad45f8b57a9de5ad977027d7b

3.3 计算Response

根据前2步计算出来的HA1及HA2,计算response值,规则如下:

qop
response
未指定
MD5(HA1:nonce:HA2)
auth或auth-int
MD5(HA1:nonce:nonceCount:cnonce:qop:HA2)

计算结果如下:

 
例1(FreeSwitch充当REG Server)
例2(OpenSIPS充当REG Server)
response

MD5("6a5e40ec8a6cbac75b9914b271516a47:bee3366b-cf59-476e-bc5e-334e0d65b386:00000001:c3606b3f70544096a7e17fcdb4670795:auth:c0a1637fb943febd38e69c2087d58fe9")

=7a8049557b2e77602625fa9ee7d8f088

MD5("109cf921db79c57e146cd8d46429312d:6135e48401ea0109021093850f9c5db2bf101786:9f5c90dad45f8b57a9de5ad977027d7b")

=885f45ae2179c9d8ce2bc1cbd8e4bb9f

qop auth
nonceCount 00000001
nonce bee3366b-cf59-476e-bc5e-334e0d65b386 6135e48401ea0109021093850f9c5db2bf101786
HA2 c0a1637fb943febd38e69c2087d58fe9 9f5c90dad45f8b57a9de5ad977027d7b
HA1 6a5e40ec8a6cbac75b9914b271516a47 109cf921db79c57e146cd8d46429312d
cnonce c3606b3f70544096a7e17fcdb4670795

附1:话机注销过程,其中跟注册过程几乎完全一样,只是Expires值会设置为 0,交互报文如下:

 recv 547 bytes from tcp/[10.32.26.25]:61932 at 09:21:34.274829:
------------------------------------------------------------------------
REGISTER sip:10.32.26.25:5070;transport=tcp SIP/2.0
Via: SIP/2.0/TCP 10.32.26.25:61932;rport;branch=z9hG4bKPj909d767a192f4db1ad491cb466fe9b99;alias
Max-Forwards: 70
From: <sip:1099@10.32.26.25>;tag=c40977782b0d4b87912ff9636fdce333
To: <sip:1099@10.32.26.25>
Call-ID: a08b443e427044e8815ed2e3f1dd51d0
CSeq: 23519 REGISTER
User-Agent: MicroSIP/3.20.3
Supported: outbound, path
Contact: <sip:1099@10.32.26.25:61932;transport=TCP;ob>;reg-id=1;+sip.instance="<urn:uuid:00000000-0000-0000-0000-000011058e7e>"
Expires: 0
Content-Length: 0 ------------------------------------------------------------------------
send 670 bytes to tcp/[10.32.26.25]:61932 at 09:21:34.279829:
------------------------------------------------------------------------
SIP/2.0 401 Unauthorized
Via: SIP/2.0/TCP 10.32.26.25:61932;rport=61932;branch=z9hG4bKPj909d767a192f4db1ad491cb466fe9b99;alias
From: <sip:1099@10.32.26.25>;tag=c40977782b0d4b87912ff9636fdce333
To: <sip:1099@10.32.26.25>;tag=6e3DjUDX76p3N
Call-ID: a08b443e427044e8815ed2e3f1dd51d0
CSeq: 23519 REGISTER
User-Agent: FreeSWITCH-mod_sofia/1.6.18+git~20170612T211449Z~6e79667c0a~64bit
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE
Supported: timer, path, replaces
WWW-Authenticate: Digest realm="10.32.26.25", nonce="7ff40180-f465-465c-8ca1-44c77d2107f4", algorithm=MD5, qop="auth"
Content-Length: 0 ------------------------------------------------------------------------
recv 821 bytes from tcp/[10.32.26.25]:61932 at 09:21:34.279829:
------------------------------------------------------------------------
REGISTER sip:10.32.26.25:5070;transport=tcp SIP/2.0
Via: SIP/2.0/TCP 10.32.26.25:61932;rport;branch=z9hG4bKPj793d3c194cd6461589e44c864e031e52;alias
Max-Forwards: 70
From: <sip:1099@10.32.26.25>;tag=c40977782b0d4b87912ff9636fdce333
To: <sip:1099@10.32.26.25>
Call-ID: a08b443e427044e8815ed2e3f1dd51d0
CSeq: 23520 REGISTER
User-Agent: MicroSIP/3.20.3
Supported: outbound, path
Contact: <sip:1099@10.32.26.25:61932;transport=TCP;ob>;reg-id=1;+sip.instance="<urn:uuid:00000000-0000-0000-0000-000011058e7e>"
Expires: 0
Authorization: Digest username="1099", realm="10.32.26.25", nonce="7ff40180-f465-465c-8ca1-44c77d2107f4", uri="sip:10.32.26.25:5070;transport=tcp", response="92e6ae0a0f23e04d21b0866a7746decd", algorithm=MD5, cnonce="85b6265e67b949aa9c2c7bcc26cad2c9", qop=auth, nc=00000001
Content-Length: 0 ------------------------------------------------------------------------
send 578 bytes to tcp/[10.32.26.25]:61932 at 09:21:34.286827:
------------------------------------------------------------------------
SIP/2.0 200 OK
Via: SIP/2.0/TCP 10.32.26.25:61932;rport=61932;branch=z9hG4bKPj793d3c194cd6461589e44c864e031e52;alias
From: <sip:1099@10.32.26.25>;tag=c40977782b0d4b87912ff9636fdce333
To: <sip:1099@10.32.26.25>;tag=7Qv6Kpy04FDpH
Call-ID: a08b443e427044e8815ed2e3f1dd51d0
CSeq: 23520 REGISTER
Date: Thu, 23 Sep 2021 09:21:34 GMT
User-Agent: FreeSWITCH-mod_sofia/1.6.18+git~20170612T211449Z~6e79667c0a~64bit
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE
Supported: timer, path, replaces
Content-Length: 0 ------------------------------------------------------------------------

  

附2:如果注册过程中,digest校验失败,SIP会返回403,报文如下

recv 647 bytes from tcp/[10.32.26.25]:63125 at 09:26:04.493306:
------------------------------------------------------------------------
REGISTER sip:10.32.26.25:5070;transport=tcp SIP/2.0
Via: SIP/2.0/TCP 10.32.26.25:63125;rport;branch=z9hG4bKPj258fc605159e449ea95e1fdd55b4c16d;alias
Max-Forwards: 70
From: <sip:1099@10.32.26.25>;tag=69516ebac8224d94a7225271fec56f87
To: <sip:1099@10.32.26.25>
Call-ID: 514ac58ec6dd4d8295a62d8f04648c52
CSeq: 25348 REGISTER
User-Agent: MicroSIP/3.20.3
Supported: outbound, path
Contact: <sip:1099@10.32.26.25:63125;transport=TCP;ob>;reg-id=1;+sip.instance="<urn:uuid:00000000-0000-0000-0000-000011058e7e>"
Expires: 300
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Content-Length: 0 ------------------------------------------------------------------------
send 670 bytes to tcp/[10.32.26.25]:63125 at 09:26:04.496305:
------------------------------------------------------------------------
SIP/2.0 401 Unauthorized
Via: SIP/2.0/TCP 10.32.26.25:63125;rport=63125;branch=z9hG4bKPj258fc605159e449ea95e1fdd55b4c16d;alias
From: <sip:1099@10.32.26.25>;tag=69516ebac8224d94a7225271fec56f87
To: <sip:1099@10.32.26.25>;tag=DemUyr3NK5j6p
Call-ID: 514ac58ec6dd4d8295a62d8f04648c52
CSeq: 25348 REGISTER
User-Agent: FreeSWITCH-mod_sofia/1.6.18+git~20170612T211449Z~6e79667c0a~64bit
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE
Supported: timer, path, replaces
WWW-Authenticate: Digest realm="10.32.26.25", nonce="7180f42a-1d76-4a6f-a846-6f9b34f7db4e", algorithm=MD5, qop="auth"
Content-Length: 0 ------------------------------------------------------------------------
recv 921 bytes from tcp/[10.32.26.25]:63125 at 09:26:04.496305:
------------------------------------------------------------------------
REGISTER sip:10.32.26.25:5070;transport=tcp SIP/2.0
Via: SIP/2.0/TCP 10.32.26.25:63125;rport;branch=z9hG4bKPj6727ace0eb4d406cadf969591438a644;alias
Max-Forwards: 70
From: <sip:1099@10.32.26.25>;tag=69516ebac8224d94a7225271fec56f87
To: <sip:1099@10.32.26.25>
Call-ID: 514ac58ec6dd4d8295a62d8f04648c52
CSeq: 25349 REGISTER
User-Agent: MicroSIP/3.20.3
Supported: outbound, path
Contact: <sip:1099@10.32.26.25:63125;transport=TCP;ob>;reg-id=1;+sip.instance="<urn:uuid:00000000-0000-0000-0000-000011058e7e>"
Expires: 300
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Authorization: Digest username="1099", realm="10.32.26.25", nonce="7180f42a-1d76-4a6f-a846-6f9b34f7db4e", uri="sip:10.32.26.25:5070;transport=tcp", response="ba8664d44668c11d030a9436800338e7", algorithm=MD5, cnonce="4c02d90a0bf94ae28a1ecd8cf30b126e", qop=auth, nc=00000001
Content-Length: 0 ------------------------------------------------------------------------
send 548 bytes to tcp/[10.32.26.25]:63125 at 09:26:04.499309:
------------------------------------------------------------------------
SIP/2.0 403 Forbidden
Via: SIP/2.0/TCP 10.32.26.25:63125;rport=63125;branch=z9hG4bKPj6727ace0eb4d406cadf969591438a644;alias
From: <sip:1099@10.32.26.25>;tag=69516ebac8224d94a7225271fec56f87
To: <sip:1099@10.32.26.25>;tag=eQDm0KmSge9rj
Call-ID: 514ac58ec6dd4d8295a62d8f04648c52
CSeq: 25349 REGISTER
User-Agent: FreeSWITCH-mod_sofia/1.6.18+git~20170612T211449Z~6e79667c0a~64bit
Allow: INVITE, ACK, BYE, CANCEL, OPTIONS, MESSAGE, INFO, UPDATE, REGISTER, REFER, NOTIFY, PUBLISH, SUBSCRIBE
Supported: timer, path, replaces
Content-Length: 0 ------------------------------------------------------------------------

  

参考文章:

https://en.wikipedia.org/wiki/Digest_access_authentication

https://datatracker.ietf.org/doc/html/rfc2069

https://datatracker.ietf.org/doc/html/rfc2617

SIP REG Digest认证算法分析的更多相关文章

  1. http 登录Digest认证相关知识

    Digest access authentication https://en.wikipedia.org/wiki/Digest_access_authentication Digest acces ...

  2. sip鉴权认证算法详解及python加密

    1. 认证和加密    认证(Authorization)的作用在于表明自己是谁,即向别人证明自己是谁.而相关的概念是MD5,用于认证安全.注意MD5仅仅是个hash函数而已,并不是用于加密.因为ha ...

  3. 批量检测GoAhead系列服务器中Digest认证方式的服务器弱口令

    最近在学习用python写爬虫工具,某天偶然发现GoAhead系列服务器的登录方式跟大多数网站不一样,不是采用POST等方法,通过查找资料发现GoAhead是一个开源(商业许可).简单.轻巧.功能强大 ...

  4. HTTP Basic和Digest认证介绍与计算

    一.说明 web用户认证,最开始是get提交+把用户名密码存放在客户端的cookie中的形式:在意识到这样不安全之后逐渐演变成了post提交+把用户凭证放到了服务端的session中的形式(当然ses ...

  5. 【ASP.NET Web API2】Digest认证

    Digest摘要认证 对于Basic认证方案来说,被传输的认证凭证仅仅采用Base64编码,所以包含密码的认证凭证基本上可以视为明文传输.Digest认证在此基础上进行了改善,在一定程度上提高了安全系 ...

  6. Http Digest认证协议

    转自:http://blog.csdn.net/htjoy1202/article/details/7067287 其认证的基本框架为挑战认证的结构,如下图所示: 1.客户端希望取到服务器上的某个资源 ...

  7. SIP 认证

    理解SIP的认证 1. 认证和加密    认证(Authorization)的作用在于表明自己是谁,即向别人证明自己是谁.而相关的概念是MD5,用于认证安全.注意MD5仅仅是个hash函数而已,并不是 ...

  8. SIP 认证方式

    SIP认证是继承了HTTP的认证方式.HTTP的认证方案主要有Basic Authentication Scheme和Digest Access Authentication Scheme两种.而Ba ...

  9. Digest Authentication 摘要认证

    “摘要”式认证( Digest authentication)是一个简单的认证机制,最初是为HTTP协议开发的,因而也常叫做HTTP摘要,在RFC2671中描述.其身份验证机制很简单,它采用杂凑式(h ...

  10. sip 认证分析

    转自:http://blog.csdn.net/wangqi0079/article/details/11569489 SIP类似Http协议.其认证模式也一样.Http协议(RFC 2616 )规定 ...

随机推荐

  1. SpringCloud——网关过滤工厂GatewayFilterFactory

    目录 GatewayFilter 工厂 AddRequestHeader AddRequestHeadersIfNotPresent AddRequestParameter AddResponseHe ...

  2. SQL 日常练习 (二十)

    也只是尽快搬完这快一个月 sql 的砖, 准备要来整新学习模块了, 因此, 正好趁着五一, 加波速. 也会一直坚守和追求, 学无止境, 气有浩然. 每次都会说, 这是一种精神的传承,而我想的是, 不仅 ...

  3. Polarctf -- Re(1)

    Polarctf之简单逆向 1. shell 用exeinfope查看下程序结构, 发现存在upx壳 用upx工具脱壳, upx.exe -d shell.exe 再使用IDAPro打开 #flag{ ...

  4. 使用torch pruning工具进行结构化剪枝

    网络结构定义 import torch import torch.nn as nn import torch.nn.functional as F import torch_pruning as tp ...

  5. 使用 C++ 20 协程降低异步网络编程复杂度

    传统异步回调 vs C++20协程 协程是一种函数对象,可以设置锚点做暂停,然后再该锚点恢复继续运行.它是如何应用在网络异步编程方面的,请对比下面的两种代码风格: 基于回调的异步网络编程 先来看一个异 ...

  6. SpringBoot3整合SpringSecurity6(五)自定义登陆页面

    大家好,我是晓凡 写在前面 在前面的文章中,我们学习了SpringSecurity 登录认证流程,对其应该有个大概印象了. 忘记的小伙伴点击下面自己复习去~ 在前面的学习中,我们使用的都是Spring ...

  7. RBMQ案例五:主题模式

    在之前的教程中,我们改进了日志系统.我们没有使用只能进行虚拟广播的扇出交换器,而是使用了直接交换器,并获得了选择性接收日志的可能性. 虽然使用直接交换改进了我们的系统,但它仍然有局限性--它不能基于多 ...

  8. Django Web应用开发实战第一章

    一.常见域名后缀 .com:商业性的机构或公司. .net:从事Internet相关的网络服务的机构或公司. .org:非营利的组织.团体. .gov:政府部门. .cn:中国国内域名. .com.c ...

  9. Visual Studio 17.3

    Visual Studio 2022 17.3新UI

  10. 导航栏激活态下划线效果的CSS实现

    一.鼠标移入效果图如下: 二.div结构 <div class="navbar"> <ul> <li>首页</li> </ul ...