.net 核心 2.0 JWT 令牌

.net core 2.0 JWT token

我有一个使用 .net core 2.0 构建的网络 Api 和一个使用 xamarin 构建的移动应用程序。要登录移动应用程序,请通过传递(用户名和密码)调用网络 api。如果凭据有效,web Api 提供回 JWT 令牌。移动应用程序具有一项功能,即使您关闭应用程序也能使用户保持登录状态,例如(facebook、Instagram 等...)。

问题是这些:

  1. 如何在用户登录之前保持 JWT 令牌有效 应用无需再次询问 him/her 即可提供 him/her 的登录凭据 另一个有效的 JWT 令牌?
  2. 如何在用户决定注销后使 JWT 令牌失效 从应用程序?

How to keep the JWT token valid until the user is logged-In in the app without ask him/her again the login credentials to give him/her another valid JWT token?

您可以设置令牌到期日期并对其进行跟踪。

How to make the JWT token invalid after the user decide to logout from the app?

  • 如果您保持较短的到期时间并不断刷新令牌到期直到用户注销。
  • 您可以保存某种无效令牌的黑名单,以便您可以对其进行验证。

更新:

JWT 由 Header、Payload 和 Signature 组成。您可以阅读所有相关内容 here 在有效载荷中,您可以设置一个名为:“exp”的声明。

The docs: The "exp" (expiration time) claim identifies the expiration time on or after which the JWT MUST NOT be accepted for processing. The processing of the "exp" claim requires that the current date/time MUST be before the expiration date/time listed in the "exp" claim.

此外,在研究澄清我的答案时,我发现了这个 SO 答案:JSON Web Token expiration

 // This code tested with dotnet core 2.1 ( WebApi + Jwt )  with sample structure 

//给你的项目添加一个class Auth

public static class Auth
{
    private static string salt = "jnyanendra_sethi"; // u can chose any key satisfying the length 
    private static int timeoutInMinute = 1;
    private static string _issuer = "http://localhost:5000";
    private static string _audience = "http://localhost:5000";

    //Generate Token
    public static string GenerateToken(Customer customer, List<SupplierInfo> lstSpplierInfo)
    {
        var securitykey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(salt));
        var credential = new SigningCredentials(securitykey, SecurityAlgorithms.HmacSha256);

        // var suppliers = any json string e.g. [{"SupplierId":1001,"SupplierName":"RateHawk"},{"SupplierId":1002,"SupplierName":"Hotelbeds"}]
        var suppliers = JsonConvert.SerializeObject(lstSpplierInfo);//"ur json object to store in claim";
        var claims = new List<Claim> {
           new Claim("CustomerName", customer.CustomerName),
           new Claim("Suppliers",suppliers )
       };

        var mytoken = new JwtSecurityToken(issuer: _issuer, audience: _audience,
            claims: claims, notBefore: DateTime.Now, expires: DateTime.Now.AddMinutes(timeoutInMinute), signingCredentials: credential);
        var tokenValue = new JwtSecurityTokenHandler().WriteToken(mytoken);
        return tokenValue;
    }

    //Validate token

    public static void ValidateJwtToken(this IServiceCollection services)
    {
        var securitykey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(salt));
        var credential = new SigningCredentials(securitykey, SecurityAlgorithms.HmacSha256);

        var tokenParam = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            ValidIssuer = _issuer,
            ValidAudience = _audience,
            ValidateIssuer = true,
            ValidateAudience = true,
            RequireSignedTokens = true,
            IssuerSigningKey = credential.Key,
            ClockSkew = TimeSpan.FromMinutes(timeoutInMinute)
        };

        services.AddAuthentication(
            options =>
            {
                options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(
            options =>
            {
                options.TokenValidationParameters = tokenParam;
            });

    }
}

[Route("api/[controller]")]
[ApiController]
public class HotelController : ControllerBase
{

    [HttpGet("Search")]
    public SearchReponse Search()// u can take search parameters for input
    {
        // based on apikey or username, call db for first time
        // get customername / supplierinfo from db
        Customer customer = new Customer() { CustomerId = "CUS001", CustomerName = "TestCust" };// dummy
        if (customer == null)
        {
            this.HttpContext.Response.StatusCode = 401;
            return new SearchReponse()
            {
                ErrorInfo = new ErrorInfo()
                {
                    Code = "0",
                    Description = "No Customer Found"
                }
            };
        }

        string token = Auth.GenerateToken(customer, GetDummyDataToStoreInClaim());

        SearchReponse reponse = new SearchReponse()
        {
            GeneralInfo = new GeneralInfo()
            {
                Token = token,
                Duration = 0
            },
            Hotels = "Hotels Data",
        };
        return reponse;
    }

    [Authorize]
    [HttpGet("Get/{id}")]
    public ActionResult<string> Get(int id)
    {//// Getting the data stored in claim that required for further process
        var CustomerName = HttpContext.User.Identities.FirstOrDefault().Claims.FirstOrDefault(x => x.Type == "CustomerName").Value;
        var strSuppliers = HttpContext.User.Identities.FirstOrDefault().Claims.FirstOrDefault(x => x.Type == "Suppliers").Value;
        return CustomerName;
    }
}

我用过的机型:

 public class SearchReponse
{
    public GeneralInfo GeneralInfo { get; set; }
    public ErrorInfo ErrorInfo { get; set; }
    public string Hotels { get; set; }
}
public class GeneralInfo
{
    public string Token { get; set; }
    public long Duration { get; set; }
}
public class ErrorInfo
{
    public string Code { get; set; }
    public string Description { get; set; }
}

在Startup.cs

public void ConfigureServices(IServiceCollection services)
    {

        services.ValidateJwtToken();
        services.AddAuthorization(Options => {
            Options.DefaultPolicy = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme).RequireAuthenticatedUser().Build();
        });
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
    }

--