首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

DotNetOpenAuth OAuth 2.0 實作:Authorization Code Flow 取得 Access Token 完整範例

     編輯:關於.NET

基於 DotNetOpenAuth 5.0 實作 OAuth 2.0 Authorization Server 與 Client,示範 Authorization Code Flow 核心流程:授權碼換 Access Token。

流程圖解

OAuth 2.0 Authorization Code Flow

本文聚焦 (D) Client 以 Authorization Code 向 Token Endpoint 請求 Access Token、(E) Server 驗證核發 Token。

環境

  • DotNetOpenAuth 5.0.0-alpha3 (NuGet 预發布版)
  • ASP.NET MVC 5 / .NET Framework 4.5.1

Authorization Server 實作

Controller 入口

public class OAuthController : Controller
{
    public async Task<ActionResult> Token()
    {
        var authServer = new AuthorizationServer(new AuthorizationServerHost());
        var response = await authServer.HandleTokenRequestAsync(Request);
        return response.AsActionResult();
    }
}

IAuthorizationServerHost 實作

public class AuthorizationServerHost : IAuthorizationServerHost
{
    // 驗證授權碼有效性
    public bool IsAuthorizationValid(IAuthorizationDescription authorization)
    {
        // 例:檢查 ClientId、RedirectUri、過期時間、Scope
        return authorization.ClientIdentifier == "webclientdemo" 
            && authorization.Scope.Contains("basic");
    }

    // 核發 Access Token
    public AccessTokenResult CreateAccessToken(IAccessTokenRequest request)
    {
        var token = new AuthorizationServerAccessToken
        {
            Lifetime = TimeSpan.FromHours(10),           // 10 小時有效
            SymmetricKeyStore = this.CryptoKeyStore      // 簽章金鑰
        };
        return new AccessTokenResult(token);
    }

    public ICryptoKeyStore CryptoKeyStore 
        => new HardCodedKeyCryptoKeyStore("your-256-bit-base64-key==");
}

Client 實作

以 HttpClient 直接呼叫 Token Endpoint

public class OAuthController : Controller
{
    private const string ClientId = "webclientdemo";
    private const string ClientSecret = "webclientdemosecret";
    private const string TokenEndpoint = "https://authserver.example.com/oauth/token";

    public async Task<ActionResult> Callback(string code)
    {
        using (var http = new HttpClient())
        {
            var form = new Dictionary<string, string>
            {
                { "grant_type", "authorization_code" },
                { "code", code },
                { "redirect_uri", Request.Url.GetLeftPart(UriPartial.Path) },
                { "client_id", ClientId },
                { "client_secret", ClientSecret }
            };

            var response = await http.PostAsync(TokenEndpoint, new FormUrlEncodedContent(form));
            string json = await response.Content.ReadAsStringAsync();
            
            if (response.IsSuccessStatusCode)
            {
                var tokenObj = JObject.Parse(json);
                string accessToken = tokenObj["access_token"].ToString();
                // 儲存 Token 至 Session/資料庫,導向受保護資源
                return Redirect("/Home/ProtectedResource");
            }
            return Content($"Token 申請失敗: {json}");
        }
    }
}

未使用 `DotNetOpenAuth.OAuth2.WebServerClient` 主因:跨平台相容性考量,純 HTTP 呼叫更透明、易除錯。

關鍵點總結

環節注意事項
Authorization Code單次使用、短效期 (建議 10 分鐘)、綁定 ClientId + RedirectUri
Client Secret機密應用才需驗證,公共應用 (SPA/行動App) 採用 PKCE 延伸
Token 儲存Access Token 加密儲存,Refresh Token 更嚴格保護
錯誤處理依 RFC 6749 回傳標準錯誤碼 (`invalid_grant`, `unauthorized_client` 等)

擴充:Resource Server 驗證 Bearer Token

public class BearerTokenHandler : DelegatingHandler
{
    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (request.Headers.Authorization?.Scheme == "Bearer")
        {
            var analyzer = new StandardAccessTokenAnalyzer(AuthorizationServerHost.CryptoKeyStore);
            var resourceServer = new ResourceServer(analyzer);
            var principal = await resourceServer.GetPrincipalAsync(request, cancellationToken);
            
            HttpContext.Current.User = principal;
            Thread.CurrentPrincipal = principal;
        }
        return await base.SendAsync(request, cancellationToken);
    }
}

// WebApiConfig.cs
config.MessageHandlers.Add(new BearerTokenHandler());

DotNetOpenAuth 文件較少,建議搭配原始碼閱讀 `AuthorizationServer`、`ResourceServer`、`StandardAccessTokenAnalyzer` 理解驗證流程。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved