日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

從事互聯(lián)網(wǎng)開發(fā)的同學(xué)們應(yīng)該或多或少聽說過 OAuth2.0 協(xié)議,例如使用微信或支付寶賬戶登錄第三方App,這是 OAuth2.0 最為開發(fā)人員所熟知的一個用途,但是圍繞著 OAuth2.0 協(xié)議其實(shí)還有很多有意思的內(nèi)容可以挖掘,我們可以用它以及它的擴(kuò)展協(xié)議來做許多有用的東西。因此我打算寫一個系列來詳細(xì)介紹 OAuth2.0 以及圍繞它所產(chǎn)生的一些擴(kuò)展協(xié)議和優(yōu)良實(shí)踐。

如果你正想要設(shè)計一個基于 OAuth2.0 協(xié)議的授權(quán)服務(wù)架構(gòu)來對外提供一些資源或服務(wù),那么本系列文章將有助于你實(shí)現(xiàn)這一目標(biāo)。

本文是本系列的第一篇,我會比較詳細(xì)地帶你解讀 OAuth2.0 協(xié)議。本文會從基礎(chǔ)概念和術(shù)語開始講起,讓你逐漸了解 OAuth2.0 的核心理念以及它所要解決的問題,然后將會用一多半的篇幅來詳細(xì)闡述4大流程模式中使用最廣的授權(quán)碼模式,我會介紹它的流程、接口、錯誤處理、注意事項等。

注:本文涉及到 OAuth2.0 協(xié)議的所有內(nèi)容全部來自于 RFC 6749 The OAuth 2.0 Authorization Framework ,也就是說全部都是第一手的解讀。

什么是授權(quán)、授權(quán)認(rèn)證、資源外放?

什么是授權(quán)?要解釋這個問題,先要引入一個概念——資源。信息或者數(shù)據(jù)就是一種資源,例如用戶的身份信息、用戶的相冊數(shù)據(jù)、評論記錄、收藏的網(wǎng)站等等,除了信息或數(shù)據(jù)之外,完成某項特定操作的能力也是一種資源,通常以API的形式出現(xiàn),例如發(fā)送短信、上傳頭像、發(fā)布vlog等等,這些都是API也是資源。有些資源需要用戶的授權(quán)(如獲得用戶身份信息),而另一些資源不需要得到用戶的授權(quán)(如發(fā)送短信),我們今天所討論的,是需要用戶授權(quán)的那一類——畢竟這些資源的所有權(quán)屬于用戶。

在什么時候需要授權(quán)呢?我們來假設(shè)一個場景,我們大部分開發(fā)者都有Github賬號(假裝大家都有),但是由于某些原因,Github以前并不提供移動版的官方客戶端,但廣大群眾需要在移動端使用Github的呼聲很強(qiáng)烈,這怎么辦呢?Github的做法是,雖然我不提供官方的app,但是我提供用于管理用戶資源的APIs,這些APIs包含了用戶認(rèn)證信息(user)、倉庫(repositories)、訂閱者(followers)、已訂閱(following)、星標(biāo)(starred)記錄等等幾乎全部的數(shù)據(jù),這樣就可以吸引那些熱心的開發(fā)者為他編寫非官方的客戶端程序,或者其它有用的應(yīng)用。那么是不是所有人或程序都能毫無限制的去使用這些 APIs 呢?顯然是不可以的,那么Github就需要通過某種機(jī)制來保護(hù)這些APIs,使得調(diào)用者必須要在用戶的允許(consent)之下才能夠進(jìn)行調(diào)用。那么授權(quán)的含義就很容易理解了——即調(diào)用者(client)獲取用戶的“允許”以訪問用戶的數(shù)據(jù)的過程就稱為“授權(quán)”。

我們現(xiàn)在明白什么是授權(quán)了,那么授權(quán)認(rèn)證是什么意思呢?授權(quán)認(rèn)證其實(shí)就是授權(quán)當(dāng)中的一類特殊情況,即調(diào)用者(client)所要申請訪問的資源屬于用戶身份信息(或稱為認(rèn)證信息)且調(diào)用者(client)使用此資源的目的在于幫助其(client)對用戶進(jìn)行認(rèn)證時,這種特殊的授權(quán)行為又稱為授權(quán)認(rèn)證。

什么是資源外放?在上文中,Github網(wǎng)站提供了用于訪問用戶數(shù)據(jù)的API的行為就屬于資源外放。資源外放通常要搭配授權(quán)協(xié)議一起實(shí)施。


什么是授權(quán)協(xié)議、OAuth2.0?

什么是協(xié)議?協(xié)議就是標(biāo)準(zhǔn),就是一套規(guī)則體系。上文中,用于規(guī)定授權(quán)操作的流程、接口、錯誤處理方式等等規(guī)則的集合,就是一個授權(quán)協(xié)議。目前互聯(lián)網(wǎng)上使用最廣的授權(quán)協(xié)議是OAuth2.0。

OAuth2.0是由IETF(互聯(lián)網(wǎng)工程小組)編纂并維護(hù)的一套授權(quán)協(xié)議,是目前業(yè)界的事實(shí)標(biāo)準(zhǔn)。

國內(nèi)的微信、支付寶,國外的微軟、谷歌等等巨頭,都采用了此協(xié)議來對外提供API資源。

在這里我有必要強(qiáng)調(diào)一點(diǎn),OAuth2.0 并不是一個認(rèn)證協(xié)議,它不是被設(shè)計為解決認(rèn)證問題的,如果你希望設(shè)計一個認(rèn)證架構(gòu),那么你應(yīng)該考慮 OpenID Connect (OIDC) 協(xié)議,它是 OAuth2.0 的衍生協(xié)議,由 OpenID 發(fā)起并維護(hù),目前已得到很多大型互聯(lián)網(wǎng)公司的支持,例如谷歌、微軟、蘋果、亞馬遜。而如果你要學(xué)習(xí) OIDC 協(xié)議,那么我建議你也應(yīng)該從 OAuth2.0 協(xié)議開始。

OAuth2.0 關(guān)鍵概念和術(shù)語

從這一段開始,我們來正式講解 OAuth2 協(xié)議,首先來介紹一下此協(xié)議有哪些重要的概念或術(shù)語。

Resource Owner

資源擁有者,即用戶

Resource Server

資源服務(wù)器,即存儲用戶資源的服務(wù)器,通常以 API 的形式暴露服務(wù),它會在驗證 Access Token 通過后為調(diào)用者提供用戶資源

Client

客戶端,即申請用戶授權(quán)的主體,可以是前端程序 —— 如 JAVAScript 應(yīng)用、移動端原生 App 等等,也可以是服務(wù)器端應(yīng)用程序 —— 如 Java 程序

Authorization Server

授權(quán)服務(wù)器(簽發(fā)授權(quán)碼和訪問令牌)

Access Token

訪問令牌,拿到此令牌即可訪問 Resource Server 中的用戶資源

Refresh Token

刷新令牌,用來獲得新的 Access Token ,有時 Authorization Server 會在簽發(fā) Access Token 的同時也附加一個 Refresh Token ,這樣 Client 就不必每次都去詢問用戶獲得授權(quán)了

Client Type

客戶端類型,分為 Public 和 Confidential 兩種

Client Identifier

客戶端標(biāo)識,即 client_id ,唯一標(biāo)識一個 Client

Client Authentication

客戶端認(rèn)證,對 Public 類型的 Client 采用 PKCE 的方式認(rèn)證,而對 Confidential 類型的 Client 一般會采用 Basic 方式或基于非對稱算法的 JWT 方式來進(jìn)行認(rèn)證。

OAuth2.0 基本流程

盡管網(wǎng)絡(luò)上很多作者都會直接開始講解授權(quán)碼模式的流程圖,但我認(rèn)為還是有必要先了解 OAuth2.0 最最基本的抽象流程圖,它是所有具體流程模式的抽象概括版,可以讓我們跳出具體的流程模式并站在一定高度上來審視 OAuth2.0 協(xié)議究竟是什么,解決了哪些問題,對于你理解一些關(guān)于 OAuth2.0 的誤區(qū)是有幫助的,如下圖:

你真的理解OAuth2.0協(xié)議嗎?深入解讀OAuth2.0協(xié)議

OAuth2.0 抽象流程圖

圖片來自 RFC6749 - The OAuth 2.0 Authorization Framework

上圖展現(xiàn)了 OAuth2.0 協(xié)議的本質(zhì),它概括為3個步驟:申請授權(quán)、獲得授權(quán)、訪問資源。 OAuth2.0 的所有流程模式(除了早先的四大模式之外還有谷歌的設(shè)備碼模式)都是這3個步驟的具體表現(xiàn)形式。

網(wǎng)絡(luò)上很多教程會一上來就給你看授權(quán)碼模式的流程圖,而我必須要說明一點(diǎn),授權(quán)碼模式不等同于 OAuth2.0 協(xié)議的全部,盡管該模式的確是使用最多的一種流程模式,但它只是一種流程模式,不是此協(xié)議的本質(zhì)。

如果跳過上面的抽象流程圖而直接開始講授權(quán)碼模式、簡化模式等流程模式,那么有一個很大的壞處就是,它會使你誤認(rèn)為 OAuth2.0 是一個認(rèn)證協(xié)議,因為授權(quán)碼模式(還有簡化模式)中帶有認(rèn)證過程,即 Authorization Server 會對 User 進(jìn)行認(rèn)證,認(rèn)證之后才會有授權(quán)碼 code 和 Access Token ,這會讓你誤以為拿到 code 或 Access Token 就代表用戶已得到認(rèn)證,你就可以拿到用戶的身份信息了,但在抽象流程圖中并沒有出現(xiàn)“認(rèn)證 Authentication”的字眼。Access Token 壓根就不是一個表示認(rèn)證信息的令牌,它是一個授權(quán)令牌,它只能表示一個 Client 確實(shí)獲得了某用戶的某項資源的訪問權(quán)限,但這既不能體現(xiàn)用戶的登錄狀態(tài),亦不表示一定能夠獲得用戶的身份信息,例如使用 Refresh Token 就可以刷新得到一個新的 Access Token ,而這個過程是不需要用戶參與的。


授權(quán)碼模式 Authorization Code

基本流程

授權(quán)碼模式是應(yīng)用最廣泛的一種流程模式,它可以應(yīng)用于任何有 Web 支持的平臺,例如傳統(tǒng) Web 網(wǎng)站,單頁應(yīng)用 SPA ,移動端原生 App 等等,它的流程圖如下:

你真的理解OAuth2.0協(xié)議嗎?深入解讀OAuth2.0協(xié)議

OAuth2.0 授權(quán)碼模式流程圖

分步驟講解:

A) 客戶端程序( Client )向資源擁有者( Resource Owner )申請授權(quán),并指定一個回跳地址用于接收接下來所產(chǎn)生的授權(quán)碼或錯誤信息

B) 資源擁有者同意授權(quán),并返回一個憑證給客戶端程序,這個憑證就是授權(quán)碼 code

C) 客戶端程序拿到授權(quán)憑證(即授權(quán)碼 code )后向授權(quán)服務(wù)器(Authorization Server)申請 Access Token

D) 授權(quán)服務(wù)器驗證客戶端程序提供的授權(quán)憑證后返回 Access Token 給到客戶端 Client

E) 客戶端程序 Client 使用 Access Token 訪問資源服務(wù)器(Resource Server)中的用戶資源

F) 資源服務(wù)器驗證 Access Token 后返回受保護(hù)的資源

以上描述中注意客戶端程序并不是指 C-S 架構(gòu)下的 Client 客戶端,它在這里既可以指前端程序(如 SPA 或 APP ),也可以指WEB網(wǎng)站的后臺服務(wù)器(如 Java Web 應(yīng)用)

在授權(quán)碼模式中,我們可以看到 Authorization Server 提供了2個接口( Endpoint ),即申請授權(quán)接口與獲得授權(quán)令牌接口,對應(yīng)的分別是申請授權(quán)與獲得授權(quán)這兩個步驟。下面我們來詳細(xì)看一下這兩個接口都定義了哪些內(nèi)容以及它們的使用方法。

注意:OAuth2.0 及其擴(kuò)展協(xié)議中所涉及的所有接口( Endpoint )全部都是 HTTP 接口

申請授權(quán)接口 Authorization Endpoint

申請授權(quán)接口的請求 Authorization Request

首先,Client 需要先構(gòu)建一個用于跳轉(zhuǎn)的 uri 地址,這個地址是由 Authorization Server 即授權(quán)服務(wù)器提供的,Client 需要在它的后面拼接如下這些參數(shù)(使用 application/x-www-form-urlencoded 編碼方式對參數(shù)進(jìn)行編碼):

你真的理解OAuth2.0協(xié)議嗎?深入解讀OAuth2.0協(xié)議

申請授權(quán)接口的請求參數(shù)

然后 Client 要控制用戶的 User-Agent (一般就是瀏覽器)跳轉(zhuǎn)到剛剛構(gòu)建的 uri 上去,下面是一個例子:

你真的理解OAuth2.0協(xié)議嗎?深入解讀OAuth2.0協(xié)議

申請授權(quán)接口的請求例子

在此接口中,有如下幾點(diǎn)規(guī)則需要注意:

  • 注意以上參數(shù)是拼接在 uri 后面的,不是在 http body 中的,編碼格式是 application/x-www-form-urlencoded
  • 授權(quán)服務(wù)器 Authorization Server 收到請求后,應(yīng)驗證該請求是否正確,例如 client_id 是否存在, redirect_uri 是否合法等等
  • 如果請求正確,則授權(quán)服務(wù)器 Authorization Server 需要先認(rèn)證用戶(如果有必要)并詢問用戶以獲得用戶的授權(quán)決定 authorization decision ,一般常見的方式就是顯示一個授權(quán)頁面,用戶可以同意授權(quán),也可以拒絕授權(quán)
  • 當(dāng)用戶做出授權(quán)選擇后,授權(quán)服務(wù)器 Authorization Server 應(yīng)當(dāng)控制 User-Agent (瀏覽器)去跳轉(zhuǎn)到前面參數(shù)中的 redirect_uri 中,如果用戶選擇了同意授權(quán),那么跳轉(zhuǎn)地址后面要附帶授權(quán)碼 code 和隨機(jī)數(shù) state (如果請求中有),關(guān)于這兩個參數(shù)請參見下面的表格“申請授權(quán)接口的響應(yīng)參數(shù)(同意授權(quán)的情況)”
  • 如果用戶拒絕授權(quán),或者授權(quán)過程出現(xiàn)了錯誤,則授權(quán)服務(wù)器應(yīng)當(dāng)參照下面的錯誤處理方式來處理,關(guān)于相關(guān)參數(shù)和錯誤代碼值請參見下面的表格“申請授權(quán)接口的響應(yīng)參數(shù)(授權(quán)失敗的情況)”
  • 請?zhí)貏e留意一下 state 這個參數(shù),它可以用來防止 CSRF 攻擊,具體的攻擊方式本文就不介紹了,你可以自行搜索。state 參數(shù)是由 client 生成,最終由 client 完成校驗的。在本接口處理完成后(不論是成功或發(fā)生錯誤),在重定向回 redirect_uri 的時候應(yīng)當(dāng)帶上 state 參數(shù)(如果有就必須帶上)。
  • 控制 User-Agent 跳轉(zhuǎn)的方式可以是 302 重定向,也可以是其他方法,比如 JavaScript 跳轉(zhuǎn)等

申請授權(quán)接口的響應(yīng)(授權(quán)成功的情況) Authorization Response

你真的理解OAuth2.0協(xié)議嗎?深入解讀OAuth2.0協(xié)議

申請授權(quán)接口的響應(yīng)參數(shù)(同意授權(quán)的情況)


你真的理解OAuth2.0協(xié)議嗎?深入解讀OAuth2.0協(xié)議

申請授權(quán)接口的響應(yīng)例子(同意授權(quán)的情況)

申請授權(quán)接口的響應(yīng)(授權(quán)失敗的情況) Authorization Error Response

你真的理解OAuth2.0協(xié)議嗎?深入解讀OAuth2.0協(xié)議

申請授權(quán)接口的響應(yīng)參數(shù)(授權(quán)失敗的情況)


你真的理解OAuth2.0協(xié)議嗎?深入解讀OAuth2.0協(xié)議

申請授權(quán)接口的錯誤代碼值


你真的理解OAuth2.0協(xié)議嗎?深入解讀OAuth2.0協(xié)議

申請授權(quán)接口的響應(yīng)例子(授權(quán)失敗的情況)

很多人在實(shí)現(xiàn) OAuth2.0 的過程中往往會忽視對于錯誤情況的處理,其實(shí) OAuth2.0 已經(jīng)規(guī)定了錯誤處理方式了,如果你的目標(biāo)是要建立一個標(biāo)準(zhǔn)的 OAuth2.0 服務(wù),那么別忽視錯誤處理這一環(huán)。

返回錯誤信息時要特別注意的幾點(diǎn)

  • 每個 client 在注冊時應(yīng)指定它所能使用的 redirect_uri ,Authorization Server 應(yīng)保存下來這些 redirect_uri ,并在本接口被調(diào)用時驗證 client_id 與 redirect_uri 是否匹配,以此來避免惡意攻擊。
  • 如果 redirect_uri 與 client_id 匹配,則依據(jù)上圖把相應(yīng)的錯誤信息拼接在給定的回跳地址 redirect_uri ,并控制 User-Agent 重定向到該地址;
  • 但如果 redirect_uri 與 client_id 不匹配,或者違反了黑名單或白名單的規(guī)則(這個規(guī)則是你可以自己設(shè)計的),那么不應(yīng)該做跳轉(zhuǎn),而應(yīng)當(dāng)在授權(quán)服務(wù)器上給予適當(dāng)提示。
  • 只要 redirect_uri 沒有問題,那么所有類型的錯誤,都應(yīng)該發(fā)送給 client ,讓 client 能夠感知到錯誤的發(fā)生,并依據(jù)錯誤類型給用戶良好的錯誤信息展示,而不是由 Authorization Server 去顯示這些錯誤。

獲取訪問令牌接口 Access Token Endpoint

獲取訪問令牌接口的請求 Access Token Request

你真的理解OAuth2.0協(xié)議嗎?深入解讀OAuth2.0協(xié)議

獲取訪問令牌接口的請求參數(shù)


你真的理解OAuth2.0協(xié)議嗎?深入解讀OAuth2.0協(xié)議

獲取訪問令牌接口的請求例子

注意:在請求中,注意編碼格式 Content-Type 是 application/x-www-form-urlencoded ,并且 method 是 POST ,這與下面的響應(yīng)是不一樣的。

在此接口中,授權(quán)服務(wù)器 Authorization Server 必須滿足以下幾點(diǎn):

  • 授權(quán)服務(wù)器必須對 Client 進(jìn)行認(rèn)證,Confidential 類型的 Client 可以采用 Basic 方式來認(rèn)證,關(guān)于 Basic 認(rèn)證方式請自行搜索一下;當(dāng)然也可以使用基于非對稱加密算法的 JWT 令牌來認(rèn)證;而 Public 類型的 Client 如果要使用此接口,則必須實(shí)現(xiàn) PKCE 協(xié)議,關(guān)于 PKCE 我會在以后的文章中專門討論,你也可以自行搜索一下
  • 授權(quán)服務(wù)器必須確保請求參數(shù)中的 code 和 client_id 是匹配的,換句話說, code 確實(shí)是簽發(fā)給請求中的 client_id 的
  • 確保 code 是有效的,有效包含2層含義 —— code 確實(shí)是授權(quán)服務(wù)器簽發(fā)的、code 仍在有效期內(nèi)
  • 如果前面的“申請授權(quán)接口的請求 Authorization Request”中有 redirect_uri ,那么本接口中也應(yīng)當(dāng)包含 redirect_uri ,并且值必須是一致的。這一點(diǎn)在很多其它博客上很容易忽視,但它很重要

獲取訪問令牌接口的響應(yīng)

你真的理解OAuth2.0協(xié)議嗎?深入解讀OAuth2.0協(xié)議

獲取訪問令牌接口的響應(yīng)參數(shù)(成功的情況)

注意, expires_in 的單位是秒,如果你不返回此參數(shù),則應(yīng)當(dāng)與 Client 約定一個默認(rèn)值,并在文檔中注明。

你真的理解OAuth2.0協(xié)議嗎?深入解讀OAuth2.0協(xié)議

獲取訪問令牌接口的響應(yīng)例子(成功的情況)

關(guān)于獲取訪問令牌接口的響應(yīng),有以下幾點(diǎn)要注意:

  • 返回的參數(shù)必須以 JSON 格式放到 HTTP Response Entity-Body 中,也就是報文體中,Content-Type 必須是 application/json (后面的字符集可以加上也可以不加上)
  • 上面參數(shù)表中定義的參數(shù)必須放在 JSON 結(jié)構(gòu)的最頂層,換句話說就是不要搞嵌套
  • 除了上面表格中規(guī)定的參數(shù),你可以附加別的參數(shù)

上面是授權(quán)成功的情況,那么授權(quán)失敗的情況呢?

你真的理解OAuth2.0協(xié)議嗎?深入解讀OAuth2.0協(xié)議

獲取訪問令牌接口的響應(yīng)參數(shù)(失敗的情況)


你真的理解OAuth2.0協(xié)議嗎?深入解讀OAuth2.0協(xié)議

獲取訪問令牌接口的錯誤代碼值


你真的理解OAuth2.0協(xié)議嗎?深入解讀OAuth2.0協(xié)議

獲取訪問令牌接口的響應(yīng)例子(錯誤的情況)

關(guān)于本接口在錯誤情況下的響應(yīng),有以下幾點(diǎn)要注意:

  • 在錯誤情況下,本接口依然要以 JSON 的格式來返回錯誤信息,即 Content-Type 是 application/json (后面的字符集可以加上也可以不加上)
  • HTTP Status 狀態(tài)碼是 400 ,注意不是 200 ;我知道很多開發(fā)者習(xí)慣于不論什么情況,都返回 200 ,然后在 HTTP Response Entity-Body 中的 JSON 報文里添加一個狀態(tài)字段,但在本接口里,是通過 HTTP Status 來表達(dá)錯誤的,請一定注意這一點(diǎn)

現(xiàn)在 Client 獲得了 Access Token 之后,就可以去訪問受保護(hù)資源了,而 Resource Server 要如何校驗 Access Token 呢?其實(shí)這一點(diǎn)最開始 ITEF 并沒有歸納到協(xié)議中,而是通過另外一個協(xié)議來將此內(nèi)容補(bǔ)充上了,請參見 RFC 7662 - OAuth 2.0 Token Introspection

結(jié)語

至此,我們已經(jīng)介紹完了 OAuth2.0 協(xié)議的基礎(chǔ)知識和授權(quán)碼模式,其實(shí) OAuth2.0 協(xié)議還有非常多值得挖掘的細(xì)節(jié),以及很多擴(kuò)展或衍生協(xié)議,來幫助你在各種不同的平臺上使用這個協(xié)議來完成授權(quán)或授權(quán)認(rèn)證的工作,我會在其它文章中陸續(xù)為大家解讀 OAuth2.0 協(xié)議的方方面面。

如果本文中有哪些地方你沒有讀懂,或希望重點(diǎn)展開的,歡迎給我留言。另外如果你發(fā)現(xiàn)本文存在紕漏,也歡迎隨時給我留言,共同學(xué)習(xí)。

分享到:
標(biāo)簽:OAuth2
用戶無頭像

網(wǎng)友整理

注冊時間:

網(wǎng)站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定