【问题标题】:authorization always returns 401授权总是返回 401
【发布时间】:2016-05-22 05:40:23
【问题描述】:

我正在尝试使用 web 调用 rest api 创建一个 SOA,但我遇到了授权问题。 AuthenticateUser 可以获得“test”作为用户和密码,但在 OnApplicationEndRequest 中无论如何都会返回 401。我错过了什么?

请询问任何额外的信息,我会尽力而为。

使用 IIS Express

ApiController

[Authorize]
public class BookController : ApiController
{
   public object Get()
   {
       return "";
   }
}

REST - 身份验证模块

namespace REST.Modules
{
    public class BasicAuthHttpModule : IHttpModule
    {
        private const string Realm = "XX WebAPI";

        public void Init(HttpApplication context)
        {
            // Register event handlers
            context.AuthenticateRequest += OnApplicationAuthenticateRequest;
            context.EndRequest += OnApplicationEndRequest;
        }

        private static void SetPrincipal(IPrincipal principal)
        {
            Thread.CurrentPrincipal = principal;
            if (HttpContext.Current != null)
            {
                HttpContext.Current.User = principal;
            }
        }

        private static bool AuthenticateUser(string credentials)
        {
            var encoding = Encoding.GetEncoding("iso-8859-1");
            credentials = encoding.GetString(Convert.FromBase64String(credentials));

            var credentialsArray = credentials.Split(':');
            var username = credentialsArray[0];
            var password = credentialsArray[1];

            if (!(username == "test" && password == "test"))
            {
                return false;
            }

            var identity = new GenericIdentity(username);
            SetPrincipal(new GenericPrincipal(identity, null));

            return true;
        }

        private static void OnApplicationAuthenticateRequest(object sender, EventArgs e)
        {
            var request = HttpContext.Current.Request;
            var authHeader = request.Headers["Authorization"];
            if (authHeader != null)
            {
                var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);

                // RFC 2617 sec 1.2, "scheme" name is case-insensitive
                if (authHeaderVal.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase) && authHeaderVal.Parameter != null)
                {
                    AuthenticateUser(authHeaderVal.Parameter);
                }
            }
        }

        // If the request was unauthorized, add the WWW-Authenticate header
        // to the response.
        private static void OnApplicationEndRequest(object sender, EventArgs e)
        {
            var response = HttpContext.Current.Response;
            if (response.StatusCode == 401)
            {
                response.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", Realm));
            }
        }

        public void Dispose()
        {
        }
    }
}

网络

    readonly static string baseUri = "http://localhost:XXXX/api/book/";

    public static void GetBookList()
    {
        string uri = baseUri;
        using (HttpClient httpClient = new HttpClient(new HttpClientHandler { Credentials = new NetworkCredential("test", "test") }))
        {
            Task<HttpResponseMessage> response = httpClient.PostAsJsonAsync(uri, data);
            var x = response.Result.Content.ReadAsAsync<object>().Result.ToJson();
        }
    }

applicationhost.config

        <authentication>

            <anonymousAuthentication enabled="false" userName="" />

            <basicAuthentication enabled="true" />

            <clientCertificateMappingAuthentication enabled="false" />

            <digestAuthentication enabled="false" />

            <iisClientCertificateMappingAuthentication enabled="false">
            </iisClientCertificateMappingAuthentication>

            <windowsAuthentication enabled="true">
                <providers>
                    <add value="Negotiate" />
                    <add value="NTLM" />
                </providers>
            </windowsAuthentication>

        </authentication>

        <authorization>
            <add accessType="Allow" users="*" />
        </authorization>

ApplicationUserManager

    public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
    {
        var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
        // Configure validation logic for usernames
        manager.UserValidator = new UserValidator<ApplicationUser>(manager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };
        // Configure validation logic for passwords
        manager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = true,
            RequireDigit = true,
            RequireLowercase = true,
            RequireUppercase = true,
        };
        var dataProtectionProvider = options.DataProtectionProvider;
        if (dataProtectionProvider != null)
        {
            manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
        }
        return manager;
    }

【问题讨论】:

    标签: c# .net soa restful-authentication


    【解决方案1】:

    您似乎没有为您的测试用户创建身份,您立即返回 false,所以如果您想拥有 test@test 帐户(您应该非常小心不要离开生产),那么您需要在这种情况下也可以创建身份。

    缺少身份会导致 ASP.NET 生成 401,因为您有 [Authorize] 属性。

    【讨论】:

    • 我认为 ApplicationUserManager 会即时创建用户(代码添加到问题中)我尝试添加 Windows 用户,因为测试/测试不起作用。我应该如何添加该帐户?
    • 问题是在将主体设置为线程之前,您确实返回 false。
    • 看来test/test是唯一的用户,你用那个用户登录吗?我认为您根本不需要一个帐户来获得 401,这些没有连接。我认为我之前的评论是错误的,所以我可能误解了这个问题。
    【解决方案2】:

    您需要从 ApplicationUser 对象创建一个身份

    private async Task SignInAsync(ApplicationUser user, bool isPersistent)
        {
            AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
    
    
            var identity = await pApplicationUserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
    
    
            AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
        }
    

    【讨论】:

      【解决方案3】:

      两件事:

      1. 在 OnApplicationAuthenticateRequest 方法中设置未授权的标头可能会更好。这样相同的方法要么授权要么拒绝。
      2. 您需要为用户分配一个角色。空角色与无角色不同。

            private static bool AuthenticateUser(string credentials)
            {
                var encoding = Encoding.GetEncoding("iso-8859-1");
                credentials = encoding.GetString(Convert.FromBase64String(credentials));
        
                var credentialsArray = credentials.Split(':');
                var username = credentialsArray[0];
                var password = credentialsArray[1];
        
                if (!(username == "test" && password == "test"))
                {
                    return false;
                }
        
                var identity = new GenericIdentity(username);
                //0 roles not null roles
                SetPrincipal(new GenericPrincipal(identity, string[]{})); 
        
                return true;
            }
        
            private static void OnApplicationAuthenticateRequest(object sender, EventArgs e)
            {
                var request = HttpContext.Current.Request;
                var authHeader = request.Headers["Authorization"];
                if (authHeader != null)
                {
                    var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);
        
                    // RFC 2617 sec 1.2, "scheme" name is case-insensitive
                    if (authHeaderVal.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase) && authHeaderVal.Parameter != null)
                    {
                        bool userIsAuthenticated =AuthenticateUser(authHeaderVal.Parameter);
                        //If not authenticated then user is not Authorized.
                        if (!userIsAuthenticated){
                           addUnauthorizedHeader()
                        }
                    }
        
                }
            }
        
           private static void addUnauthorizedHeader(){
                 response.Headers.Add("WWW-Authenticate", string.Format("Basic realm=\"{0}\"", Realm));
           }
        

      【讨论】:

        猜你喜欢
        • 2019-08-10
        • 1970-01-01
        • 2014-07-03
        • 2019-08-29
        • 2018-05-19
        • 2018-01-01
        • 1970-01-01
        • 2018-11-03
        • 2018-01-09
        相关资源
        最近更新 更多