TokenEndPoint не найден при аутентификации пользователя из SPA в веб-API с использованием OWIN

Я сталкиваюсь с трудностями при аутентификации пользователей с использованием механизма токенов от Angular JS SPA Page до WEB API.

Я не хочу использовать таблицы ASP.NET Identity по умолчанию для добавления или аутентификации пользователя. У меня есть собственная база данных и таблица с именем «EmployeeAccess», которая содержит EmployeeNumber в качестве идентификатора пользователя и пароля. Я хочу аутентифицировать пользователей по значениям в этой таблице, а затем хочу предоставить токен, чтобы они были авторизованы для последующего вызова. Я использовал все необходимые ссылки OWIN и ASP.NET для достижения результата.

См. соответствующий код ниже: -

Startup.cs

[assembly: OwinStartup(typeof(Application.WebAPI.Startup))]

namespace Application.WebAPI
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888
            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
            var myProvider = new AuthorizationServerProvider();
            OAuthAuthorizationServerOptions options = new OAuthAuthorizationServerOptions
            {
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/Token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
                Provider = myProvider
            };
            app.UseOAuthAuthorizationServer(options);
        }
    }
}

AuthorizationServerProvider.cs

public class AuthorizationServerProvider : OAuthAuthorizationServerProvider
    {
        public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            context.Validated(); // 
        }

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

            EmployeeAccessBLL chkEmpAccessBLL = new EmployeeAccessBLL();
            EmployeeAccessViewModel vmEmployeeAccess = chkEmpAccessBLL.CheckEmployeeAccess(Convert.ToInt32(userId), password);

            if(vmEmployeeAccess != null)
            {
                var identity = new ClaimsIdentity(context.Options.AuthenticationType);
                identity.AddClaim(new Claim("username", vmEmployeeAccess.EmpName));
                context.Validated(identity);
            }

            else
            {
                context.SetError("invalid_grant", "Provided username and password is incorrect");
                return;
            }
        }
    }

WebApiConfig.cs

public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {            
            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));
            config.Formatters.Remove(config.Formatters.XmlFormatter);

            var cors = new EnableCorsAttribute("*", "*", "*");
            config.EnableCors(cors);
        }
    }

Логин.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.0/angular.min.js"></script>
    <script src="../Scripts/AngularControllers/LoginController.js"></script>
    <script src="../Scripts/AngularServices/ApiCallService.js"></script>
</head>
<body ng-app="appHome">
    <div ng-controller="ctrlLogin">
        <label>Employee Number</label>
        <input type="text" id="txtEmpNumber" ng-model="md_empnumber" />
        <br/>
        <br/>
        <label>Password</label>
        <input type="text" id="txtEmpNumber" ng-model="md_password"  />

        <button id="btnAdd" type="submit" ng-click="Login()">Login</button>
    </div>
</body>
</html>

LoginController.js

var myApp = angular.module('appHome', []);
myApp.controller("ctrlLogin", ['$scope', 'MetadataOrgFactory', '$location', function ($scope, MetadataOrgFactory, $location) {
    $scope.Login = function () {
        var objLogin = {
            'username' : $scope.md_empnumber,
            'password' : $scope.md_password,
            'grant_type' : 'password'
        };

        MetadataOrgFactory.postLoginCall('Token', objLogin, function (dataSuccess) {
            alert("Welcome " + dataSuccess);           
        }, function (dataError) {
        });
    }
}]);

ApiCallService.js

var appService = angular.module('appHome');

appService.factory('MetadataOrgFactory', ['$http', function ($http) {

    var url = 'http://localhost:60544';

    var dataFactory = {};

    dataFactory.postLoginCall = function (controllerName, objData, callbackSuccess, callbackError) {

        $http.post(url + '/' + controllerName, objData).then
            (function success(response) {
                alert("Success");
                callbackSuccess(response.data);
            }, function error(response) {
                callbackError(response.status);
            });
    };
    return dataFactory;
}])

Я получаю следующие две ошибки при нажатии кнопки входа в систему: -

ВАРИАНТЫ http://localhost:60544/Token 404 (не найдено)

XMLHttpRequest не может загрузить http://localhost:60544/Token. Ответ на предварительный запрос не проходит проверку управления доступом: в запрошенном ресурсе отсутствует заголовок «Access-Control-Allow-Origin». Таким образом, доступ к источнику 'http://localhost:60512' запрещен. В ответе был код состояния HTTP 404.

Я просмотрел много постов, но ни один из постов не соответствует моим критериям, поэтому решил опубликовать свой запрос. Пожалуйста, помогите мне в этом.




Ответы (1)


Ошибка является результатом вызова OPTIONS.

Метод HTTP OPTIONS используется для описания параметров связи для целевого ресурса. Клиент может указать конкретный URL-адрес для метода OPTIONS или звездочку (*) для ссылки на весь сервер.

Поскольку вы не обрабатываете их, вы увидите 404 (не найдено). Вы можете прочитать о CORS здесь: https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS

Один из способов реализовать это — добавить в Global.asax следующий код:

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        GlobalConfiguration.Configure(WebApiConfig.Register);
    }

    protected void Application_BeginRequest()
    {
        if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
        {
            // Cache the options request.
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", HttpContext.Current.Request.Headers["Origin"]);
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET, PUT, DELETE, POST, OPTIONS");
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Accept, Authorization");
            HttpContext.Current.Response.AddHeader("Access-Control-Max-Age", "1728000");
            HttpContext.Current.Response.End();
        }
    }
}
person Ruard van Elburg    schedule 29.06.2017
comment
Это прекрасно работает. Спасибо за ваш ответ. Старые сообщения об ошибках исчезли. Теперь новое сообщение об ошибке выглядит следующим образом: Не удалось загрузить ресурс: сервер ответил со статусом 400 (неверный запрос). Любая идея по этому поводу? - person simple user; 30.06.2017
comment
Когда я нажимаю кнопку входа в систему, она вызывает метод ValidateClientAuthentication в классе AuthorizationServerProvider. Прежде чем достичь метода GrantResourceOwnerCredentials, он фактически выдает сообщение об ошибке Bad Request (400). Может ли кто-нибудь помочь, что следует добавить в сообщение запроса после просмотра моего кода, написанного в основном сообщении.? - person simple user; 30.06.2017