18
2023
04
14:17:14

从 OAuth2 服务器获取授权授权

搭建好了基于 OWIN 的 OAuth2 服务器之后, 接下来就是如何从服务器取得授权了, 下面就介绍如何实现 OAuth2 定义的四种授权方式。

授权码授权 (Authorization Code Grant)

授权码授权针对机密的客户端优化, 可以同时获取访问凭据 (access token) 和刷新凭据 (refresh token) , 因为是基于 HTTP 重定向的方式, 所以客户端必须能够操纵资源所有者的用户代理(通常是浏览器)并且能够接收从授权服务器重定向过来的请求。

authorization-code-grant

在实现上使用开源的 DotNetOpenAuth 来简化实现代码, DotNetOpenAuth 可以通过 NuGet 获取, 示例代码如下:

// init a new oauth web server client;var authServer = new AuthorizationServerDescription {
    AuthorizationEndpoint = new Uri(Paths.AuthorizePath),
    TokenEndpoint = new Uri(Paths.TokenPath)
};var webServerClient = new WebServerClient(authServer, clientId, clientSecret);// redirect user user-agent to authorization endpoint;var userAuthorization = webServerClient.PrepareRequestUserAuthorization(new[] { "bio", "notes" });
userAuthorization.Send(HttpContext);
Response.End();// get access token from request (redirect from oauth server)var authorizationState = webServerClient.ProcessUserAuthorization(Request);if (authorizationState != null) {
    ViewBag.AccessToken = authorizationState.AccessToken;
    ViewBag.RefreshToken = authorizationState.RefreshToken;
    ViewBag.Action = Request.Path;
}//refresh tokenvar state = new AuthorizationState {
    AccessToken = Request.Form["AccessToken"],
    RefreshToken = Request.Form["RefreshToken"]
};if (webServerClient.RefreshAuthorization(state)) {
    ViewBag.AccessToken = state.AccessToken;
    ViewBag.RefreshToken = state.RefreshToken;
}// call protected user resourcevar client = new HttpClient(webServerClient.CreateAuthorizingHandler(accessToken));var body = await client.GetStringAsync(new Uri(Paths.ResourceUserApiPath));
ViewBag.ApiResponse = body;

隐式授权 (Implicit Grant)

隐式授权为已知的公开客户端优化, 用于客户端操作一个特定的重定向地址, 只能获取访问凭据 (access token) , 不支持刷新凭据 (refresh token) 。 客户端通常在浏览器内用 Javascript 实现。

因为是基于 HTTP 重定向的方式, 所以客户端必须能够操纵资源所有者的用户代理(通常是浏览器)并且能够接收从授权服务器重定向过来的请求。

与授权码授权方式不同的是, 客户端不需要为授权和访问凭据分别发送单独的请求, 可以直接从授权请求获取访问凭据。

隐式授权不包括客户端授权, 依赖资源所有者(用户)的现场判断以及客户端重定向地址, 由于访问凭据是在 URL 中编码的, 所以有可能会暴漏给用户或客户端上的其它应用。

implicit-grant

由于这种授权方式一般是通过浏览器实现的, 所以就不用依赖 DotNetOpenAuth 了, 只需要 Javascript 就行了, 示例代码如下:

// index.htmlvar authorizeUri = '@(Paths.AuthorizePath)';var tokenUri = '@(Paths.TokenPath)';var apiUri = '@Paths.ResourceUserApiPath';var clientId = '@clientId';var returnUri = '@clientRedirectUrl';var nonce = 'my-nonce';

$('#authorize').click(function () {    // build redirect url
    var uri = addQueryString(authorizeUri, {        'client_id': clientId,        'redirect_uri': returnUri,        'state': nonce,        'scope': 'bio notes',        'response_type': 'token'
    });    // login callback
    window.oauth = {};    window.oauth.signin = function (data) {        if (data.state !== nonce) {            return;
        }
        $('#accessToken').val(data.access_token);
    }    // open login.html in a new window.
    window.open(uri, 'authorize', 'width=640,height=480');
});// add query string to urifunction addQueryString(uri, parameters) {    var delimiter = (uri.indexOf('?') == -1) ? '?' : '&';    for (var parameterName in parameters) {        var parameterValue = parameters[parameterName];
        uri += delimiter + encodeURIComponent(parameterName) + '=' + encodeURIComponent(parameterValue);
        delimiter = '&';
    }    return uri;
}// login.html// get fragment and call opener's signin function.var fragments = getFragment();if (window.opener && window.opener.oauth && window.opener.oauth.signin) {    window.opener.oauth.signin(fragments);
}window.close();// get fragment from window urifunction getFragment() {    if (window.location.hash.indexOf("#") === 0) {        return parseQueryString(window.location.hash.substr(1));
    } else {        return {};
    }
}// parse query string to object;function parseQueryString(queryString) {    var data = {}, pairs, pair, separatorIndex, escapedKey, escapedValue, key, value;    if (queryString === null) {        return data;
    }

    pairs = queryString.split("&");    for (var i = 0; i < pairs.length; i++) {
        pair = pairs[i];
        separatorIndex = pair.indexOf("=");        if (separatorIndex === -1) {
            escapedKey = pair;
            escapedValue = null;
        } else {
            escapedKey = pair.substr(0, separatorIndex);
            escapedValue = pair.substr(separatorIndex + 1);
        }

        key = decodeURIComponent(escapedKey);
        value = decodeURIComponent(escapedValue);

        data[key] = value;
    }    return data;
}

资源所有者密码凭据授权 (Resource Owner Password Credentials Grant)

资源所有者密码凭据授权适用于那些被充分信任的应用, 比如设备操作系统或者权限很高的应用。 授权服务器启用这类授权是要格外注意, 只能在其它授权方式不能用的时候才使用这种授权方式。

这种授权方式适用于能够取得用户的凭据 (通常是通过可交互的表单) 的应用, 也可以用于迁移现有的那些需要直接授权 (HTTP Basic 或 Digest ) 的应用, 将保存的用户凭据改为保存访问凭据 (access token) 。

resource-owner-password-credentials-grant

对于 DotNetOpenAuth 来说, 这种授权也是十分容易实现的, 示例代码如下:

// create auth server description var authServer = new AuthorizationServerDescription {
    AuthorizationEndpoint = new Uri(Paths.AuthorizePath),
    TokenEndpoint = new Uri(Paths.TokenPath)
};// create web server clientvar webServerClient = new WebServerClient(authServer, clientId, clientSecret);// use user name and password to exchange access token;var state = webServerClient.ExchangeUserCredentialForToken(
    username, password,    new[] {"scope1", "scope2", "scope3"}
);// get access token;var token = state.AccessToken;

客户端凭据授权 (Client Credentials Grant)

客户端凭据授权是指客户端可以只通过客户端自己的凭据 (client_id 和 client_secret) (或者其它方式的认证) 来获取访问凭据, 客户端可以根据自己的需要来访问受保护的资源, 或者资源所有者已经访问过认证服务器时, 才能使用这种授权方式。 只有对完全受信任的客户端才能使用这种授权方式, 因为对受保护的资源方来说, 认证信息的内容是客户端程序的凭据, 而不是资源所有者的凭据。

client-credentials-grant

DotNetOpenAuth 也支持这种授权方式, 示例代码如下:

// create auth server description var authServer = new AuthorizationServerDescription {
    AuthorizationEndpoint = new Uri(Paths.AuthorizePath),
    TokenEndpoint = new Uri(Paths.TokenPath)
};// create web server clientvar webServerClient = new WebServerClient(authServer, clientId, clientSecret);// get client access token;var state = webServerClient.GetClientAccessToken(  new[] { "test1", "test2", "test3" }
);// get access token;var token = state.AccessToken;

使用访问凭据访问受保护的资源

上面介绍的都是如何取得访问凭据 (access_token) , 拿到了访问凭据之后如何来使用呢? 对于使用微软的 OWIN 中间件 Microsoft.Owin.Security.OAuth 搭建的服务器来说, 需要设置 HTTP 请求的 Authorization 标头为 Bearer {access_token} 就可以了, 这个属于 OAuth 的规范之内了, 示例代码如下:

使用 jQuery 的 Ajax 请求时, 示例代码如下:

var accessToken = '@AccessToken';

$.ajax({    url: '@ResourcePath',    beforeSend: function(jqr) {
        jqr.setRequestHeader('Authorization', 'Bearer ' + accessToken);
    }
})
.done(function (data) {    // other code here.});

使用其它语言的代码与上面的 js 代码大同小异,上面只是一些代码片段, 在 github 上有完整的项目代码, 不清楚的地方可以直接查看源代码。




推荐本站淘宝优惠价购买喜欢的宝贝:

image.png

本文链接:https://hqyman.cn/post/3907.html 非本站原创文章欢迎转载,原创文章需保留本站地址!

分享到:
打赏





休息一下~~


« 上一篇 下一篇 »

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

请先 登录 再评论,若不是会员请先 注册

您的IP地址是: