如何在使用JWT令牌保护asp.net核心web api时从Azure AD获取用户

如何在使用JWT令牌保护asp.net核心web api时从Azure AD获取用户,jwt,azure-active-directory,asp.net-core-webapi,Jwt,Azure Active Directory,Asp.net Core Webapi,我在React JS中有一个.net核心web api和SPA客户端。我想允许用户使用在Azure AD中注册的电子邮件从客户端登录,并使用JWT令牌保护我的web api。我试图用简单的硬编码用户名和密码生成令牌,但我不知道如何从Azure AD获取用户并生成JWT令牌 这是我的JWTController: [Route("api/[controller]")] public class JwtController : Controller { private readonly Jwt

我在React JS中有一个.net核心web api和SPA客户端。我想允许用户使用在Azure AD中注册的电子邮件从客户端登录,并使用JWT令牌保护我的web api。我试图用简单的硬编码用户名和密码生成令牌,但我不知道如何从Azure AD获取用户并生成JWT令牌

这是我的JWTController:

[Route("api/[controller]")]
public class JwtController : Controller
{
    private readonly JwtIssuerOptions _jwtOptions;
    private readonly ILogger _logger;
    private readonly JsonSerializerSettings _serializerSettings;

    public JwtController(IOptions<JwtIssuerOptions> jwtOptions, ILoggerFactory loggerFactory)
    {
        _jwtOptions = jwtOptions.Value;
        ThrowIfInvalidOptions(_jwtOptions);

        _logger = loggerFactory.CreateLogger<JwtController>();

        _serializerSettings = new JsonSerializerSettings
        {
            Formatting = Formatting.Indented
        };
    }

    [HttpPost]
    [AllowAnonymous]
    public async Task<IActionResult> Get([FromForm] string Username, string Password)
    {
        var applicationUser = new ApplicationUser();
        applicationUser.UserName = Username;
        applicationUser.Password = Password;
        var identity = await GetClaimsIdentity(applicationUser);
        if (identity == null)
        {
            _logger.LogInformation($"Invalid username({applicationUser.UserName}) or password ({applicationUser.Password})");
            return BadRequest("Invalid credentials");
        }

        var claims = new[]
        {
            new Claim(JwtRegisteredClaimNames.Sub, applicationUser.UserName),
            new Claim(JwtRegisteredClaimNames.Jti, await _jwtOptions.JtiGenerator()),
            new Claim(JwtRegisteredClaimNames.Iat,
                ToUnixExpochDate(_jwtOptions.IssuedAt).ToString(),
                ClaimValueTypes.Integer64),
            identity.FindFirst("Disney")
        };

        //Create the JWT security token and encode it.
        var jwt = new JwtSecurityToken(
            issuer: _jwtOptions.Issuer,
            audience: _jwtOptions.Audience,
            claims:claims,
            notBefore:_jwtOptions.NotBefore,
            expires:_jwtOptions.Expiration,
            signingCredentials:_jwtOptions.SigningCredentials);

        var encodedJwt = new JwtSecurityTokenHandler().WriteToken(jwt);

        //Serialize and return the response.
        var response = new
        {
            access_token = encodedJwt,
            expires_in = (int)_jwtOptions.ValidFor.TotalSeconds
        };

        var json = JsonConvert.SerializeObject(response, _serializerSettings);
        return new OkObjectResult(json);
    }

    private static void ThrowIfInvalidOptions(JwtIssuerOptions options)
    {
        if (options == null) throw new ArgumentNullException(nameof(options));

        if (options.ValidFor <= TimeSpan.Zero)
        {
            throw new ArgumentException("Must be a non-zero TimeSpan.", nameof(JwtIssuerOptions.ValidFor));
        }

        if (options.SigningCredentials == null)
        {
            throw new ArgumentNullException(nameof(JwtIssuerOptions.SigningCredentials));
        }

        if (options.JtiGenerator == null)
        {
            throw new ArgumentNullException(nameof(JwtIssuerOptions.JtiGenerator));
        }
    }

    private static long ToUnixExpochDate(DateTime date)
        => (long)Math.Round((date.ToUniversalTime() -
            new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero))
            .TotalSeconds);

    private Task<ClaimsIdentity> GetClaimsIdentity(ApplicationUser user)
    {
        if (user.UserName == "mickey" && user.Password == "mouse")
        {
            return Task.FromResult(new ClaimsIdentity(
                new GenericIdentity(user.UserName, "Token"),
                new[]
                {
                    new Claim("Disney", "mickey")
                }));
        }

        if (user.UserName == "notmickey" && user.Password == "mouse")
        {
            return Task.FromResult(new ClaimsIdentity(
                new GenericIdentity(user.UserName, "Token"),
                new Claim[] { }));
        }

        return Task.FromResult<ClaimsIdentity>(null);
    }
}
[路由(“api/[控制器]”)]
公共类JwtController:控制器
{
私有只读jwtissueoptions\u jwtOptions;
专用只读ILogger\u记录器;
私有只读JsonSerializerSettings _serializerSettings;
公共JwtController(IOptions jwtOptions,iLogger工厂loggerFactory)
{
_jwtOptions=jwtOptions.Value;
通过有效选项(_jwtOptions);
_logger=loggerFactory.CreateLogger();
_serializerSettings=新JsonSerializerSettings
{
格式化=格式化。缩进
};
}
[HttpPost]
[异名]
公共异步任务获取([FromForm]字符串用户名,字符串密码)
{
var applicationUser=new applicationUser();
applicationUser.UserName=用户名;
applicationUser.Password=密码;
var identity=wait GetClaimsIdentity(applicationUser);
if(identity==null)
{
_logger.LogInformation($“无效用户名({applicationUser.username})或密码({applicationUser.password})”;
返回请求(“无效凭证”);
}
风险值索赔=新[]
{
新声明(JwtRegisteredClaimNames.Sub,applicationUser.UserName),
新索赔(JwtRegisteredClaimNames.Jti,wait_jwtOptions.JtiGenerator()),
新索赔(JwtRegisteredClaimNames.Iat,
ToUnixExpochDate(_jwtOptions.IssuedAt).ToString(),
ClaimValueTypes.Integer64),
identity.FindFirst(“迪士尼”)
};
//创建JWT安全令牌并对其进行编码。
var jwt=新的JwtSecurityToken(
发卡机构:jwtOptions.发卡机构,
观众:jwtOptions.publications,
索赔:索赔,
notBefore:_jwtOptions.notBefore,
expires:\u jwtOptions.expirement,
签名凭据:_jwtOptions.signingCredentials);
var encodedJwt=新的JwtSecurityTokenHandler().WriteToken(jwt);
//序列化并返回响应。
var响应=新
{
访问令牌=encodedJwt,
expires_in=(int)_jwtOptions.ValidFor.TotalSeconds
};
var json=JsonConvert.SerializeObject(响应,_serializerSettings);
返回新的OkObjectResult(json);
}
私有静态void ThrowIfInvalidOptions(jwtissueoptions选项)
{
如果(options==null)抛出新的ArgumentNullException(nameof(options));
if(options.ValidFor(long)Math.Round((date.ToUniversalTime)()-
新的DateTimeOffset(1970,1,1,0,0,0,TimeSpan.0))
.totals);
私有任务GetClaimsEntity(应用程序用户)
{
如果(user.UserName==“mickey”&&user.Password==“鼠标”)
{
返回Task.FromResult(新索赔实体(
新GenericEntity(user.UserName,“令牌”),
新[]
{
新索赔(“迪士尼”、“米奇”)
}));
}
if(user.UserName==“notmickey”&&user.Password==“鼠标”)
{
返回Task.FromResult(新索赔实体(
新GenericEntity(user.UserName,“令牌”),
新的索赔[]{}];
}
返回Task.FromResult(空);
}
}

有人知道如何实现这一点吗?

我认为你的想法有点倒退

您的React客户端应该重定向到Azure AD登录页面,然后从Azure AD获取JWT以调用您的API。然后,您的API只需验证传入令牌并为请求构建用户标识。ASP.NET Core中有现成的组件

将Adal.js与React一起使用的一个示例:


Azure AD v2在ASP.NET MVC核心API中的使用示例:

我认为您的使用有点落后

您的React客户端应该重定向到Azure AD登录页面,然后从Azure AD获取JWT以调用您的API。然后,您的API只需验证传入令牌并为请求构建用户标识。ASP.NET Core中有现成的组件

将Adal.js与React一起使用的一个示例:


ASP.NET MVC核心API中Azure AD v2的使用示例:

我不明白。如何通过客户端的简单重定向从AzureAD生成JWT令牌?请参阅此处的流程图了解其工作原理:。如果您的API和SPA前端实际上是Azure AD中的同一个应用程序,您可以按照其中提到的操作,只需发送ID令牌。否则,您可以使用Adal.js为其他API获取额外的访问令牌。还有一个示例应用程序使用Angular:有关隐式授权流的更多信息:。我要看看这个,谢谢您的帮助!我不明白。如何通过客户端的简单重定向从AzureAD生成JWT令牌?请参阅此处的流程图了解其工作原理:。如果您的API和SPA前端实际上是Azure AD中的同一个应用程序,您可以按照其中提到的操作,只发送ID令牌。否则,您可以使用Adal.js获取其他API的其他访问令牌。还有一个示例应用程序使用Angular:有关隐式授权流的更多信息:.我来看看,谢谢你的帮助!