C#[Authorize]属性无法在集成测试中与Microsoft.Owin.Testing一起使用

问题描述

我正在尝试使用带有[Authorize]属性Owin创建WebApi项目的IntegrationTests。我完全没有授权方面的经验。 我们正在Service项目中使用Bearer令牌类型的授权注册

public static void ConfigureBasicWithJWT(IAppBuilder app)
{
app.USEOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
    AllowInsecureHttp = true,TokenEndpointPath = new PathString("/auth/token"),AccesstokenExpireTimeSpan = TimeSpan.FromDays(1),//token expiration time  
    Provider = new OauthProvider()
});

// token consumption
var oauthConfig = new OAuthBearerAuthenticationoptions
{
    AuthenticationMode = AuthenticationMode.Active,AuthenticationType = "Bearer"
};
app.USEOAuthBearerAuthentication(oauthConfig);
}

OAuth提供者:

public class OauthProvider : OAuthAuthorizationServerProvider
    {
        public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
        {
            await Task.Run(() => context.Validated());
        }

        private bool IsAuthorized(MobileSecLogin login,OAuthGrantResourceOwnerCredentialsContext context)
        {
            if (login == null || context == null) return false;

            //verify by login/pwd first
            if (SecurePasswordHasher.Verify(context.Password,login.PassHash))
                return true;


            //verify by login/token
            if (SecurePasswordHasher.Verify(context.Password,login.LoginTokenHash) && login.LoginTokenExpiration < DateTimeOffset.Now)
                return true;

            return false;
        }

        public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
        {
            var identity = new ClaimsIdentity(context.Options.AuthenticationType);

            using (var db = APIContext.MobileDBContext)
            {
                if (db != null)
                {
                    //verify by login + password
                    //verify by login + token,but token must be valid in time
                    var login = db.Logins.GetLoginobjByLogin(context.UserName);
                    if (!IsAuthorized(login,context))
                    {
                        context.SetError("Wrong Credentials","Provided username and password is incorrect");
                        return;
                    }

                    var user = login?.User;
                    if (user != null)
                    {
                        //get all functional roles from all asigned groups or their children groups
                        var childGroups = db.Groups.GetChildGroups(user.Groups).ToList();
                        var funcRoles = db.Roles.GetAllRoles(childGroups);
                        foreach (var secRole in funcRoles)
                        {
                            identity.AddClaim(new Claim(ClaimTypes.Role,secRole.Name));
                        }

                        //including all role names
                        var loggedDate = DateTime.Now;
                        foreach (var childGroup in childGroups)
                        {
                            identity.AddClaim(new Claim(ClaimTypes.Role,childGroup.Name));
                        }
                        identity.AddClaim(new Claim(ClaimTypes.Name,user.Name));
                        identity.AddClaim(new Claim(ClaimTypes.Surname,user.LastName));
                        identity.AddClaim(new Claim(ClaimTypes.NameIdentifier,login.Id.ToString()));
                        identity.AddClaim(new Claim(ClaimTypes.Email,user.Email));
                        identity.AddClaim(new Claim("LoggedOn",loggedDate.ToString()));

                        //set lastLoginDate
                        login.LastLoginDate = loggedDate;
                        APIContext.AuditUser = login.User;
                        db.AuditUser = login.User;
                        db.SaveChanges();
                        await Task.Run(() => context.Validated(identity));
                    }
                    else
                    {
                        APIContext.AuditUser = null;
                        db.AuditUser = null;
                        context.SetError("Wrong Credentials","Provided username and password is incorrect");
                    }
                }
                else
                {
                    APIContext.AuditUser = null;
                    db.AuditUser = null;
                    context.SetError("Wrong Credentials","Provided username and password is incorrect");
                }
                return;
            }
        }
    }

示例控制器方法

        [HttpGet]
        [Route("auth/users/{guid}")]
        [Authorize]
        public HttpResponseMessage GetMobileUser(string guid)
        {
            var manager = new MobileSecUserManager(context);
            return Request.CreateJsonResponseFromObject(manager.GetByGuid(guid));
        }

当我实际构建并运行该服务时,此设置始终有效。我可以请求Bearer令牌并在其他请求中使用它,并且它可以正常工作,我已获得请求的授权。

在集成测试项目中,我正在使用Owin.Testing TestServer:

public class WebAPITestStartup : Program
    {
        public override void Configuration(IAppBuilder appBuilder)
        {
            var configuration = new HttpConfiguration();
            configuration.MapHttpAttributeRoutes();
            configuration.Formatters.Clear();
            configuration.Formatters.Add(new JsonMediaTypeFormatter());
            appBuilder.UseCors(CorsOptions.AllowAll);
            appBuilder.UseWebApi(configuration);
            CallControlleRSStaticConstructors();
            ConfigureBasicWithJWTTest(appBuilder);
        }

        public static void ConfigureBasicWithJWTTest(IAppBuilder app)
        {
            app.USEOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
            {
                AllowInsecureHttp = true,//token expiration time  
                Provider = new OauthProvider()
            });

            var oauthConfig = new OAuthBearerAuthenticationoptions
            {
                AuthenticationMode = AuthenticationMode.Active,AuthenticationType = "Bearer",};
            app.USEOAuthBearerAuthentication(oauthConfig);
        }
         protected void CallControlleRSStaticConstructors()
        {
            foreach (var type in Assembly.GetExecutingAssembly().DefinedTypes.Where(type => type.IsSubclassOf(typeof(ApiController))))
                InvokeStaticConstractor(type);
        }

        private void InvokeStaticConstractor(Type type)
        {
            RuntimeHelpers.runclassConstructor(type.TypeHandle);
        }
    }

我使用 var server = TestServer.Create<WebAPITestStartup>()来实现此TestServer。 当我使用这个实体化的TestServer调用端点“ / auth / token”时,我能够获得Bearer令牌。 然后,我尝试在这样的其他请求中使用此令牌:

var msg = new HttpRequestMessage(HttpMethod.Get,"auth/users/8bb677a6-39e7-4343-9087-2bc4e004d4df");
msg.Content = content;
msg.Headers.Add("Authorization","Bearer "+_bearerToken);
response=server.HttpClient.SendAsync(msg).Result;

然后,响应始终是未授权的(401)。我试图在库中进行调试,以检查它们如何处理此令牌,但未发现任何结果。

当我删除[Authorize]属性或使用[AllowAnonymous]时,此方法将被正确调用删除属性后,我还检查了Authorization标头值,并在其中填充了数据。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)