接上一篇:IdentityServer4实现OAuth2.0四种模式之隐藏模式
授权码模式隐藏码模式最大不同是授权码模式不直接返回token,而是先返回一个授权码,然后再根据这个授权码去请求token。这比隐藏模式更为安全。从应用场景上来区分的话,隐藏模式适应于全前端的应用,授权码模式适用于有后端的应用,为什么呢?因为客户端根据授权码去请求token时是需要把客户端密码转进来的,为了避免客户端密码被暴露出去,所以建议把请求token这个过程放在后台。
new Client()
{
//客户端Id
ClientId="apiClientCode",
ClientName="ApiClient for Code",
//客户端密码
ClientSecrets={new Secret("apiSecret".Sha256()) },
//客户端授权类型,Code:授权码模式
AllowedGrantTypes=GrantTypes.Code,
//允许登录后重定向的地址列表,可以有多个
RedirectUris = {"https://localhost:5001/auth.html"},
//允许访问的资源
AllowedScopes={
"secretapi"
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript">
var content = "";
window.onload = function () {
var url = window.location.href;
var array = url.split("#");
if (array.length > 1) {
content = array[1];
}
var search = window.location.search;
if (search) {
search = search.substr(1);
var paras = search.split("&");
paras.forEach(element => {
content += element;
content+=";"
});
}
document.getElementById("content").innerHTML = content;
}
</script>
</head>
<body>
<div id="content"></div>
</body>
</html>
client_id:客户端Id redirect_uri=重定向Url,用户登录成功后跳回此地址 response_type=code,固定值,表示获取授权码 scope=secretapi,此token需要访问的api
拼接url:http://localhost:5000/connect/authorize?client_id=apiClientCode&redirect_uri=https://localhost:5001/auth.html&response_type=code&scope=secretapi
在浏览器中访问此url,会跳转到用户登录界面,用之前创建的用户apiUser和密码登录后浏览器会自动跳转回设置的重定向Url

可以看到已经取到了code。
根据OAuth2.0协议,传以下参数,地址则是之前在客户端模式和密码模式获取token时用到的地址,可以在identityServer4的discover文档中找到。
client_id:客户端Id client_secret:客户端密码 grant_type:authorization_code,固定值 redirect_uri=重定向Url,用户登录成功后跳回此地址 code:获取到的授权码 scope=secretapi,此token需要访问的api
1,在后台获取token,修改之前在客户端模式和密码创建的获取token接口,参数code,新增case “code”判断使之支持通过code获取token
IdentityApi.Controllers.IdentityContoller.getToken
[HttpGet]
[Route("api/getToken")]
public async Task<object> GetCdTokenAsync(string type,bool? request,string username,string password,string code)
{
var client = new HttpClient();
var disco = await client.GetDiscoveryDocumentAsync("http://localhost:5000");
TokenResponse resp = null;
switch (type)
{
case "cd":
resp = await client.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest
{
//获取Token的地址
Address = disco.TokenEndpoint,
//客户端Id
ClientId = "apiClientCd",
//客户端密码
ClientSecret = "apiSecret",
//要访问的api资源
Scope = "secretapi"
});
break;
case "pass":
resp = await client.RequestPasswordTokenAsync(new PasswordTokenRequest()
{
//获取Token的地址
Address = disco.TokenEndpoint,
//客户端Id
ClientId = "apiClientPassword",
//客户端密码
ClientSecret = "apiSecret",
//要访问的api资源
Scope = "secretapi",
//用户名
UserName = username,
//密码
Password = password
});
break;
case "code":
resp = await client.RequestAuthorizationCodeTokenAsync(new AuthorizationCodeTokenRequest()
{
Address = disco.TokenEndpoint,
ClientId = "apiClientCode",
//客户端密码
ClientSecret = "apiSecret",
Code = code,
RedirectUri = "https://localhost:5001/auth.html"
});
break;
}
if (request??false&&null!=resp)
{
//添加Bearer认证头
client.SetBearerToken(resp.AccessToken);
var reslut =await client.GetStringAsync("https://localhost:5001/api/identity");
JArray json = JArray.Parse(reslut);
return json;
}
return resp?.Json;
}
注意:RequestAuthorizationCodeTokenAsync里的RedirectUri就是之前用于获取授权码的地址,这个地址只是验证一下重定向地址,token数据会直接返回,不需要再到这个地址去取,只要有授权码,可以在任何地方取得token。
访问https://localhost:5001/api/getToken?type=code&code=42c8fd9ad0fc8f20f6f17706668783f2ecb7c10baa6a65417aff470219d9cd3e。其中code参数为上一步获取的授权码

可以看到token已经获取。要注意的是一个授权码只能获取一次token,第二次就失效了。可以把token存起来反复使用。
2,使用HTTP请求获取token

获取到token就可以访问api了。

四种模式讲完,IdentityServer.Config.GetIdentityResouce还没用上呢!因为这四种模式只涉及到IdentityServer4的OAuth2.0特性,OpenId部分还没有涉及,有时间再写。
IdentityServer4实现OAuth2.0四种模式之授权码模式
原文:https://www.cnblogs.com/liujiabing/p/11482120.html