搭建好了基于 OWIN 的 OAuth2 服务器之后, 接下来就是如何从服务器取得授权了, 下面就介绍如何实现 OAuth2 定义的四种授权方式。
授权码授权 (Authorization Code Grant)
授权码授权针对机密的客户端优化, 可以同时获取访问凭据 (access token) 和刷新凭据 (refresh token) , 因为是基于 HTTP 重定向的方式, 所以客户端必须能够操纵资源所有者的用户代理(通常是浏览器)并且能够接收从授权服务器重定向过来的请求。
在实现上使用开源的 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 中编码的, 所以有可能会暴漏给用户或客户端上的其它应用。
由于这种授权方式一般是通过浏览器实现的, 所以就不用依赖 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) 。
对于 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) (或者其它方式的认证) 来获取访问凭据, 客户端可以根据自己的需要来访问受保护的资源, 或者资源所有者已经访问过认证服务器时, 才能使用这种授权方式。 只有对完全受信任的客户端才能使用这种授权方式, 因为对受保护的资源方来说, 认证信息的内容是客户端程序的凭据, 而不是资源所有者的凭据。
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 上有完整的项目代码, 不清楚的地方可以直接查看源代码。
推荐本站淘宝优惠价购买喜欢的宝贝:
本文链接:https://hqyman.cn/post/3907.html 非本站原创文章欢迎转载,原创文章需保留本站地址!
休息一下~~