用ASOS实现两个因素

时间:2017-02-09 17:05:42

标签: openid-connect two-factor-authentication aspnet-contrib

我可能会说这一切都错了,但我一直在关注本文中的示例设置:Creating your own OpenID Connect server with ASOS,但是,它没有解释如何实现两个因素,因为这不是这个的主要目的文章。

本文中唯一提到的两个派系是在令牌端点,其中有一个双因素身份验证检查,如果启用了两个因子,它会拒绝令牌请求。所以我在我的客户端应用程序中添加了一个检查,检查特定的拒绝条件,然后重定向到要求两个因子代码的页面。该页面首先调用授权端点,该端点将代码发送到存档的用户电话。然后,一旦用户输入了代码,它就会再次使用该代码调用授权端点,并且处理授权端点的方法会验证代码并在成功时返回SignInResult。但是,我在返回SignInResult的SignIn(原则,属性,架构)方法中遇到500错误。

首先,我想知道我是否正确行事,其次,如果我做得正确,我做错了什么?请在下面找到我的相关代码:

AuthorizationProvider:

public override async Task HandleTokenRequest(HandleTokenRequestContext context) {
      var _dbContext = context.HttpContext.RequestServices.GetRequiredService<DbContext>();

      if(context.Request.IsPasswordGrantType()) {
        var u = await _dbContext.Users.Include(m => m.Organization).SingleOrDefaultAsync(x => x.Email.ToLowerInvariant() == context.Request.Username.ToLowerInvariant());

        if(u == null || !PasswordHelper.VerifyPassword(context.Request.Password, u.Password)) {
          context.Reject(
            error: OpenIdConnectConstants.Errors.AccessDenied,
            description: "The email or password is incorrect");
          return;
        } else if(u.Organization == null) {
          context.Reject(
            error: OpenIdConnectConstants.Errors.InvalidGrant,
            description: "Your user account is not associated with an organization.");
          return;
        }

        // // Reject the token request if two-factor authentication has been enabled by the user.
        if(u.TwoFactorEnabled) {
          context.Reject(
              error: OpenIdConnectConstants.Errors.InvalidGrant,
              description: "Two-factor authentication is required for this account.");
          return;
        }

        var identity = new ClaimsIdentity(context.Options.AuthenticationScheme);

        List<Claim> claims = new List<Claim>();
        claims.Add(new Claim(ClaimTypes.NameIdentifier, u.Id.ToString()));
        claims.Add(new Claim(ClaimTypes.Name, context.Request.Username));
        claims.Add(new Claim(ClaimTypes.Role, u.RoleString));
        claims.Add(new Claim("user_id", u.Id.ToString()));
        claims.Add(new Claim("org_id", u.Organization.Id.ToString()));

        foreach(var claim in claims) {
          claim.SetDestinations(new List<string> { OpenIdConnectConstants.Destinations.AccessToken, OpenIdConnectConstants.Destinations.IdentityToken });
        }

        identity.AddClaims(claims);

        var ticket = new AuthenticationTicket(
            new ClaimsPrincipal(identity),
            new AuthenticationProperties(),
            context.Options.AuthenticationScheme);
        // Set the list of scopes granted to the client application.
        ticket.SetScopes(
            /* openid: */ OpenIdConnectConstants.Scopes.OpenId,
            /* email: */ OpenIdConnectConstants.Scopes.Email,
            /* profile: */ OpenIdConnectConstants.Scopes.Profile,
            /* offline_access: */ OpenIdConnectConstants.Scopes.OfflineAccess);
        context.Validate(ticket);
      }
    }

授权方法:

[HttpPost]
[Route("authorize")]
public async Task<IActionResult> Authorize() {
  var request = HttpContext.GetOpenIdConnectRequest();
  if(request.Code == null) {
    var u = await _dbContext.Users.SingleOrDefaultAsync(x => x.Email.ToLowerInvariant() == request.Username.ToLowerInvariant());

    if(u == null || !PasswordHelper.VerifyPassword(request.Password, u.Password)) {
      return Forbid(OpenIdConnectServerDefaults.AuthenticationScheme);
    }

    var response = await _twoFactorProvider.SendCode(CodeMethods.sms, u.AuthyId);

    return Ok(new { Id = u.AuthyId, Response = response });
  } else {
    var response = await _twoFactorProvider.VerifyCode(request.Code, int.Parse(request.Username));

    if(response.Token != "is valid") {
      return Forbid(OpenIdConnectServerDefaults.AuthenticationScheme);
    }

    var u = await _dbContext.Users.Include(m => m.Organization).SingleOrDefaultAsync(x => x.AuthyId == int.Parse(request.Username));

    var identity = new ClaimsIdentity(OpenIdConnectServerDefaults.AuthenticationScheme);

    List<Claim> claims = new List<Claim>();
    claims.Add(new Claim(ClaimTypes.NameIdentifier, u.Id.ToString()));
    claims.Add(new Claim(ClaimTypes.Name, u.Email));
    claims.Add(new Claim(ClaimTypes.Role, u.RoleString));
    claims.Add(new Claim("user_id", u.Id.ToString()));
    claims.Add(new Claim("org_id", u.Organization.Id.ToString()));

    foreach(var claim in claims) {
      claim.SetDestinations(new List<string> { OpenIdConnectConstants.Destinations.AccessToken, OpenIdConnectConstants.Destinations.IdentityToken });
    }

    identity.AddClaims(claims);

    var ticket = new AuthenticationTicket(
        new ClaimsPrincipal(identity),
        new AuthenticationProperties(),
        OpenIdConnectServerDefaults.AuthenticationScheme);
    // Set the list of scopes granted to the client application.
    ticket.SetScopes(
        /* openid: */ OpenIdConnectConstants.Scopes.OpenId,
        /* email: */ OpenIdConnectConstants.Scopes.Email,
        /* profile: */ OpenIdConnectConstants.Scopes.Profile,
        /* offline_access: */ OpenIdConnectConstants.Scopes.OfflineAccess);

    return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
  }
}

客户端方法:

login(email, password) {
  var deferred = q.defer();

  var payload = {
    'grant_type': 'password',
    'username': email,
    'password': password,
    'scope': 'openid offline_access'
  };

  var url = this.authContextConfiguration.baseUrl + 'connect/token';

  $.ajax({
    url: url,
    type: 'POST',
    contentType: 'application/x-www-form-urlencoded',
    data: payload,
    success: function (data) {
      // store the access token / everything else //
      deferred.resolve();
    },
    error: function (req) {
      var error = {
        message: req.responseJSON.error_description || 'There was an error when signing in.'
      };
      deferred.reject(error);
    }
  });
  return deferred.promise;
}

twoFactorLogin(email, password) {
  var deferred = q.defer();

  var payload = {
    'username': email,
    'password': password
  }

  var url = this.authContextConfiguration.baseUrl + 'connect/authorize';

  $.ajax({
    url: url,
    type: 'POST',
    contentType: 'application/x-www-form-urlencoded',
    data: payload,
    success: function (data) {
      deferred.resolve(data);
    },
    error: function (req) {
      var error = {
        message: req.responseJSON.error_description || 'There was an error generating your two factor code.'
      };
      deferred.reject(error);
    }
  });

  return deferred.promise;
}

verifyTwoFactorCode(id, code, remember) {
  var deferred = q.defer();

  var payload = {
    'username': id,
    'code': code,
    'rememberMe': remember
  }

  var url = this.authContextConfiguration.baseUrl + 'connect/authorize';

  $.ajax({
    url: url,
    type: 'POST',
    contentType: 'application/x-www-form-urlencoded',
    data: payload,
    success: function (data) {
      deferred.resolve(data);
    },
    error: function (req) {
      var error = {
        message: req.responseJSON.error_description || 'There was an error verifying your two factor code.'
      };
      deferred.reject(error);
    }
  });

  return deferred.promise;
}

0 个答案:

没有答案