簡體   English   中英

為什么獲取我的訪問令牌在 Postman 中有效,但在我的代碼中無效?

[英]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 中有效,但在我用代碼調用時卻無效?

我的流程如下:

  1. 調用 api 以通過將患者 ID 和 GUID 保存到數據庫來設置患者上下文。 Guid 是我的“啟動”值。

  2. 我調用自定義 /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

    此端點將在數據庫中將“狀態”的值與“啟動”相關聯以維護上下文。

  3. 上面的端點然后調用 IDS4 /connect/authorize/ 端點,傳入適當的值。 然后在身份驗證管道中,我再次將“sessionId”與“狀態”相關聯以維護上下文。

  4. IDS4 /connect/authorize/ 端點按預期返回授權碼 scope、state 和 session_state。

  5. 在上面的“授權”調用中指定的重定向URI 的獲取中,我獲取授權代碼並執行到 ID4 /connect/token 端點的標准發布。

  6. 響應是'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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM