[英]Why does getting my access token work in Postman but not in my code?
I have implemented Identity Server 4 to for OAuth authentication and it is working fine when I make an authentication request in Postman (I recieve my AccessToken, Token Type, id_token, expires_in etc) and can use the access token to access my protected api. 但是,當我嘗試在代碼中執行此操作時,我最終會遇到錯誤“invalid_grant”。
為什么這在 Postman 中有效,但在我用代碼調用時卻無效?
我的流程如下:
調用 api 以通過將患者 ID 和 GUID 保存到數據庫來設置患者上下文。 Guid 是我的“啟動”值。
我調用自定義 /auth 端點,因為它需要用於維護上下文(患者的 id 值)的額外參數('launch')傳遞 ID4 /connect/authorize/ 的所有必需參數
例如。 https://IDS4.azurewebsites.net/auth2?client_id=client&response_type=code&scope=openid profile myAPI&client_secret=secret&state=1234567890p&aud=https://api.location.com&launch=K123K456Y7.777&redirect_uri=th
此端點將在數據庫中將“狀態”的值與“啟動”相關聯以維護上下文。
上面的端點然后調用 IDS4 /connect/authorize/ 端點,傳入適當的值。 然后在身份驗證管道中,我再次將“sessionId”與“狀態”相關聯以維護上下文。
IDS4 /connect/authorize/ 端點按預期返回授權碼 scope、state 和 session_state。
在上面的“授權”調用中指定的重定向URI 的獲取中,我獲取授權代碼並執行到 ID4 /connect/token 端點的標准發布。
響應是'invalid_grant'
所有這些都適用於 Postman。
我曾嘗試改變我客戶的 AllowedGrantTypes,但我認為“authorization_code”是要堅持的。 我使用 GrantTypes 枚舉。 以下是我的客戶端配置:
new Client
{
ClientId = "client",
ClientSecrets = { new Secret("secret".Sha256()) },
//RequireClientSecret = false, //false is default
RequirePkce = false, //to prevent 'code challenge required' message from appearing when using 'Code'
AllowedGrantTypes = GrantTypes.Code ,//{ "code", "authorization_code" },//
// where to redirect to after login
RedirectUris = { "https://IDS4.azurewebsites.net/signin-oidc", "https://test.azurewebsites.net/auth",
"https://test.azurewebsites.net/token", "https://IDS4.azurewebsites.net/Account/Login" },
// where to redirect to after logout
PostLogoutRedirectUris = { "https://IDS4.azurewebsites.net/signout-callback-oidc" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"myAPI"
}
}
我的啟動代碼:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDbContextPool<AppDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DBConnection")));
var builder = services.AddIdentityServer()
.AddInMemoryIdentityResources(Config.IdentityResources)
.AddInMemoryApiScopes(Config.ApiScopes)
.AddInMemoryClients(Config.Clients)
.AddTestUsers(TestUsers.Users)
.AddCustomTokenRequestValidator<CustomTokenRequestValidator>()
.AddCustomAuthorizeRequestValidator<CustomAuthorizeRequestValidator>();
builder.AddDeveloperSigningCredential();
services.AddAuthentication()
.AddGoogle("Google", options =>
{
options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme;
options.ClientId = "<insert here>";
options.ClientSecret = "<insert here>";
});
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_3_0).AddXmlSerializerFormatters()
.AddMvcOptions(options => options.EnableEndpointRouting = false);
services.AddScoped<IDebugRepository, SQLDebugRepository>();
services.AddScoped<IPatientContextRepository, SQLPatientContextRepository>();
services.AddScoped<IClinicAccessRepository, SQLClinicAccessRepository>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCookiePolicy(new CookiePolicyOptions
{
HttpOnly = HttpOnlyPolicy.None,
MinimumSameSitePolicy = SameSiteMode.None,
Secure = CookieSecurePolicy.Always
});
app.UseStaticFiles();
app.UseRouting();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
這就是我在 Auth Get 中對 /connect/Token 端點進行 POST 的方式:
[HttpGet]
public async Task<string> Get(string code, string scope, string state, string session_state)
{
try
{
//AuthResponseModel arm = new AuthResponseModel
//{
// code = code,
// scope = scope,
// state = state,
// session_state = session_state
//};
string grant_type = "authorization_code";
string redirect_uri = "https://test.azurewebsites.net/token"; //sends the token back to requestor
string client_id = "client"; //current stable testing client
string baseAddress = $"https://IDS4.azurewebsites.net/connect/token";
string client_secret = "secret";
var client = new HttpClient();
client.BaseAddress = new Uri($"https://IDS4.azurewebsites.net/");
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("client_id", client_id),
new KeyValuePair<string, string>("client_secret", client_secret),
new KeyValuePair<string, string>("grant_type", grant_type),
new KeyValuePair<string, string>("code", code),
new KeyValuePair<string, string>("redirect_uri", redirect_uri)
});
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
var res = await client.PostAsync(baseAddress, content);
var resp = await res.Content.ReadAsStringAsync();
return resp;
}
catch (Exception ex)
{
return ex.Message + Environment.NewLine + ex.StackTrace ;
}
}
我沒有嘗試過的一件事是設置簽名證書。 我認為 Postman 使用了我需要接受的內部證書,但是已經很久了,我不記得我是否這樣做了。 我認為丟失的證書會在現在之前給我帶來問題,但這是我正在研究的問題。
另外,請注意 - 我已經測試了令牌重定向並且它正在工作。
這里是:
[Controller]
[Route("Token")]
[AllowAnonymous]
public class TokenController : Controller
{
[HttpPost]
public string Post([FromForm] string access_token,
[FromForm] string token_type,
[FromForm] string expires_in,
[FromForm] string scope,
[FromForm] string patient,
[FromForm] string id_token,
[FromForm] string oceanSharedEncryptionKey)
{
TokenResponseModel token = new TokenResponseModel
{
access_token = access_token,
expires_in = expires_in,
id_token = id_token,
patient = patient,
scope = scope,
token_type = token_type
};
string rslt = JsonConvert.SerializeObject(token);
return rslt;
}
public string Get( string test1)
{
return test1;
}
}
您需要提供授權類型。 在這里您可以找到適用於您案例的文檔 - https://docs.identityserver.io/en/latest/topics/grant_types.html
我有類似的實現,我在 postman 中使用客戶端憑據並在代碼中使用密碼。 您也可以嘗試 postman 中的密碼
private async Task<string> GetNewAccessTokenAsync()
{
var postMessage = new Dictionary<string, string>
{
{"client_id", "Client ID goes here"},
{"client_secret","Client secret goes here" },
{"scope","User.Read" },
{"grant_type", "password"},
{"username", "Username goes here"},
{"password", "Password goes here"}
};
var client1 = new HttpClient();
var response = await client1.PostAsync("https://login.microsoftonline.com/{{id}}/oauth2/v2.0/token", new FormUrlEncodedContent(postMessage));
// return response.ReasonPhrase;
if (response.IsSuccessStatusCode)
{
var json = response.Content.ReadAsStringAsync();
return json.Result;
}
return "";
}
如果對您有用,請標記答案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.