我已经实现了Identity Server 4来进行OAuth身份验证,当我在Postman中发出身份验证请求时,它工作正常(我收到了AccessToken、Token Type、id_token、expires_in等),并且可以使用访问令牌来访问我的受保护API。但是,当我尝试在代码中执行此操作时,我以错误“invalid_grant”结束。
为什么在Postman中可以工作,但在代码中调用时却不行?
我的过程如下:
1.通过将患者ID和GUID保存到数据库,进行API调用以设置患者上下文。GUID是我的“启动”值。
1.我调用了一个自定义/auth端点,因为它需要额外的参数(“启动”),用于维护上下文(患者的id值),传入ID 4/connect/authorize/的所有必需参数。
例如,https://IDS4.azurewebsites.net/auth2?client_id=client&response_type=code&scope=openid配置文件myAPI和客户端密码=密码和状态= 1234567890api.location.comtest.azurewebsites.net/auth
此端点会将'state'的值与数据库中的'launch'相关联,以维护上下文。
1.上面的端点然后调用IDS 4/connect/authorize/ endpoint,传入适当的值。在auth管道中,我然后再次将“sessionId”与“state”关联以维护上下文。
- IDS 4/connect/authorize/ endpoint会如预期般传回受权码、范围、状态和session_state。
1.在上面的'authorize'调用中指定的redirectURI的Get中,我获取授权代码并执行到ID 4/connect/token端点的标准post。
1.响应为“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;
}
}
1条答案
按热度按时间mrzz3bfm1#
您需要提供授权类型。您可以在此处找到案例的文档-https://docs.identityserver.io/en/latest/topics/grant_types.html
我有一个类似的实现,我在postman中使用客户端凭据,在代码中使用密码。
如果对你有用,请在答案上做记号。