SPA – Firebase和.Net WebApi 2身份validation

我有一个用AngularJs编写的单页面应用程序(框架在这一点上是无关紧要的)应用程序托管在IIS中,它由index.html和一堆客户端资产组成。

在后端我有WebApi 2,也作为单独的应用程序在IIS中托管。

对于客户端身份validation,我使用Firebase(简单登录),启用了几个社交网络,如Facebook,Twitter或Google。

到现在为止还挺好。 我喜欢用firebase启用twitter身份validation是多么容易。

在使用社交网络登录时,我从firebase返回,firebaseAuthToken和提供者accessstoken。

现在我想使用firebaseAuthToken或提供者访问令牌来validation我的WebApi。

问题是: 在给定条件下使用WebApi进行身份validation的最佳方法什么?

由于我在服务器上安装了复杂的业务逻辑,所以没有选项只使用firebase来存储我的数据并摆脱web api。

到目前为止,我有一个愚蠢的想法是将社交提供者访问令牌传递给服务器,针对提供者validation令牌,然后使用Owin -Katana发出安全令牌。

由于缺乏文档,复杂性以及与单页应用程序的错误集成,我没有使用katana构建的社交提供程序支持。 我发现SPA的视觉工作室模板太具体了。 但那是我:)

tl; dr – GitHub上的演示项目

以下步骤可能看起来很长,但实际上很容易。 我在一个小时左右的时间内创建了我的演示项目。


我同意你关于使用Owin和Katana的看法。 我以前经历过这个过程,并不是一个很棒的经历。 使用Firebase非常容易。

这一切都可以通过JWT完成!

当您通过Firebase和任何社交提供程序进行身份validation时,您将获得JSON Web令牌(JWT) – firebaseAuthToken

从仪表板中获取Firebase机密

JWT的工作方式是我们有一个秘密令牌和一个客户端令牌。 客户端令牌是我们在登录后收到的firebaseAuthToken。在Firebase仪表板中为我们生成了密钥令牌。

Firebase JWTs仪表板

将您的Firebase机密存储在Web.config的appSettings部分中

我们需要将此密钥存储在Web.config中,以便以后更容易访问。

  

创建一个Action Filter以从Authorization Header中检查JWT

我们可以通过在Authorization标头中传递客户端令牌来validation请求是否有效。 在服务器上,我们可以存储从Firebase仪表板获取的密钥。 当Web API检查请求时,我们可以使用JWT库( 可从NuGet获得 )解码JWT。 如果解码成功,那么我们可以检查令牌以确保它没有过期。

 public class DecodeJWT: ActionFilterAttribute { public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext) { string firebaseAuthToken = string.Empty; if (actionContext.Request.Headers.Authorization != null) { firebaseAuthToken = actionContext.Request.Headers.Authorization.Scheme; } else { throw new HttpException((int) HttpStatusCode.Unauthorized, "Unauthorized"); } string secretKey = WebConfigurationManager.AppSettings["FirebaseSecret"]; try { string jsonPayload = JWT.JsonWebToken.Decode(firebaseAuthToken, secretKey); DecodedToken decodedToken = JsonConvert.DeserializeObject < DecodedToken > (jsonPayload); // TODO: Check expiry of decoded token } catch (JWT.SignatureVerificationException jwtEx) { throw new HttpException((int) HttpStatusCode.Unauthorized, "Unauthorized"); } catch (Exception ex) { throw new HttpException((int) HttpStatusCode.Unauthorized, "Unauthorized"); } base.OnActionExecuting(actionContext); } } 

创建$ httpInterceptor将firebaseAuthToken添加到每个请求的标头中

在客户端,诀窍是每次都必须传递令牌。 为了使这更容易,我们需要使用Angular创建一个$httpInterceptor ,以检查sessionStorage上的sessionStorage

 .factory('authInterceptor', function ($rootScope, $q, $window) { return { request: function (config) { config.headers = config.headers || {}; if ($window.sessionStorage.firebaseAuthToken) { config.headers.Authorization = $window.sessionStorage.firebaseAuthToken; } return config; }, response: function (response) { if (response.status === 401) { // TODO: User is not authed } return response || $q.when(response); } }; }) 

成功登录后,将firebaseAuthToken设置为sessionStorage

每当用户登录时,我们都可以将值设置为sessionStorage

 $rootScope.$on('$firebaseSimpleLogin:login', function (e, user) { // add a cookie for the auth token if (user) { $window.sessionStorage.firebaseAuthToken = user.firebaseAuthToken; } cb(e, user); }); 

全局注册DecodeJWTfilter

WebApiConfig.cs Register方法的内部,我们可以设置DecodeJWTfilter以应用于我们所有的ApiControllers。

 config.Filters.Add(new DecodeJWT()); 

现在每当我们向ApiController发出请求时,它都会拒绝它,除非有一个有效的JWT。 因此,在用户登录后,如果它已经不存在,我们可以将它们的数据保存到ApiController。

 // globally uses DecodeJWT public class UsersController: ApiController { // POST api/users public void Post([FromBody] FbUser user) // See GitHub for this Model { // Save user if we do not already have it } }