WebAPI [Login] error at login

I am trying to configure WebAPIto MVC5/ Web Api 2, it is currently using default configurations and other default values ​​right now. When I log into the system with an account in the browser, I can go to the regular controller actions MVCwith the attribute [Authorize]just fine, for example, on the home page, as it should, when allowed, but if I go to /api/Me(default built-in api controller action) or any The custom action of the api controller that I built using the standard MVC Web Api 2, which require authorization, I get this error:

{"message":"Authorization has been denied for this request."}

This is when I try in Microsoft Edge, I have not tried it on my actual client code that I create, which is an application UWP. I decided that I would first check in the browser so that everything worked correctly.

I started to study this article: https://docs.microsoft.com/en-us/aspnet/web-api/overview/security/individual-accounts-in-web-api Although it seems to be more query oriented Ajaxand SPAs. My goal is for things to work both through the Internet and through UWP. I will probably focus more on the side UWPthan on developing a reliable web application with ajax, since the application will run on the intranet and access the IIS server on the intranet running the web api, I would like to create a client table in UWP and, ultimately, Xamarin, who access data through Web Api.

Can you assume that if you use a regular web browser such as Edge, you cannot access the actions of the Web Api controller if they are protected with an attribute [Authorize], since it does not send an access token to the header?

+1
source share
2 answers

So, from your UWP application, you can create several methods, for example, below, or you can wrap them in a class that you can enter through DI (your choice).

public async Task<TResult> GetAsync<TResult>(string uriString) where TResult : class
    {
        var uri = new Uri(uriString);
        using (var client = GetHttpClient())
        {
            HttpResponseMessage response = await client.GetAsync(uri);
            if (response.StatusCode != HttpStatusCode.OK)
            {
                //Log.Error(response.ReasonPhrase);
                return default(TResult);
            }
            var json = await response.Content.ReadAsStringAsync();
            return JsonConvert.DeserializeObject<TResult>(json, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() });
        }
    }

    public async Task<TResult> PostAsync<TResult, TInput>(string uriString, TInput payload = null) where TInput : class
    {
        var uri = new Uri(uriString);
        using (var client = GetHttpClient())
        {
            var jsonContent = JsonConvert.SerializeObject(payload, Formatting.Indented, new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() });
            HttpResponseMessage response = await client.PostAsync(uri, new StringContent(jsonContent, Encoding.UTF8, "application/json"));
            if (response.StatusCode != HttpStatusCode.OK)
            {
                //Log.Error(response.ReasonPhrase);
                return default(TResult);
            }
            var json = await response.Content.ReadAsStringAsync();
            return JsonConvert.DeserializeObject<TResult>(json);
        }
    }

And if you use basic (username and password authentication), then your GetHttpClient method will look something like this:

private HttpClient GetHttpClient()
    {
        var client = new HttpClient();
        var username = // get username;
        var password = // get password;
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}")));
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        return client;
    }

or if you use a carrier token, then you can do:

client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer ", "string token goes here...");
+2
source

, , MVC5/Web Api 2 , UWP Xamarin, Api Authorize.

, , MVC, POST /Token ( ).

, SSL , , :

C:\Program Files (x86)\IIS Express>iisexpressadmincmd setupSslUrl -url:https://localhost:55970/ -UseSelfSigned

55970 - -, .

, , ApplicationOAuthProvider.cs , .

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
    {
        context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });

        UserManager<ApplicationUser> _userManager;
        ApplicationDbContext db = new ApplicationDbContext();
        _userManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(db));
        try
        {

            ApplicationUser user = await _userManager.FindAsync(context.UserName, context.Password);


            if (user == null)
            {
                context.SetError("invalid_grant", "The user name or password is incorrect.");
                return;
            }

            var identity = new ClaimsIdentity(context.Options.AuthenticationType);
            identity.AddClaim(new Claim("sub", context.UserName));
            identity.AddClaim(new Claim("role", "user"));

            context.Validated(identity);
        }
        catch (Exception ex)
        {
            string str = ex.ToString();
        }

        db.Dispose();
    }

    public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
    {
        string clientId = "";
        string clientSecret = "";
        context.TryGetFormCredentials(out clientId, out clientSecret);

        List<string> validClients = new List<string>(){ "web","Alliance_UWP","Alliance_Xamarin","Alliance_Web" };
        if (validClients.Contains(clientId))
            context.Validated();
    }

, , "-" , Http POST url, grant_type = "" /. UWP, , / , api, Authorize. , , .

, , IIS Express .

    Uri tokenUri = new Uri(@"https://localhost:55970/Token");
    // This is a test data set from my Web Api pulling data from 
    // Entity Framework and SQL Server protected by the Authorize attribute
    Uri testCasesUri = new Uri(@"https://localhost:55970/api/Cases");
    string accessToken = "";

    public MainPage()
    {
        this.InitializeComponent();
    }

    private async void btn_SubmitLogin_Click(object sender, RoutedEventArgs e)
    {
        string username = txt_User.Text;
        string password = txt_Password.Password;

        HttpBaseProtocolFilter filter = new HttpBaseProtocolFilter();
        filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.Untrusted);
        filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.InvalidName);
        filter.IgnorableServerCertificateErrors.Add(ChainValidationResult.RevocationFailure);
        HttpClient client = new HttpClient(filter);
        Dictionary<string, string> parameters = new Dictionary<string, string>();
        parameters.Add("client_id", "web");
        parameters.Add("grant_type", "password");
        parameters.Add("username", username);
        parameters.Add("password", password);
        try
        {
            HttpResponseMessage result = await client.PostAsync(tokenUri, new HttpFormUrlEncodedContent(parameters));
            string jsonResult = await result.Content.ReadAsStringAsync();
            // TokenResult is a custom model class for deserialization of the Token Endpoint
            // Be sure to include Newtonsoft.Json from NuGet
            var resultObject = JsonConvert.DeserializeObject<TokenResult>(jsonResult);
            accessToken = resultObject.AccessToken;

            // When setting the request for data from Web Api set the Authorization
            // header to Bearer and the token you retrieved
            client.DefaultRequestHeaders.Add("Authorization", "Bearer " + accessToken);
            result = await client.GetAsync(testCasesUri);
            jsonResult = await result.Content.ReadAsStringAsync();

        } catch(Exception ex)
        {
            string debugBreak = ex.ToString();
        }

, - , Xamarin UWP Web Api.

0

Source: https://habr.com/ru/post/1016261/


All Articles