如何在Azure移动服务中使用我的自定义OWIN身份验证

时间:2015-01-12 14:30:25

标签: owin azure-mobile-services

我在AWS中托管了一个有效的Web API 2移动服务,我想转移到AMS。它适用于Postman和移动设备上。

我关注了几个博客/帖子,花了几个小时重写和重新排序WebApiConfig.Register。然后我创建了一个新的AMS项目并复制了我的所有控制器等,我得到了相同的结果。我回顾了很多类似的问题,但我的脑子已经过了20多行代码。

它通过Postman在本地工作,但在我发布之后我得到了

HTTP 401 - {"消息":"此请求已拒绝授权。"}

以下是AWS正在运行的startup.cs - 我没有调用WebApiConfig.Register

namespace Savviety.Data.Service

{     公共部分类启动     {         public void Configuration(IAppBuilder app)         {

        var config = new HttpConfiguration();

        ConfigureOAuth(app);

        // remove in production
        var cors = new EnableCorsAttribute("*", "*", "*");
        config.EnableCors(cors);

        app.UseWebApi(config);

        config.SuppressDefaultHostAuthentication();
        config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

        // Web API routes
        config.MapHttpAttributeRoutes();

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


        var path = AppDomain.CurrentDomain.BaseDirectory + @"\log4net.config";
        var fileInfo = new FileInfo(path);


        XmlConfigurator.ConfigureAndWatch(fileInfo);
        if (fileInfo.Exists)
        {
            log4net.Config.XmlConfigurator.ConfigureAndWatch(fileInfo);
        }
        else
        {
            throw new FileNotFoundException("Could not find log4net.config");
        }

    }

    public void ConfigureOAuth(IAppBuilder app)
    {
        var oAuthServerOptions = new OAuthAuthorizationServerOptions()
        {
            AllowInsecureHttp = true,
            TokenEndpointPath = new PathString("/token"),
            AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
            Provider = new SimpleAuthorizationServerProvider()
        };

        // Token Generation
        app.UseOAuthAuthorizationServer(oAuthServerOptions);
        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);

    }
}

在AMS版本中,我从Global.asax中的Application.Onstart调用WebApiConfig.Register方法

 public static void Register( )
    {
        .
        var options = new ConfigOptions();

        var config = ServiceConfig.Initialize(new ConfigBuilder(options));
        config.SuppressDefaultHostAuthentication();
        config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));

        // Make sure this is after ServiceConfig.Initialize
        // Otherwise ServiceConfig.Initialize will overwrite your changes
        Microsoft.WindowsAzure.Mobile.Service.Config.StartupOwinAppBuilder.Initialize(appBuilder =>
        {
            ConfigureOAuth(appBuilder);

            appBuilder.UseWebApi(config);

            var path = AppDomain.CurrentDomain.BaseDirectory + @"\log4net.config";
            var fileInfo = new FileInfo(path);

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


        // Web API routes
        // config.MapHttpAttributeRoutes();

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

我还用[AuthorizeLevel(AuthorizationLevel.User)]替换了[Authorize]并删除了startup.cs类。

在Postman中,它在本地工作,但在我发布后却没有。它会生成令牌,但身份验证失败。

TIA

加里

2 个答案:

答案 0 :(得分:1)

AuthorizeLevel属性查找由移动服务发布的令牌。由于您实际上并未在上面发出此类令牌,​​因此会失败。

事情可能在本地工作,因为默认配置会接受所有本地呼叫。如上所述here,您将需要进入WebApiConfig.cs的Register()方法并添加以下内容:

config.SetIsHosted(true);

这会导致调用开始在本地失败。

要解决核心问题,可以将自己的OWIN提供商连接到移动服务管道。您将需要创建一个LoginProvider的子类,它基本上在其ConfigureMiddleware()内部执行您的ConfigureAuth()调用。请参阅this blog post中设置LinkedIn中间件的示例。

答案 1 :(得分:0)

好的,主要问题是Azure不支持自定义OWIN身份验证,或者我找不到如何在任何地方实现它。我必须使用其他系统提供的用户和密码列表,因此必须自定义。

解决方案是自定义LoginController和LoginProvider相关代码如下。

MyLoginProvider是LoginProvider的子类,并调用CreateLoginResult基本方法。

我必须将我的javascript auth拦截器修改为config.headers["X-ZUMO-AUTH"] = $localStorage.token;而不是OAuth bearer token header。

我无法在请求中获取声明标识中的电子邮件或显示名称,但我使用了一种解决方法。当我搞清楚时,我会在这里发布,但现在它并没有阻止我。

public HttpResponseMessage Post(LoginRequest loginRequest)
    {

        var mongoDbManager = MongoDbManager.GetInstance();
        var userCollection = mongoDbManager.GetCollection<UserDocument>(CollectionNames.User);
        var q0 = Query<UserDocument>.EQ(i => i.ClientId, loginRequest.ClientId);
        var q1 = Query<UserDocument>.EQ(i => i.UserEmailAddress, loginRequest.UserName);
        var q2 = Query<UserDocument>.EQ(i => i.UserPassword, loginRequest.Password);
        var query = Query.And(q0, q1, q2);

        var result = userCollection.FindOne(query);

        if (result == null)
        {
            return this.Request.CreateResponse(HttpStatusCode.Unauthorized, "Invalid username or password");
        }
        else
        {
            var claimsIdentity = new ClaimsIdentity();
            claimsIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, result.UserId));
            claimsIdentity.AddClaim(new Claim(ClaimTypes.Email, result.UserEmailAddress));
            claimsIdentity.AddClaim(new Claim("DisplayName", result.DisplayName));
            var loginResult = new SavvietyLoginProvider(handler).CreateLoginResult(claimsIdentity, Services.Settings.MasterKey);
            return this.Request.CreateResponse(HttpStatusCode.OK, loginResult);
        }
    }
}