ASP.NET Core Web API之Token验证
在实际开发中,源码数据安全是源码关键,对外提供接口时,源码验证客户身份是源码诱导消费源码必要步骤。本文以ASP.NET Core Web API为例,源码介绍一种常用的源码JWT身份验证方式。JWT,源码全称JSON Web Token,源码是源码一种基于JSON的令牌,用于声明网络上的源码某种主张。
JWT由三部分组成:头信息、源码连板金钻源码消息体和签名。源码头信息描述令牌的源码类型和算法,消息体包含用户信息,源码签名确保信息传输的源码安全性。
在分布式部署环境中,代码圣诞树源码JWT应用广泛。以下步骤演示如何在ASP.NET Core Web API中使用JWT进行身份验证:
1. 安装JwtBearer:使用Nuget包管理器安装Microsoft.AspNetCore.Authentication.JwtBearer。
2. 添加JWT身份验证服务:在Program.cs启动类中配置。
3. 应用鉴权授权中间件:同样在Program.cs中添加鉴权中间件。
4. 配置Swagger身份验证(可选):在配置Swagger服务时,jsp网上鞋城源码可选择输入身份验证方式,方便测试。
5. 创建JWT帮助类:用于生成Token,包括配置Token验证参数。
6. 创建Token获取接口:实现AuthController/GetToken方法,Unity怪物AI实现源码提供获取Token功能。
7. 创建测试接口:实现测试接口,用于验证Token的效用。
在接口测试中,通过执行API端点,获取Token并设置到请求头中,再调用测试接口以验证Token有效性。若移除Token验证配置,尝试访问测试接口时会收到未授权信息。
至此,ASP.NET Core Web API中的Token验证流程完成。为了方便交流,加入技术群或关注公众号,请通过指定方式联系。
ASP.NET Core认è¯åçåå®ç°
é常å¨åºç¨ç¨åºä¸ï¼å®å ¨å为åå两个æ¥éª¤ï¼éªè¯åææãéªè¯è´è´£æ£æ¥å½å请æ±è ç身份ï¼èææåæ ¹æ®ä¸ä¸æ¥å¾å°ç身份å³å®å½å请æ±è æ¯å¦è½å¤è®¿é®ææçèµæºã
æ¢ç¶å®å ¨ä»éªè¯å¼å§ï¼æ们ä¹å°±ä»éªè¯å¼å§ä»ç»å®å ¨ã
æ们å ä»æ¯è¾ç®åçåºæ¯å¼å§èèï¼ä¾å¦å¨ Web API å¼åä¸ï¼éè¦éªè¯è¯·æ±æ¹æ¯å¦æä¾äºå®å ¨ä»¤çï¼å®å ¨ä»¤çæ¯å¦ææãå¦ææ æï¼é£ä¹ API 端åºè¯¥æç»æä¾æå¡ãå¨å½åç©ºé´ Microsoft.AspNetCore.Authentication ä¸ï¼å®ä¹å ³äºéªè¯çæ ¸å¿æ¥å£ã对åºçç¨åºéæ¯ Microsoft.AspNetCore.Authentication.Abstractions.dllã
å¨ ASP.NET ä¸ï¼éªè¯ä¸å å« 3 个åºæ¬æä½ï¼
éªè¯æä½è´è´£åºäºå½å请æ±çä¸ä¸æï¼ä½¿ç¨æ¥èªè¯·æ±ä¸çä¿¡æ¯ï¼ä¾å¦è¯·æ±å¤´ãCookie ççæ¥æé ç¨æ·æ è¯ãæ建çç»ææ¯ä¸ä¸ª AuthenticateResult 对象ï¼å®æ示äºéªè¯æ¯å¦æåï¼å¦ææåçè¯ï¼ç¨æ·æ è¯å°å¯ä»¥å¨éªè¯ç¥¨æ®ä¸æ¾å°ã
常è§çéªè¯å æ¬ï¼
å¨ææ管çé¶æ®µï¼å¦æç¨æ·æ²¡æå¾å°éªè¯ï¼ä½æææ访é®çèµæºè¦æ±å¿ é¡»å¾å°éªè¯çæ¶åï¼æææå¡ä¼ååºè´¨è¯¢ãä¾å¦ï¼å½å¿åç¨æ·è®¿é®åéèµæºçæ¶åï¼æè å½ç¨æ·ç¹å»ç»å½é¾æ¥çæ¶åãæææå¡ä¼éè¿è´¨è¯¢æ¥ç¸åºç¨æ·ã
ä¾å¦
质询æä½åºè¯¥è®©ç¨æ·ç¥éåºè¯¥ä½¿ç¨ä½ç§éªè¯æºå¶æ¥è®¿é®è¯·æ±çèµæºã
å¨ææ管çé¶æ®µï¼å¦æç¨æ·å·²ç»éè¿äºéªè¯ï¼ä½æ¯å¯¹äºå ¶è®¿é®çèµæºå¹¶æ²¡æå¾å°è®¸å¯ï¼æ¤æ¶ä¼ä½¿ç¨æç»æä½ã
ä¾å¦ï¼
æç»è®¿é®å¤çåºè¯¥è®©ç¨æ·ç¥éï¼
å¨è¿ä¸ªåºæ¯ä¸ï¼å¯ä»¥çå°ï¼éªè¯éè¦æä¾çåºæ¬åè½å°±å æ¬äºéªè¯åéªè¯å¤±è´¥åçæç»æå¡ä¸¤ä¸ªæä½ãå¨ ASP.NET Core ä¸ï¼éªè¯è¢«ç§°ä¸º Authenticateï¼æç»è¢«ç§°ä¸º Forbidã å¨ä¾æ¶è´¹è 访é®çç½ç«ä¸ï¼å¦ææ们å¸æå¨éªè¯å¤±è´¥åï¼ä¸æ¯å API ä¸æ ·ç´æ¥è¿åä¸ä¸ªé误页é¢ï¼èæ¯å°ç¨æ·å¯¼èªå°ç»å½é¡µé¢ï¼é£ä¹ï¼å°±è¿éè¦å¢å ä¸ä¸ªæä½ï¼è¿ä¸ªæä½çæ¬è´¨æ¯å¸æç¨æ·å次æä¾å®å ¨åæ®ï¼å¨ ASP.NET Core ä¸ï¼è¿ä¸ªæä½è¢«ç§°ä¸º Challengeãè¿ 3 个æä½ç»åå¨ä¸èµ·ï¼å°±æ¯éªè¯æåºæ¬çè¦æ±ï¼ä»¥æ¥å£å½¢å¼è¡¨ç¤ºï¼å°±æ¯ IAuthenticationHandler æ¥å£ï¼å¦ä¸æ示ï¼
éªè¯çç»ææ¯ä¸ä¸ª AuthenticateResult 对象ãå¼å¾æ³¨æçæ¯ï¼å®è¿æä¾äºä¸ä¸ªéææ¹æ³ NoResult() ç¨æ¥è¿å没æå¾å°ç»æï¼éææ¹æ³ Fail() çæä¸ä¸ªè¡¨ç¤ºéªè¯å¼å¸¸çç»æï¼è Success() æååéè¦æä¾éªè¯ç¥¨æ®ã
éè¿éªè¯ä¹åï¼ä¼è¿åä¸ä¸ªå å«äºè¯·æ±è 票æ®çéªè¯ç»æã
å¨ GitHub ä¸æ¥ç AuthenticateResult æºç
é£ä¹éªè¯çä¿¡æ¯æ¥èªåªéå¢ï¼é¤äºåé¢ä»ç»ç 3 个æä½ä¹å¤ï¼è¿è¦æ±ä¸ä¸ªåå§åçæä½ Initializeï¼éè¿è¿ä¸ªæ¹æ³æ¥æä¾å½å请æ±çä¸ä¸æä¿¡æ¯ã
å¨ GitHub ä¸æ¥ç IAuthenticationHandler å®ä¹
æçæ¶åï¼æ们è¿å¸ææä¾ç»åºæä½ï¼å¢å ç»åºæä½çæ¥å£è¢«ç§°ä¸º IAuthenticationSignOutHandlerã
å¨ GitHub ä¸æ¥ç IAuthenticationSignOutHandler æºç
å¨ç»åºçåºç¡ä¸ï¼å¦æè¿å¸ææä¾ç»å½æä½ï¼é£ä¹å°±æ¯ IAuthenticationSignInHandler æ¥å£ã
å¨ GitHub ä¸æ¥ç IAuthenticationSignInHandler æºç
ç´æ¥å®ç°æ¥å£è¿æ¯æ¯è¾éº»ç¦çï¼å¨å½åç©ºé´ Microsoft.AspNetCore.Authentication ä¸ï¼å¾®è½¯æä¾äºæ½è±¡åºç±» AuthenticationHandler 以æ¹ä¾¿éªè¯æ§å¶å¨çå¼åï¼å ¶å®æ§å¶å¨å¯ä»¥ä»è¯¥æ§å¶å¨æ´¾çï¼ä»¥åå¾å ¶æä¾çæå¡ã
éè¿ç±»çå®ä¹å¯ä»¥çå°ï¼å®ä½¿ç¨äºæ³åãæ¯ä¸ªæ§å¶å¨åºè¯¥æä¸ä¸ªå¯¹åºè¯¥æ§å¶å¨çé ç½®é项ï¼éè¿æ³åæ¥æå®éªè¯å¤çå¨æ使ç¨çé 置类åï¼å¨æé å½æ°ä¸ï¼å¯ä»¥çå°å®è¢«ç¨äºè·å对åºçé ç½®é项对象ã
å¨ GitHub ä¸æ¥ç AuthenticationHandler æºç
éè¿ InitializeAsync()ï¼éªè¯å¤çå¨å¯ä»¥è·å¾å½å请æ±çä¸ä¸æ对象 HttpContextã
æç»ï¼ä½ä¸ºæ½è±¡ç±»ç ï¼å¸ææ´¾çç±»æ¥å®æè¿ä¸ªéªè¯ä»»å¡ï¼æ½è±¡æ¹æ³ HandleAuthenticateAsync() æä¾äºæ©å±ç¹ã
éªè¯çç»ææ¯ä¸ä¸ª AuthenticateResultã
èæç»æå¡åç®åçå¤ï¼ç´æ¥å¨è¿ä¸ªæ½è±¡åºç±»ä¸æä¾äºé»è®¤å®ç°ãç´æ¥è¿å HTTP ã
å©ä¸çä¸ä¸ªä¹ä¸æ ·ï¼æä¾äºé»è®¤å®ç°ãç´æ¥è¿å HTTP ååºã
å¯¹äº JWT æ¥è¯´ï¼å¹¶ä¸æ¶åå°ç»å ¥åç»åºï¼æ以å®éè¦ä»å®ç° IAuthenticationHandler æ¥å£çæ½è±¡åºç±» AuthenticationHandler æ´¾çåºæ¥å³å¯ãä» AuthenticationHandler æ´¾çåºæ¥ç JwtBearerHandler å®ç°åºäºèªå·±çé ç½®é项 JwtBearerOptionsãæ以该类å®ä¹å°±åå¾å¦ä¸æ示ï¼èæé å½æ°æ¾ç¶é åäºæ½è±¡åºç±»çè¦æ±ã
å¨ GitHub ä¸æ¥ç JwtBearerHandler æºç
çæ£çéªè¯åå¨ HandleAuthenticateAsync() ä¸å®ç°ãä¸é¢ç代ç æ¯ä¸æ¯å°±å¾çæäºï¼ä»è¯·æ±å¤´ä¸è·åé带ç JWT 访é®ä»¤çï¼ç¶åéªè¯è¯¥ä»¤ççæææ§ï¼æ ¸å¿ä»£ç å¦ä¸æ示ã
å¨ GitHub ä¸æ¥ç JwtBearerHandler æºç
å¨ ASP.NET Core ä¸ï¼ä½ å¯ä»¥ä½¿ç¨åç§éªè¯å¤çå¨ï¼å¹¶ä¸ä» ä» åªè½ä½¿ç¨ä¸ä¸ªï¼éªè¯æ§å¶å¨éè¦ä¸ä¸ªå称ï¼å®è¢«çä½è¯¥éªè¯æ¨¡å¼ Schema çå称ãJwt éªè¯æ¨¡å¼çé»è®¤åç§°å°±æ¯ "Bearer"ï¼éè¿å符串常é JwtBearerDefaults.AuthenticationScheme å®ä¹ã
å¨ GitHub ä¸æ¥ç JwtBearerDefaults æºç
æç»éè¿ AuthenticationBuilder çæ©å±æ¹æ³ AddJwtBearer() å° Jwt éªè¯æ§å¶å¨æ³¨åå°ä¾èµæ³¨å ¥ç容å¨ä¸ã
å¨ GitHub ä¸æ¥ç JwtBearerExtensions æ©å±æ¹æ³æºç
ä¸ç§éªè¯å¤çå¨ï¼å ä¸å¯¹åºçéªè¯é ç½®é项ï¼æ们å为å®èµ·ä¸ä¸ªååï¼ç»åèµ·æ¥å°±æ为ä¸ç§éªè¯æ¶æ Schemaãå¨ ASP.NET Core ä¸ï¼å¯ä»¥æ³¨åå¤ç§éªè¯æ¶æãä¾å¦ï¼ææçç¥å¯ä»¥ä½¿ç¨æ¶æçå称æ¥æå®æ使ç¨çéªè¯æ¶ææ¥ä½¿ç¨ç¹å®çéªè¯æ¹å¼ãå¨é ç½®éªè¯çæ¶åï¼é常设置é»è®¤çéªè¯æ¶æãå½æ²¡ææå®éªè¯æ¶æçæ¶åï¼å°±ä¼ä½¿ç¨é»è®¤æ¶æè¿è¡å¤çã
è¿å¯ä»¥
注åçéªè¯æ¨¡å¼ï¼æç»åæ AuthenticationSchemeï¼æ³¨åå°ä¾èµæ³¨å ¥æå¡ä¸ã
å¨ GitHub ä¸æ¥ç AuthenticationScheme æºç
åç§éªè¯æ¶æ被ä¿åå°ä¸ä¸ª IAuthenticationSchemeProvider ä¸ã
å¨ GitHub ä¸æ¥ç IAuthenticationSchemeProvider æºç
æç»ç使ç¨æ¯éè¿ IAuthenticationHandlerProvider æ¥å®ç°çï¼éè¿ä¸ä¸ªéªè¯æ¨¡å¼çå符串å称ï¼å¯ä»¥åå¾æ对åºçéªè¯æ§å¶å¨ã
å¨ GitHub ä¸æ¥ç IAuthenticationHandlerProvider æºç
å®çé»è®¤å®ç°æ¯ AuthenticationHandlerProviderï¼æºç 并ä¸å¤æã
å¨ GitHub ä¸æ¥ç AuthenticationHandlerProvider æºç
éªè¯ä¸é´ä»¶çå¤ç就没æé£ä¹å¤æäºã
æ¾å°é»è®¤çéªè¯æ¨¡å¼ï¼ä½¿ç¨é»è®¤éªè¯æ¨¡å¼çå称åå¾å¯¹åºçéªè¯å¤çå¨ï¼å¦æéªè¯æåçè¯ï¼æå½å请æ±ç¨æ·ç主ä½æ¾å°å½å请æ±ä¸ä¸æç User ä¸ã
éé¢è¿æä¸æ®µç¹å«ç代ç ï¼ç¨æ¥æ¾åºåªäºéªè¯å¤çå¨å®ç°äº IAuthenticationHandlerProviderï¼å¹¶ä¾æ¬¡è°ç¨å®ä»¬ï¼ççæ¯å¦éè¦æåç»æ¢è¯·æ±å¤çè¿ç¨ã
å¨ GitHub ä¸æ¥ç AuthenticationMiddle æºç
å¼è¿ä½ä»£ç å¦ä½
å¼è¿ä½ä»£ç å¦ä½ï¼æä¹æ ·ï¼å¥½ä¸å¥½ç¨ï¼ä¸é¢è¯´è¯´ä¸ªäººæäºè§£çã
å¼è¿ä½ä»£ç ï¼å称为JNPFï¼å ¶å身æ¯ä¸å®¶å¿«éå¼åå¹³å°ï¼åé¢éæ¸è½¬åæ为ä½ä»£ç 产åãç±ç¦å»ºå¼è¿ä¿¡æ¯ææ¯æéå ¬å¸ç åèæï¼è¯¥å ¬å¸æç«äºå¹´ï¼æ³å®ä»£è¡¨äººä½èµéï¼æ³¨åèµæ¬ä¸ï¼äººåè§æ¨¡äººãæ¯ä¸æ¬¾åºäºä»£ç çæå¨çä½ä»£ç å¼åå¹³å°ï¼æçè§èçå¼åæµç¨åçµæ´»çä¸å¡é»è¾ãéç¨çææ¯æ2ç§ï¼ä¸ç§æ¯NETCoreï¼ä¸ç§æ¯JAVAå¼åï¼æ¥æå¯è§åå¼åç¯å¢ï¼ææ½å¼å¿«é设计表åï¼PCãPadãææºç«¯éé ï¼æéé ç½®ãSaaSæå¡ï¼æ¥å£å¯¹æ¥ï¼å·¥ä½æµå¼æï¼å¤ç«¯ä½¿ç¨WebãAndroidãIOSã微信å°ç¨åºï¼å¹¶ä¸æ以æ建ä¸å¡æµç¨ãé»è¾åæ°æ®æ¨¡åçæéçåè½ã为ä¼ä¸é¡¹ç®èçé¨åéå¤å·¥ä½ï¼è®©å¼åè å°éå¿æ¾å¨ä¸å¡é»è¾ï¼ä¸å¿ ç¦æ¼åºå±æ¶æ设计ã
å¼è¿ä½ä»£ç åè½ï¼
1ãé¶ä»£ç å¼åï¼æ é代ç ï¼ææ½å¼æä½ï¼èªå¨çæå¯è§ååºç¨ï¼çµæ´»æ建ä¸å¡ç®¡çç³»ç»ï¼å å¿«ä¸å¡é¨ç½²ã
2ãä½ä»£ç å¼åï¼åºäºä»£ç çæå¨ï¼ä»£ç èªå¨çæåå¯ä»¥ä¸è½½æ¬å°ï¼è¿è¡äºæ¬¡å¼åï¼æææé«æ´ä½å¼åæçã
3ãæ¥è¡¨å¯è§åï¼æä½çé¢å¯è§åï¼éè¿ç®æé ç½®å³å¯èªå¨çæåç§ç±»åçæ¥è¡¨ï¼ä¸ºä¼ä¸èç大éçéå¤å¼åå·¥ä½ã
4ã大å±å¯è§åï¼ä¸°å¯ç交äºæ§ä»¶åå¾è¡¨ç»ä»¶ï¼æä¾æºè½å¾å½¢æ¨èï¼æ¥è¡¨å¾å½¢ä»»æåæ¢ï¼ä¸ä¸å维度ã度éçéå¶ã
5ãå·¥ä½æµå¼æï¼å®ç°äºçé¢åæµç¨ç建模ï¼ä½¿å¾æµç¨è®¾è®¡åå¾ç®ååå¯æä½ï¼ç¨æ·éè¿æãæãç¹ãæ½å³å¯å¿«éå®ç°æµç¨è®¾è®¡ã
6ã移å¨ç«¯APPï¼ç§»å¨ç«¯æ°æ®æéï¼å¯ä¸é®åå¸å°APPãå°ç¨åºãH5ç移å¨å¹³å°ä¸ï¼å®ç°äºèäºéãé«æåå ¬ã
å¼è¿ä½ä»£ç ç¹ç¹ï¼
1ãææ¯åå¼æï¼éç¨.NET/JAVAææ¯
2ãå ¨æºç 交ä»ï¼å¯äºæ¬¡å¼åçå ¨æºç 交ä»
3ãéä½é¡¹ç®ææ¬ï¼%åºç¡ä»£ç æ éç¼å
4ãè·å¾åä¸ææï¼ä¿æ¤å®¢æ·çåæ³æç
5ãæé«å¼åæçï¼åºç¡åè½æ éå¼å
å¼è¿ä½ä»£ç ææ¯æ ï¼
主æ¡æ¶ï¼Spring Boot + Spring Frameworkãæä¹ å±æ¡æ¶ï¼Mybatis-plusãHibernate ValidationãAlibaba DruidãJSONåºåå: Jacksonã
æ°æ®ç¼åï¼Redisã项ç®æ建ï¼Mavenãå®å ¨æ¡æ¶ï¼Spring Security Oauth2+JWTã模æ¿å¼æï¼Velocityãå³æ¶é讯ï¼spring-boot-starter-websocketãAOP: spring-boot-starter-aopçã
æ¡é¢æä½ç³»ç»ï¼
Windows 7+ãMacOSãUbuntu Desktop(æ¡é¢ç)ãDeepin(深度æä½ç³»ç»)ãç»ä¿¡UOSæ¡é¢(ä¸ä¸)çãä¸æ éºéºæ¡é¢çãä¸ç§æ¹å¾·æ¡é¢ççã
å½å è¿æåªäºå¥½ç¨çä½ä»£ç å¼åå¹³å°ï¼
æè¿éçä½ä»£ç ççç«ï¼å½å å·²ç»åºç°äºå¾å¤ä½ä»£ç å¼åå¹³å°ï¼èä¸JNPFä½ä»£ç 产å类似çä½ä»£ç å¹³å°ï¼å½å ä¹æå¾å¤ï¼æ¯å¦ï¼ééå®æãå为åºç¨éæ¹ãç±éæãClickPaaSãç»ä¿¡Informatçã
ä»æ°æ®å®å ¨è§åº¦èèï¼è¿æ¯ç§æåé¨ç½²çä½ä»£ç å¹³å°æ´é è°±ï¼æ¯å¦ç»ä¿¡Informatä¼ä¸çº§ä½ä»£ç å¹³å°ï¼å¯ä»¥æ»¡è¶³ç¨æ·æ´å¤å®å¶åéæ±ï¼åæ¶æ°æ®æ´å®å ¨ãç§æåé¨ç½²å¯ä»¥ä¸ºä¼ä¸å¸¦æ¥å¾å¤å¢çï¼
1ãå®å¶å¼å
ç§æåé¨ç½²å¯ä»¥æ ¹æ®å®¢æ·èªå·±çéæ±åæ åµï¼å®å¶ä½¿ç¨åè½ãä¸åè¡ä¸ãä¸åç±»åçä¼ä¸ç¨æ·å¯¹è½¯ä»¶éæ±æ¯ä¸ä¸æ ·çï¼éç¨è½¯ä»¶å¹¶ä¸è½æ»¡è¶³ä¸åç±»åç管çéæ±ãè对äºä¸ä¸ªä¼ä¸æ¥è¯´ï¼æå¤çåå±é¶æ®µä¸ä¸æ ·ï¼å°±åå¨äºä¸ä¸æ ·ç管çéæ±ãå¾å¤ä¼ä¸å¯¹è½¯ä»¶æäºä¸ªæ§åå®å¶çéæ±ï¼éè¦å¼åä¸å±åè½ï¼ç§æåé¨ç½²å¹³å°å¯ä»¥æ´å¥½å°æ»¡è¶³è¿ç±»éæ±ã
2ãæ°æ®å®å ¨
ä¸äºå¯¹æ°æ®ææçè¡ä¸ï¼æ¯å¦æ¿ä¼åä½ãéèãåå·¥çè¡ä¸ï¼æ 论æ¯å¤å æ°æ®åå¨è¿æ¯ä½¿ç¨æµè¡çäºè®¡ç®SaaSåºç¨ç¨åºï¼é½å°ä½¿ä¼ä¸æ°æ®çå®å ¨æ§åéå¯æ§é¾ä»¥ä¿è¯ï¼ç»ä¼ä¸å¸¦æ¥æ æ³é¢æçé£é©ï¼ç§æåé¨ç½²å¹³å°æ´å®å ¨ã
3ã对æ¥å·²æç³»ç»
ä¼ä¸ç³»ç»éç使ç¨æ¶é´è¶é¿ãå¤ææ§è¶é«ï¼è°æ´ä¼åè½åè¶æ¥è¶å·®ï¼ä½ä¼ä¸åä¸æ³éæ°æ´ä½å¼å以è´äºå½¢æåµå±ï¼å¯¹æ¤ï¼å¯ç§æåé¨ç½²çä½ä»£ç å¼åå¹³å°å¯ä»¥å©ç¨å¼æ¾çæ¥å£å°æ°ç³»ç»éæå°ä¼ä¸å·²æç³»ç»ä¸ï¼ä»¥æå°çè°æ´ææ¬å®ç°å¯¹åæç³»ç»æ¹é å级ãåæ¶ï¼ç§æåé¨ç½²çå¹³å°æå±æ§å¼ºï¼å¯å¨åæåè½ä¸äºæ¬¡å¼åè¿è¡èªä¸»å级ï¼è®©äº§åæ´å¥½çæå¡äºä¼ä¸ï¼å»¶é¿è½¯ä»¶ä½¿ç¨å¯¿å½ã
2024-12-23 23:52
2024-12-23 23:36
2024-12-23 23:24
2024-12-23 23:10
2024-12-23 22:43