简体   繁体   English

如何使用 authentication_code 在 C# 中获取 Oauth2 不记名令牌?

[英]How to obtain an Oauth2 bearer token in C# using authorization_code?

I have a postman request that works correctly in obtaining a bearer token, that I can grab and use to make a successful request.我有一个邮递员请求,它在获取不记名令牌时可以正常工作,我可以抓取并使用它来发出成功的请求。 But I cannot obtain an equally valid bearer token in c# and I have tried about 100 different approaches.但是我无法在 c# 中获得同样有效的不记名令牌,并且我尝试了大约 100 种不同的方法。

Here is the Postman request, which gets a valid bearer token:这是 Postman 请求,它获取有效的不记名令牌:

在此处输入图像描述

Scope: AX.FullAccess CustomService.FullAccess Odata.FullAccess范围: AX.FullAccess CustomService.FullAccess Odata.FullAccess

Auth URL: https://login.microsoftonline.com/abe3ad26.../oauth2/authorize?resource=https://myCust.sandbox.operations.dynamics.com/认证网址: https://login.microsoftonline.com/abe3ad26.../oauth2/authorize?resource=https://myCust.sandbox.operations.dynamics.com/ ://login.microsoftonline.com/abe3ad26.../oauth2/authorize?resource=https://myCust.sandbox.operations.dynamics.com/

In the Client Authentication pulldown there are 2 options.Client Authentication下拉菜单中有 2 个选项。 The other option is Send as basic auth header .另一个选项是Send as basic auth header It doesn't matter which I choose, they both work.我选择哪个并不重要,它们都有效。

And here is my non-working c# attempting to do the same thing postman does:这是我的非工作 c# 试图做邮递员所做的同样的事情:

using(WebClient client = new WebClient()) {
  var querystring = new System.Collections.Specialized.NameValueCollection();
  querystring.Add("grant_type", "authorization_code");
  querystring.Add("client_id", "e93c4014...");
  querystring.Add("client_secret", "USu8Q...");
  querystring.Add("redirect_uri", "https://myCust.sandbox.operations.dynamics.com/");
  querystring.Add("resource", "https://myCust.sandbox.operations.dynamics.com/");
  querystring.Add("scope", "AX.FullAccess CustomService.FullAccess Odata.FullAccess");

  byte[] responsebytes = client.UploadValues("https://login.microsoftonline.com/abe3ad26.../oauth2/authorize", "POST", querystring);

  [code to retrieve the response...]
}

In all the various permutations I have tried of the above code, I either get an exception with no message, or I get a large html response that is merely Microsoft's generic page titled Sign in to your account .在我尝试过的上述代码的所有各种排列中,我要么得到一个没有消息的异常,要么得到一个大的 html 响应,它只是 Microsoft 的通用页面,标题为Sign in to your account

I'm unsure whether resource should be a formal param, or appended to the Auth URL as in postman, or what.我不确定resource是否应该是正式的参数,或者像邮递员一样附加到Auth URL ,或者什么。

I am certain the client_id and client_secret are right, both in name and value .我确定client_idclient_secretnamevalue上都是正确的。 As for all the other params, I'm not as sure.至于所有其他参数,我不确定。 I'm especially unsure what exact url I should be POSTing this request to.我特别不确定我应该将此请求发布到哪个确切的网址。 I have tried the full Auth URL with and without the resource querystring value appended, no luck either way.我已经尝试了带有和不带有资源查询字符串值的完整Auth URL ,无论哪种方式都没有运气。

One issue is that you should always ask for the openid scope.一个问题是您应该始终要求openid范围。

this is a required scope in most identity providers.这是大多数身份提供者的必需范围。

Below is the C# code I use to get the token from an openid-connect token provider: (using the Flurl.Http NuGet package)下面是我用来从 openid-connect 令牌提供程序获取令牌的 C# 代码:(使用 Flurl.Http NuGet 包)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Flurl;
using Flurl.Http;
using Microsoft.AspNetCore.Mvc;
using OpenID_Connect_client.Models;

public class CodeFlowController : Controller
{
    private readonly IOpenIDSettings _openIdSettings;

    public CodeFlowController(IOpenIDSettings openIdSettings)
    {
        this._openIdSettings = openIdSettings;
    }

    /// <summary>
    /// Start page for the login using the fragment as return type
    /// </summary>
    /// <returns></returns>
    public IActionResult Login()
    {
        string url = BuildLoginUrl();
        ViewData["loginurl"] = url;

        return View();
    }


    /// <summary>
    /// Construct the login URL
    /// </summary>
    /// <returns></returns>
    private string BuildLoginUrl()
    {
        //In real life, nonce and state should be random values, but we hardcoded them here for simplicity
        string nonceValue = "1122334455";
        string stateValue = "9988776655";

        //Please redirect us back to this page after successful login
        string redirectUrl = "https://localhost:5001/CodeFlow/callback";

        var url = new Url(_openIdSettings.authorization_endpoint);

        url = url.SetQueryParams(new
        {
            response_type = "code",       //Get both access-token + ID-token
            client_id = "authcodeflowclient",       //Id of this client

            scope = "openid email profile shop.admin",   //openid (required; to indicate that the application intends to use OIDC to verify the user's identity)

            prompt = "consent",                     // Force users to provide consent
            response_mode = "form_post",            // Send the token response as a form post instead of a fragment encoded redirect

            state = stateValue,                     // To prevent CSRF attacks
            nonce = nonceValue,                     // To further strengthen the security

            redirect_uri = redirectUrl              // The URL to which the Auth0 will redirect the user's browser after authorization has been granted by the user. 
        });

        return url.ToString();
    }


    /// <summary>
    /// This method is called with the authorization code and state parameter
    /// </summary>
    /// <param name="code">authorization code generated by the authorization server. This code is relatively short-lived, typically lasting between 1 to 10 minutes depending on the OAuth service.</param>
    /// <param name="state"></param>
    /// <returns></returns>
    [HttpPost]
    public IActionResult Callback(string code, string state)
    {

        //To be secure then the state parameter should be compared to the state sent in the previous step

        var url = new Url(_openIdSettings.token_endpoint);

        var token = url.PostUrlEncodedAsync(new
        {
            client_id = "authcodeflowclient",       //Id of this client
            client_secret = "mysecret",
            grant_type = "authorization_code",
            code = code,
            redirect_uri = "https://localhost:5001/CodeFlow/Callback"

        }).ReceiveJson<Token>().Result;

        return View(token);
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM