【问题标题】:Ajax Calls Web API With Forms AuthenticationAjax 使用表单身份验证调用 Web API
【发布时间】:2020-08-24 21:28:57
【问题描述】:

我们一直在开发一个 asp.net Web 应用程序,并且我们已经在应用程序中实现了表单身份验证。最近我们收到要求为其他系统公开应用程序的某些功能。所以我们计划为这个应用程序开发 Web API。我们需要将这些 Web API 托管在同一个 IIS Web 应用程序下,并且我们需要确保它们的安全。所以我在 Web API Controller 类中添加了[Authorize] 属性。

现在我对它的安全性感到困惑。如果我们保留表单身份验证,那么我如何才能对我的外部系统调用进行身份验证?或者我是否需要使用其他一些身份验证机制(例如:OAuth)但这会在我们拥有表单身份验证的同一个应用程序中工作吗?我还在 API Controller 类上启用了 COR。混乱只是关于安全机制。

我们有 Angular 应用程序和一个原生移动应用程序来使用这些 API。 Angular App 在 IIS 中单独托管,Mobile App 在 IOS 和 Android 上运行。

请提出解决方案,因为我不确定我应该朝哪个方向移动。

问候, 贾米尔

【问题讨论】:

  • 你听说过 jwt (Json web token) 认证吗

标签: asp.net-web-api oauth-2.0 owin forms-authentication


【解决方案1】:

我关注这篇文章Mixing MVC + Web API Authentication (Using Forms Auth + Basic Auth)

简而言之,对于外部系统,要对 WebAPI 进行身份验证,不能使用 Forms Auth,我们必须使用 Basic Auth 或 OAuth。除非整个应用程序升级为使用 OAuth,否则 OAuth 不能与 Form Auth 混合使用,但是通过为 Web API 定义 SecurityFilter,我们可以保持 Forms Authentication 在 Web 应用程序中工作,并且与此并行,我们可以定义 Basic Authentication Security,它将使用基本身份验证或我们可以使用的任何其他身份验证机制。

对我来说,这个解决方案有效。

  1. 我在 Web 表单项目中创建了一个 Web API 控制器。
  2. 默认情况下,由于使用 Web.Config 在整个站点级别启用表单身份验证。这个新控制器还使用表单身份验证进行保护。为了跳过这种安全性,我在 Web 配置中添加了一个位置标记,并允许所有用户访问 Web API 路径。

    <location path="api">
        <system.web>
            <authorization>
                <allow users="*" />
            </authorization>
        </system.web>
    </location>
    
  3. 接下来,我定义了安全过滤器类,并为请求实现了自己的认证和授权逻辑。

    public class BasicAuthenticationIdentity : GenericIdentity
    {
        public BasicAuthenticationIdentity(string name, string password)
            : base(name, "Basic")
        {
            this.Password = password;
        }
    
        /// 
        /// Basic Auth Password for custom authentication
        /// 
        public string Password { get; set; }
    }
    
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
    public class BasicAuthenticationFilter : AuthorizationFilterAttribute
    {
        bool Active = true;
    
        public BasicAuthenticationFilter()
        { }
    
        ///
        /// Overriden constructor to allow explicit disabling of this
        /// filter's behavior. Pass false to disable (same as no filter
        /// but declarative)
        ///
        ///
        public BasicAuthenticationFilter(bool active)
        {
            Active = active;
        }
    
        ///
        /// Override to Web API filter method to handle Basic Auth check
        ///
        ///
        public override void OnAuthorization(HttpActionContext actionContext)
        {
            if (Active)
            {
                var identity = ParseAuthorizationHeader(actionContext);
                if (identity == null)
                {
                    Challenge(actionContext);
                    return;
                }
    
                if (!OnAuthorizeUser(identity.Name, identity.Password, actionContext))
                {
                    Challenge(actionContext);
                    return;
                }
    
                var principal = new GenericPrincipal(identity, null);
    
                Thread.CurrentPrincipal = principal;
    
                // inside of ASP.NET this is required
                //if (HttpContext.Current != null)
                //    HttpContext.Current.User = principal;
    
                base.OnAuthorization(actionContext);
            }
        }
    
        ///
        /// Base implementation for user authentication - you probably will
        /// want to override this method for application specific logic.
        /// 
        /// The base implementation merely checks for username and password
        /// present and set the Thread principal.
        /// 
        /// Override this method if you want to customize Authentication
        /// and store user data as needed in a Thread Principle or other
        /// Request specific storage.
        ///
    
        protected virtual bool OnAuthorizeUser(string username, string password, HttpActionContext actionContext)
        {
            if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password))
                return false;
    
            return true;
        }
    
        ///
        /// Parses the Authorization header and creates user credentials
        ///
        protected virtual BasicAuthenticationIdentity ParseAuthorizationHeader(HttpActionContext actionContext)
        {
            string authHeader = null;
            var auth = actionContext.Request.Headers.Authorization;
            if (auth != null && auth.Scheme == "Basic")
                authHeader = auth.Parameter;
    
            if (string.IsNullOrEmpty(authHeader))
                return null;
    
            authHeader = Encoding.Default.GetString(Convert.FromBase64String(authHeader));
    
            var tokens = authHeader.Split(':');
            if (tokens.Length < 2)
                return null;
    
            return new BasicAuthenticationIdentity(tokens[0], tokens[1]);
        }
    
        ///
        /// Send the Authentication Challenge request
        ///
        void Challenge(HttpActionContext actionContext)
        {
            var host = actionContext.Request.RequestUri.DnsSafeHost;
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
            //actionContext.Response = actionContext.Request.CreateUserNoAccessResponse();
            actionContext.Response.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", host));
        }
    }
    

    public class MyBasicAuthenticationFilter : BasicAuthenticationFilter
    {
        public MyBasicAuthenticationFilter()
        { }
    
        public MyBasicAuthenticationFilter(bool active)
            : base(active)
        { }
    
        protected override bool OnAuthorizeUser(string username, string password, HttpActionContext actionContext)
        {
            return true;
            //MembershipHelper Members = new MembershipHelper(UmbracoContext.Current);
    
            //if (Members.Login(username, password))
            //{
            //    // Here you can also check against a specific member type or member group
    
            //    Members.Logout();
            //    return true;
            //}
            //return false;
        }
    }
    
    [MyBasicAuthenticationFilter]
    [EnableCors(origins: "*", headers: "*", methods: "*")]
    public class TestController : ApiController
    {
        public List<string> Get()
        {
            return new List<string>() { "Value 1", "Value 2" };
        }
    }
    

    var authHeaders = {};
    authHeaders.Authorization = 'Basic ' + atob(username + ":" + password);
    $.ajax({
       url: "http://localhost:49501/api/values",
       type: "GET",
       headers: authHeaders,
       success: function (response) {
       }
    });
    

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-26
    • 1970-01-01
    • 2018-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多