使用 OWIN 从 SPA 到 Web API 对用户进行身份验证时未找到 TokenEndPoint

TokenEndPoint not found while authenticating user from SPA to Web API using OWIN

我在使用从 Angular JS SPA 页面到 WEB API 的令牌机制对用户进行身份验证时遇到困难。

我不想使用 ASP.NET 身份默认值 table 添加或验证用户。我有自己的数据库和一个名为 "EmployeeAccess" table 的 table,其中包含 EmployeeNumber 作为用户 ID 和密码。我想根据 table 中的值对用户进行身份验证,然后授予令牌以便他们获得后续调用的授权。我已经使用了所有必需的 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);
        }
    }

Login.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;
}])

点击登录按钮时出现以下两个错误:-

OPTIONS http://localhost:60544/Token 404 (Not Found)

XMLHttpRequest cannot load http://localhost:60544/Token. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:60512' is therefore not allowed access. The response had HTTP status code 404.

我搜索了很多 post,但 post 中的 none 符合我的条件,所以考虑 post 我的查询。 请帮助我。

错误是 OPTIONS 调用的结果。

The HTTP OPTIONS method is used to describe the communication options for the target resource. The client can specify a specific URL for the OPTIONS method, or an asterisk (*) to refer to the entire server.

由于您不处理这些,您将看到 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();
        }
    }
}