Basic Authentication via Angular, why is this thro

2019-04-16 08:29发布

问题:

I have an Angular application that I'm trying to authenticate with Basic authentication to my REST service. I'm adding the authorization header with the corresponding "Base {username:password}" encoded in base64 and I'm calling my rest api but keep getting back a 401. I'm obviously missing a step here...

Here's the angular code:

angular
    .module('myApp.services')
    .factory('AuthenticationService', ['$http', '$q', '$location', 'Base64', 'SessionService', function ($http, $q, $location, encoder, session) {
        return {
            authenticate:
                function (user, password) {

                    var deferred = $q.defer();
                    var url = "http://localhost:28924/api/login";

                    if (user && password) {
                        var encoded = encoder.encode(user + ':' + password);
                        $http.defaults.headers.common.Authorization = 'Basic ' + encoded;
                        console.log('here');
                        sessionStorage.setItem('Authorization', $http.defaults.headers.common.Authorization);

                        $http.get(url)
                            .success(function (data, status, headers, config) {
                                console.log('login Successful in Authentication service');
                                deferred.resolve(data);
                                session.setSession();
                            })
                            .error(function (data, status, headers, config) {
                                deferred.reject(status);
                            });
                    }
                    else {
                        deferred.reject(401);
                    }

                    return deferred.promise;
                },
            logout:
                function () {
                    $http.defaults.headers.common.Authorization = null;
                    $http.defaults.headers.common.Impersonate = null;
                    $location.url('/login');
                }
        };
    }
    ]
);

Here's my LoginController:

public class LoginController : ApiController
{
    public LoginController()
    {

    }
    [Authorize]
    public HttpResponseMessage Get()
    {
        //return this.ControllerContext.Request.CreateResponse(HttpStatusCode.OK);

        if (this.User.Identity.IsAuthenticated)
        {
            return this.ControllerContext.Request.CreateResponse(HttpStatusCode.OK);
        }
        return this.ControllerContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
    }
}

And I've also set my IISExpress config file to "Allow" basic authentication, like described here: set basic authentication in IIS Express.

Does just adding the "Authorize" attribute to my Get method let the host know to check the credentials that were passed in the Authorization header? Or do I need to implement something extra, like in this SO post (the question part): basic authentication with custom message handler?

It seems to me that there needs to be more in my "Get" method, but I can't find any good examples to help walk me through this....(if you haven't figure it out, this is my first try with basic authentication AND REST api/services.

Edit: Aha! I'm getting closer. @Chandermani's response for some reason prompted me to check out my OWN web.config and I realized I didn't have this:

<security>
  <authentication>
    <basicAuthentication enabled="true"/>
  </authentication>
</security>

Adding this now prompts me for my credentials when navigating to the .../api/login page.

Edit2: Checking to see what was sent across the wire via Chrome Dev tools shows that the authorization header is being sent, while specifying Basic authentication and my base64 encoded username and password. Here's what it looks like:

Request URL:http://localhost:28924/api/login
Request Method:GET
Status Code:401 Unauthorized
Request Headersview source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Authorization:Basic YWblahblahblahDE=
Connection:keep-alive
Host:localhost:28924
Referer:http://localhost:28924/index.html
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
Response Headersview source
Cache-Control:private
Content-Length:6333
Content-Type:text/html; charset=utf-8
Date:Wed, 08 Jan 2014 14:32:14 GMT
Server:Microsoft-IIS/8.0
WWW-Authenticate:Negotiate
WWW-Authenticate:NTLM
WWW-Authenticate:Basic realm="localhost"
X-Powered-By:ASP.NET
X-SourceFiles:=?UTF-8?B?QzpcU291cmNlQ29kZVxUcmlhbHNNb2JpbGVcVHJhaWxzTW9iaWxlLldlYlxhcGlcbG9naW4=?=

When the api/login page prompts me for my credentials it gets stuck in an infinite loop. I'll enter them, hit enter, then it asks for them again.

Edit3: Ok, I'm able to authenticate!!! I had to specify the domain in front of my username since I'm running localhost...

Thanks everyone for pointing me in the right direction!

回答1:

A combination of changes led to fixing my problem:

1) I needed to allow basic authentication in my OWN web.config. I had only previously set it up in the IISExpress applicationhost.config (see Edit(1))

2) Showing the output from Chrome Dev tools proved that the Basic Authentication authorization header was, in fact, being sent across.

3) The last problem was since I'm running on localhost, I needed to specify the domain to authenticate against in my username. There's probably a cleaner way of doing this, but I just entered this in my username field: mydomain\ganders and it started working.