[WebAPI/C#] WebAPI Basic Authentication

Pagina: 1
Acties:

Acties:
  • 0 Henk 'm!

  • tha_crazy
  • Registratie: Maart 2007
  • Laatst online: 21:36
Ik ben op het moment een WebAPI aan het ontwikkelen welke vanaf de buitenwereld aangeroepen moet worden. Echter moet deze niet door de hele wereld aangeroepen kunnen worden.
Afgezien van HTTPS zal er ook een BA header meegegeven moeten worden.

Nu ben ik bezig deze te implementeren, echter skipt de controller steeds de BasicAuthentication.
Of ik nou wel of niet een header mee geef, het werkt altijd.

Op het moment gebruik ik dit:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
    public class BasicAuthenticationAttribute : ActionFilterAttribute
    {
        protected string Username { get; set; }
        protected string Password { get; set; }

        public BasicAuthenticationAttribute(string username, string password)
        {
            this.Username = username;
            this.Password = password;
        }

        public override void OnActionExecuting(ActionExecutingContext actionContext)
        {
            var request = actionContext.HttpContext.Request;
            var authorization = request.Headers["Authorization"];

            if (!String.IsNullOrEmpty(authorization))
            {
                var credentials = Encoding.UTF8.GetString(Convert.FromBase64String(authorization.Substring(6))).Split(':');
                var user = new { Name = credentials[0], Pass = credentials[1] };
                if (user.Name == Username && user.Pass == Password) return;
            }
            actionContext.Result = new HttpUnauthorizedResult();
        }
    }


En dit implementeer ik op de volgende manier:
C#:
1
2
3
4
5
        [BasicAuthentication("Test","ABC")]
        public string Get(string AccessToken, string Label)
        {
            //code hier
        }


Bronnen:
http://stackoverflow.com/...vice-basic-authentication
http://www.ryadel.com/en/...sing-custom-actionfilter/
http://stackoverflow.com/...tication-in-asp-net-mvc-5

Acties:
  • 0 Henk 'm!

  • DoDo
  • Registratie: Juli 2001
  • Laatst online: 23:23
Ik gok dat je nog even onderaan in "OnActionExecuting" de volgende regel moet zetten:
C#:
1
    base.OnActionExecuting(context);


Het wordt dan dus:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public override void OnActionExecuting(ActionExecutingContext actionContext)
{
    var request = actionContext.HttpContext.Request;
    var authorization = request.Headers["Authorization"];

    if (!String.IsNullOrEmpty(authorization))
    {
        var credentials = Encoding.UTF8.GetString(Convert.FromBase64String(authorization.Substring(6))).Split(':');
        var user = new { Name = credentials[0], Pass = credentials[1] };
        if (user.Name == Username && user.Pass == Password)
        {
            base.OnActionExecuting(context);
            return;
        }
    }
    
    actionContext.Result = new HttpUnauthorizedResult();
    base.OnActionExecuting(context);
}


Anders zet je de result wel van de actionContext, maar wordt er volgens niks mee gedaan.

[ Voor 11% gewijzigd door DoDo op 04-08-2016 13:56 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Unrelated: in deze regel mis ik 2 keer "this." - if (user.Name == Username && user.Pass == Password) return;

Acties:
  • 0 Henk 'm!

  • Merethil
  • Registratie: December 2008
  • Laatst online: 20:24
Verwijderd schreef op donderdag 04 augustus 2016 @ 14:05:
Unrelated: in deze regel mis ik 2 keer "this." - if (user.Name == Username && user.Pass == Password) return;
Gezien in de scope verder nergens Username en Password in gebruik zijn werkt dit prima.

Acties:
  • 0 Henk 'm!

Verwijderd

Ze zijn alleen niet geinitialiseerd in OnActionExecuting, en in BasicAuthenticationAttribute wordt de "this.Username" variant een waarde gegeven. Tenzij je in C# "this" gewoon weg mag laten, wat me stug lijkt... ;)

Acties:
  • 0 Henk 'm!

  • DanTm
  • Registratie: Juni 2002
  • Niet online
this mag je inderdaad weglaten in dit geval.
Wordt de functie wel aangeroepen in de Debugger?
Je zou nog kunnen testen door de het filter in je RegisterGlobalFilters op te nemen.

GlobalFilters.Filters.Add(new BasicAuthenticationAttribute());

Ik gebruik nagenoeg dezelfde code als GlobalFilter, en bij mij werkt het wel.

[ Voor 14% gewijzigd door DanTm op 04-08-2016 14:15 ]


Acties:
  • 0 Henk 'm!

  • Merethil
  • Registratie: December 2008
  • Laatst online: 20:24
Verwijderd schreef op donderdag 04 augustus 2016 @ 14:11:
Ze zijn alleen niet geinitialiseerd in OnActionExecuting, en in BasicAuthenticationAttribute wordt de "this.Username" variant een waarde gegeven. Tenzij je in C# "this" gewoon weg mag laten, wat me stug lijkt... ;)
Ze zijn geinitialiseerd buiten de functions als class variables, en worden assigned in de constructor. Daarna kan je ze prima zonder "this" gebruiken in een functie. Waarom zou dat niet kunnen?

Edit: Sterker nog, hij zou "this" weg kunnen halen in zijn constructor, kijk maar naar de casing van de parameters en de class variables. Alleen als ze gelijk zouden zijn zou "this" nog nodig moeten zijn op die locatie.

[ Voor 18% gewijzigd door Merethil op 04-08-2016 14:22 ]


Acties:
  • 0 Henk 'm!

  • tha_crazy
  • Registratie: Maart 2007
  • Laatst online: 21:36
DoDo schreef op donderdag 04 augustus 2016 @ 13:54:
Ik gok dat je nog even onderaan in "OnActionExecuting" de volgende regel moet zetten:
C#:
1
    base.OnActionExecuting(context);
Het toevoegen van base.OnActionExecuting(context); heeft helaas geen effect, de debugger komt nog niet in de OnActionExecuting methode.
DanTm schreef op donderdag 04 augustus 2016 @ 14:14:
this mag je inderdaad weglaten in dit geval.
Wordt de functie wel aangeroepen in de Debugger?
Je zou nog kunnen testen door de het filter in je RegisterGlobalFilters op te nemen.

GlobalFilters.Filters.Add(new BasicAuthenticationAttribute());
Na het toevoegen in de GlobalFilters kom ik wel in de OnActionExecuting bij het laden van de testpagina. Echter bij een aanroep naar de API blijft deze ongemoeid, ik begin dus eigenlijk het idee te krijgen dat deze manier niet toepasbaar is bij WebAPI

Edit: Wat ook nog eens bevestigd wordt in deze link:
http://stackoverflow.com/...tication-in-asp-net-mvc-5
1e antwoord, 3 commentaar.

[ Voor 7% gewijzigd door tha_crazy op 04-08-2016 14:19 ]


Acties:
  • 0 Henk 'm!

  • DanTm
  • Registratie: Juni 2002
  • Niet online
WebApi heeft weer zijn eigen opbouw, probeer eens:
GlobalConfiguration.Configuration.Filters.Add(new BasicAuthenticationAttribute());

Acties:
  • 0 Henk 'm!

  • DoDo
  • Registratie: Juli 2001
  • Laatst online: 23:23
Aha, het probleem is dan als volgt: WebAPI gebruikt andere ActionFilters dan MVC (met dezelfde naam).
Zorg dat je voor API de gene gebruikt uit
C#:
1
using System.Web.Http.Filters;


en niet uit
C#:
1
using System.Web.Mvc;

Acties:
  • 0 Henk 'm!

  • tha_crazy
  • Registratie: Maart 2007
  • Laatst online: 21:36
DoDo schreef op donderdag 04 augustus 2016 @ 14:21:
Aha, het probleem is dan als volgt: WebAPI gebruikt andere ActionFilters dan MVC (met dezelfde naam).
Zorg dat je voor API de gene gebruikt uit
C#:
1
using System.Web.Http.Filters;


en niet uit
C#:
1
using System.Web.Mvc;
Ziet er inderdaad naar uit dat ik de verkeerde gebruikte.
Na een aanpassing naar Filters en een nieuwe override geplaatst te hebben, begon hij deze wel netjes op te pikken.
Het resultaat is nu als volgt geworden:

C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
        public override void OnActionExecuting(HttpActionContext actionContext)
        {
            if(actionContext.Request.Headers.Authorization != null)
            {
                try
                {
                    var credentials = Encoding.UTF8.GetString(Convert.FromBase64String(actionContext.Request.Headers.Authorization.Parameter)).Split(':');
                    var user = new { Name = credentials[0], Pass = credentials[1] };
                    if (user.Name == Username && user.Pass == Password) return;
                }
                catch (Exception ex)
                {
                    actionContext.Response = new System.Net.Http.HttpResponseMessage(HttpStatusCode.Unauthorized);
                }
            }

            actionContext.Response = new System.Net.Http.HttpResponseMessage(HttpStatusCode.Unauthorized);

            base.OnActionExecuting(actionContext);
        }

[ Voor 9% gewijzigd door tha_crazy op 05-08-2016 09:14 ]


Acties:
  • 0 Henk 'm!

Verwijderd

Merethil schreef op donderdag 04 augustus 2016 @ 14:15:
[...]
Daarna kan je ze prima zonder "this" gebruiken in een functie. Waarom zou dat niet kunnen?
In de meeste andere programmeertalen kan dat niet, maar in C# blijkbaar wel - ik heb wel jaren in C/C++ geprogrammeerd, maar nog nooit in C#, vandaar. :)

Acties:
  • 0 Henk 'm!

  • Merethil
  • Registratie: December 2008
  • Laatst online: 20:24
Verwijderd schreef op donderdag 04 augustus 2016 @ 16:16:
[...]

In de meeste andere programmeertalen kan dat niet, maar in C# blijkbaar wel - ik heb wel jaren in C/C++ geprogrammeerd, maar nog nooit in C#, vandaar. :)
Ik ken eigenlijk niet anders maar mijn ervaring met C/C++ is niet heel groot en daarnaast is het jaren geleden dat ik dat voor 't laatst deed, dus daarom vroeg ik 't maar even :) Hoe dan ook, C#, Java, PHP en vast veel andere talen kunnen het met én zonder.

Acties:
  • 0 Henk 'm!

Verwijderd

PHP niet, hoor - in een class is $this->var heel wat anders dan $var.

Acties:
  • 0 Henk 'm!

  • Merethil
  • Registratie: December 2008
  • Laatst online: 20:24
Verwijderd schreef op donderdag 04 augustus 2016 @ 16:35:
PHP niet, hoor - in een class is $this->var heel wat anders dan $var.
Bijzonder, ik dacht altijd dat de scope in PHP ook zo werkte. Ik laat het maar staan, maar je hebt helemaal gelijk.

Acties:
  • 0 Henk 'm!

  • pretender 0
  • Registratie: September 2007
  • Laatst online: 23:17
Verwijderd schreef op donderdag 04 augustus 2016 @ 16:16:
[...]

In de meeste andere programmeertalen kan dat niet, maar in C# blijkbaar wel - ik heb wel jaren in C/C++ geprogrammeerd, maar nog nooit in C#, vandaar. :)
in c++ mag je this in zo'n scenario ook weglaten.

Acties:
  • +1 Henk 'm!

  • Sebazzz
  • Registratie: September 2006
  • Laatst online: 14:51

Sebazzz

3dp

Mag ik vragen waarom je geen IAuthorizationFilter gebruikt?

[Te koop: 3D printers] [Website] Agile tools: [Return: retrospectives] [Pokertime: planning poker]


Acties:
  • 0 Henk 'm!

Verwijderd

pretender 0 schreef op donderdag 04 augustus 2016 @ 20:55:
in c++ mag je this in zo'n scenario ook weglaten.
Het is alweer bijna 20 jaar geleden, dus - ik geloof je! ;)

Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Verwijderd schreef op donderdag 04 augustus 2016 @ 22:42:
[...]

Het is alweer bijna 20 jaar geleden, dus - ik geloof je! ;)
Je hoeft this alleen te gebruiken om ambiguïteit tussen variabelen te resolven. Aangezien die er hier niet is, wordt gewoon de variabele op class scope gepakt. Anders zou het natuurlijk ook een compiler opleveren, aangezien er in de method scope zelf helemaal geen variabele met die naam gedeclareerd is.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • tha_crazy
  • Registratie: Maart 2007
  • Laatst online: 21:36
Sebazzz schreef op donderdag 04 augustus 2016 @ 20:57:
Mag ik vragen waarom je geen IAuthorizationFilter gebruikt?
Eigenlijk het enige voorbeeld wat ik echt kon vinden waarin de OnAuthorization method gebruikt was, was deze https://weblog.west-wind....tion-authorization-filter
Deze was echter te uitgebreid voor mijn doeleinden, plus dat ik er rekening mee moet houden dat als ik omval om wat voor reden dan ook, iemand er blind mee moet verder kunnen gaan (en de kennis hiervan is niet zo super op de afdeling)

Dus besloten over de OnActionExecuting wat precies doet wat wij moeten doen, in een duidelijke manier, zonder overhead

Acties:
  • 0 Henk 'm!

  • Haan
  • Registratie: Februari 2004
  • Laatst online: 21:16

Haan

dotnetter

Ik heb nog even vergeleken met m'n eigen implementatie, die is gelijk aan wat je nu hebt, met als enige verschil dat ik eerst check of er wel een Basic authentication header binnenkomt:
C#:
1
2
3
4
if (actionContext.Request.Headers.Authorization.Scheme != "Basic")
{
    return;
}

Kater? Eerst water, de rest komt later


Acties:
  • 0 Henk 'm!

  • tha_crazy
  • Registratie: Maart 2007
  • Laatst online: 21:36
Haan schreef op vrijdag 05 augustus 2016 @ 10:17:
Ik heb nog even vergeleken met m'n eigen implementatie, die is gelijk aan wat je nu hebt, met als enige verschil dat ik eerst check of er wel een Basic authentication header binnenkomt:
C#:
1
2
3
4
if (actionContext.Request.Headers.Authorization.Scheme != "Basic")
{
    return;
}
Ik heb het ook aangepast hierboven.
Onderandere een if/else om te kijken of die er is.
Daarnaast een try/catch eromheen voor als de conversie van base64 een error geeft.

In alle gevallen waarin het mis gaat alleen een 401 gooien, niet meer niet minder.

Acties:
  • 0 Henk 'm!

  • Mercatres
  • Registratie: September 2009
  • Laatst online: 10-10 12:25
Gebruik je WebAPI 1 of WebAPI 2.x? Er zijn nogal wezenlijke verschillen tussen die twee, vooral in de Requesthandling.
Pagina: 1