【问题标题】:Accessing a secure Web API from a WPF client从 WPF 客户端访问安全的 Web API
【发布时间】:2016-05-25 15:50:11
【问题描述】:

我有一个为 CORS 配置的 Web API 项目,并在其中一个 APIController 上实现 [Authorize]。当我删除 [Authorize] 时,我可以从 WPF 客户端访问 API,但是当它到位时,调用似乎丢失了。这是我为请求令牌而设置的。

在WPF代码后面

    internal void RefreshRecentFilesList()
    {
        //Get the token
        var token = GetAPIToken(email, password, "http://localhost:50006").Result;
        MessageBox.Show(token);
    }

    private static async Task<string> GetAPIToken(string userName, string password, string apiBaseUri)
    {
        using (var client = new HttpClient())
        {
            //setup client
            client.BaseAddress = new Uri(apiBaseUri);
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            //client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Token.AccessToken);

            //setup login data
            var formContent = new FormUrlEncodedContent(new[]
             {
             new KeyValuePair<string, string>("grant_type", "password"), 
             new KeyValuePair<string, string>("username", userName), 
             new KeyValuePair<string, string>("password", password), 
             });

            //send request
            HttpResponseMessage responseMessage = await client.PostAsync("/Token", formContent);

            //get access token from response body
            var responseJson = await responseMessage.Content.ReadAsStringAsync();
            var jObject = JObject.Parse(responseJson);
            return jObject.GetValue("access_token").ToString();
        }
    }

在 Web API 项目中 WebAPIConfig.cs

        //Enable CORS
        var cors = new EnableCorsAttribute("*", "*", "GET");
        config.EnableCors(cors);

在 API 控制器中

    [HttpGet]
    //[Authorize]
    public List<FileInfo> GetFileTypes()
    {
        List<FileInfo> fileInfos = new List<FileInfo>();
        ...

在 StartAuth.cs 中

public void ConfigureAuth(IAppBuilder app)
    {
        // Configure the db context and user manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

        // Enable the application to use a cookie to store information for the signed in user
        // and to use a cookie to temporarily store information about a user logging in with a third party login provider
        app.UseCookieAuthentication(new CookieAuthenticationOptions());
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);

        // Configure the application for OAuth based flow
        PublicClientId = "self";
        OAuthOptions = new OAuthAuthorizationServerOptions
        {
            TokenEndpointPath = new PathString("/Token"),
            Provider = new ApplicationOAuthProvider(PublicClientId),
            AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
            // In production mode set AllowInsecureHttp = false
            AllowInsecureHttp = true
        };

        // Enable the application to use bearer tokens to authenticate users
        app.UseOAuthBearerTokens(OAuthOptions);

当我运行 WPF 并逐步执行代码时,它会到达发送请求行,然后就挂起。

谁能指点我正确的方向?

非常感谢

【问题讨论】:

    标签: c# wpf asp.net-web-api


    【解决方案1】:

    我认为你的问题的主要候选人是这一行:

    var token = GetAPIToken(email, password, "http://localhost:50006").Result;
    

    您正在调用async 方法,然后您正在同步等待其结果:这将导致死锁。永远不要那样做。

    相反,将您的方法(以及整个调用堆栈)异步化。如果您在 WPF 中,您几乎可以肯定会从某种事件处理程序回调中调用此方法。这些回调支持async(即使它们必须返回void)。

    将您的代码更改为与此类似的代码,然后重试(假设Form_Load 是事件处理程序回调):

    private async void Form_Load(object sender, EventArgs e)
    {
        await RefreshRecentFilesList();
    }
    
    internal async Task RefreshRecentFilesList()
    {
        //Get the token
        var token = await GetAPIToken(email, password, "http://localhost:50006");
        MessageBox.Show(token);
    }
    

    参考资料:
    Why does this async action hang?
    How to call asynchronous method from synchronous method in C#?

    【讨论】:

    • 感谢您的帮助,是同步和异步调用的混合导致了死锁。我根据您的建议重新编写了我的代码,现在我有一个功能齐全的 WPF 客户端调用安全的 Web API 方法。
    • 我已将答案标记为已解决。我还不能投票,我需要更多的声望点:-(
    【解决方案2】:

    Federico Dipuma 解决方案的补充是使用构造函数调用 Form_Load

    this.Loaded += new RoutedEventHandler(Form_Load);
    

    【讨论】:

    • 这应该怎么做?
    • 如果你是一个窗口和“代码隐藏”类,如果你有这个函数而没有被“调用”,指令将不会被执行。上面的代码将添加到路由事件并在页面完全加载后执行
    • 对不起,我还是不明白。因为接受的答案是正确的,我看不出这有什么帮助.. #NoOffense
    • 接受的答案是正确的,这是我在回答中提到的补充,如果你不知道什么是构造函数或如何调用函数显然你不会看到它的用途跨度>
    • 我在问题中看不到任何构造函数的使用。这不是让我感到困惑的地方。从来没有提到他的函数是由任何 FormEvents 触发的。也许你应该在你的答案中添加更多细节,因为只是说它的互补性而不谈论你的方法的优点/缺点,它甚至没有用#StillNoOffense
    猜你喜欢
    • 2020-01-24
    • 2022-10-31
    • 1970-01-01
    • 2011-03-26
    • 2012-12-19
    • 1970-01-01
    • 2011-11-29
    • 2019-05-05
    • 1970-01-01
    相关资源
    最近更新 更多