[英]Authorization_code grant flow on Owin.Security.OAuth: returns invalid_grant
我正在嘗試使用authorization_code
授權流程設置我的身份驗證。 我以前使用過grant_type=password
,所以我知道這些東西應該如何工作。 但是當使用grant_type=authorization_code
,我不能讓它返回invalid_grant
以外的任何東西
這是我的設置:
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/auth/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(5),
Provider = new SampleAuthProvider()
});
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Active,
AuthenticationType = "Bearer"
});
SampleAuthProvider 是以下類: https : //gist.github.com/anonymous/8a0079b705423b406c00
基本上,它只是記錄每一步並驗證它。 我嘗試了請求:
POST http://localhost:12345/auth/token
grant_type=authorization_code&code=xxxxxx&client_id=xxxxx&redirect_uri=https://xxxx.com/
Content-Type: application/x-www-form-urlencoded
它正在經歷:
OnMatchEndpoint
OnValidateClientAuthentication
就這樣。 我希望它接下來調用OnValidateTokenRequest
和OnGrantAuthorizationCode
,但它沒有。 我不知道為什么。
請求中的xxxx
不是占位符,我是這樣嘗試的。 也許中間件會自行進行一些檢查並因此拒絕請求? 我用http
嘗試了redirect_uri
變體,沒有任何協議,沒有尾部斜杠......
它也可以與自定義grant_type
一起正常工作。 所以如果我太絕望了,我想我可以用它來模擬authorization_code
,但我寧願不必那樣做。
TL; 博士
當使用grant_type=authorization_code
時,我的OAuthAuthorizationServerProvider
在OnValidateClientAuthentication
之后返回{"error":"invalid_grant"}
。
謝謝你的幫助!
編輯
正如 RajeshKannan 所指出的,我在配置中犯了一個錯誤。 我沒有提供AuthorizationCodeProvider
實例。 但是,這並沒有完全解決問題,因為在我的情況下,代碼不是由AuthorizationCodeProvider
發布的,我不能只是反序列化它。 我回答了我開始工作的解決方法。
這是我的工作。 我對該解決方案並不完全滿意,但它有效並且應該可以幫助其他人解決他們的問題。
所以,問題是我沒有設置AuthorizationCodeProvider
屬性。 當收到帶有grant_type=authorization_code
的請求時,代碼必須由該代碼提供者驗證。 該框架假定代碼是由該代碼提供者發布的,但我的情況並非如此。 我從另一台服務器獲取它,並且必須將代碼發送回它進行驗證。
在標准情況下,您也是發布代碼的人,RajeshKannan 提供的鏈接描述了您必須做的一切。
這是您必須設置屬性的地方:
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString(Paths.TokenPath),
Provider = new SampleAuthProvider(),
AuthorizationCodeProvider = new MyAuthorizationCodeProvider ()
}
以及MyAuthorizationCodeProvider
類的聲明:
internal class MyAuthorizationCodeProvider : AuthenticationTokenProvider
{
public override async Task ReceiveAsync(
AuthenticationTokenReceiveContext context)
{
object form;
// Definitely doesn't feel right
context.OwinContext.Environment.TryGetValue(
"Microsoft.Owin.Form#collection", out form);
var redirectUris = (form as FormCollection).GetValues("redirect_uri");
var clientIds = (form as FormCollection).GetValues("client_id");
if (redirectUris != null && clientIds != null)
{
// Queries the external server to validate the token
string username = await MySsoService.GetUserName(context.Token,
redirectUris[0]);
if (!string.IsNullOrEmpty(username))
{
var identity = new ClaimsIdentity(new List<Claim>()
{
// I need the username in GrantAuthorizationCode
new Claim(ClaimTypes.NameIdentifier, username)
}, DefaultAuthenticationTypes.ExternalBearer);
var authProps = new AuthenticationProperties();
// Required. The request is rejected if it's not provided
authProps.Dictionary.Add("client_id", clientIds[0]);
// Required, must be in the future
authProps.ExpiresUtc = DateTimeOffset.Now.AddMinutes(1);
var ticket = new AuthenticationTicket(identity, authProps);
context.SetTicket(ticket);
}
}
}
}
我有同樣的錯誤。 我缺少的東西:
OAuthAuthorizationServerOptions.AuthorizationCodeProvider
。client_id
指定為 GET 參數,就像您在收到authorization_code
時所做的那樣。OAuthAuthorizationServerProvider.ValidateClientAuthentication
並在此方法中調用context.TryGetFormCredentials
。 這將屬性context.ClientId
設置為來自client_id
GET 參數的值。 必須設置此屬性,否則您將收到invalid_grant
錯誤。 另外,調用context.Validated()
。 完成上述所有操作后,我終於可以將authorization_code
交換為令牌端點處的access_token
。
謝謝方案,我的代碼缺少以下兩個必需值。 發布在這里以防其他人發現它有用:
// Required. The request is rejected if it's not provided
authProps.Dictionary.Add("client_id", clientIds[0]);
// Required, must be in the future
authProps.ExpiresUtc = DateTimeOffset.Now.AddMinutes(1);
確保您已配置授權服務器選項。 我認為您應該提供您的授權端點詳細信息:
AuthorizeEndpointPath = new PathString(Paths.AuthorizePath)
在下面的鏈接中,將詳細解釋授權碼授予,並列出了授權碼授予生命周期中涉及的方法。
我用以下最簡單的例子解決了這個問題,並想分享它。 希望有人覺得它有幫助。
——
中間件似乎會檢查AuthenticationProperties
字典中是否存在 key redirect_uri
,將其刪除,一切正常(使用經過驗證的上下文)。
AuthorizationCodeProvider
的簡化示例如下所示:
public class AuthorizationCodeProvider:AuthenticationTokenProvider {
public override void Create(AuthenticationTokenCreateContext context) {
context.SetToken(context.SerializeTicket());
}
public override void Receive(AuthenticationTokenReceiveContext context) {
context.DeserializeTicket(context.Token);
context.Ticket.Properties.Dictionary.Remove("redirect_uri"); // <-
}
}
並且不要忘記在重寫的方法OAuthAuthorizationServerProvider.ValidateClientAuthentication
中驗證上下文。 同樣,這是一個從模板項目的ApplicationOAuthProvider
類繼承的簡化示例:
public partial class DefaultOAuthProvider:ApplicationOAuthProvider {
public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context) {
if(null!=context.RedirectUri) {
context.Validated(context.RedirectUri);
return Task.CompletedTask;
}
return base.ValidateClientRedirectUri(context);
}
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) {
if(context.TryGetFormCredentials(out String clientId, out String clientSecret)) {
// Specify the actual expected client id and secret in your case
if(("expected-clientId"==clientId)&&("expected-clientSecret"==clientSecret)) {
context.Validated(); // <-
return Task.CompletedTask;
}
}
return base.ValidateClientAuthentication(context);
}
public DefaultOAuthProvider(String publicClientId) : base(publicClientId) {
}
}
請注意,如果您使用特定的客戶端 ID 調用context.Validated
,則您必須將相同的 client_id 放在票證的屬性中,您可以使用AuthenticationTokenProvider.Receive
方法來做到這一點
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.