从ASP.net Web Api设置HTTPOnly cookie

时间:2020-02-14 07:54:15

标签: asp.net-web-api asp.net-mvc-5 angular8 access-token jwt-auth

我正在尝试在Web API中实现jwt令牌认证。我有一个角度为8的前端应用程序。我想将令牌保存在cookie中。如何实现?如果我在登录后将令牌保存在cookie中,那么从角度进行后续调用的语法将是什么。

TokenValidationHandler

internal class TokenValidationHandler : DelegatingHandler
{
private static bool TryRetrieveToken(HttpRequestMessage request, out string token)
{
    token = null;
    IEnumerable<string> authzHeaders;
    if (!request.Headers.TryGetValues("Authorization", out authzHeaders) || authzHeaders.Count() > 1)
    {
        return false;
    }
    var bearerToken = authzHeaders.ElementAt(0);
    token = bearerToken.StartsWith("Bearer ") ? bearerToken.Substring(7) : bearerToken;
    return true;
}

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
    HttpStatusCode statusCode;
    string token;
                //determine whether a jwt exists or not
    if (!TryRetrieveToken(request, out token))
    {
        statusCode = HttpStatusCode.Unauthorized;
        //allow requests with no token - whether a action method needs an authentication can be set with the claimsauthorization attribute
        return base.SendAsync(request, cancellationToken);
    }

    try
    {
        const string sec = "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429090fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1";
        var now = DateTime.UtcNow;
        var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(sec));                


        SecurityToken securityToken;
        JwtSecurityTokenHandler handler = new JwtSecurityTokenHandler();
        TokenValidationParameters validationParameters = new TokenValidationParameters()
        {
            ValidAudience = "http://localhost:50191",
            ValidIssuer = "http://localhost:50191",
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            LifetimeValidator = this.LifetimeValidator,                    
            IssuerSigningKey = securityKey                
        };
        //extract and assign the user of the jwt
        Thread.CurrentPrincipal = handler.ValidateToken(token, validationParameters, out securityToken);
        HttpContext.Current.User = handler.ValidateToken(token, validationParameters, out securityToken);

        return base.SendAsync(request, cancellationToken);
    }
    catch (SecurityTokenValidationException e)
    {
        statusCode = HttpStatusCode.Unauthorized;
    }
    catch (Exception ex)
    {
        statusCode = HttpStatusCode.InternalServerError;
    }
    return Task<HttpResponseMessage>.Factory.StartNew(() => new HttpResponseMessage(statusCode){ });
}

public bool LifetimeValidator(DateTime? notBefore, DateTime? expires, SecurityToken securityToken, TokenValidationParameters validationParameters)
{
    if (expires != null)
    {
        if (DateTime.UtcNow < expires) return true;
    }
    return false;
}
}

LoginController(将生成令牌)

public class LoginController : ApiController
{
[HttpPost]
public IHttpActionResult Authenticate([FromBody] LoginRequest login)
{
    var loginResponse = new LoginResponse { };
    LoginRequest loginrequest = new LoginRequest { };
    loginrequest.Username = login.Username.ToLower();
    loginrequest.Password = login.Password;

    IHttpActionResult response;
    HttpResponseMessage responseMsg = new HttpResponseMessage();
    bool isUsernamePasswordValid = false;       

    if(login != null)
    isUsernamePasswordValid=loginrequest.Password=="pass" ? true:false;
    // if credentials are valid
    if (isUsernamePasswordValid)
    {
        string token = createToken(loginrequest.Username);
        //return the token
        return Ok<string>(token);
    }
    else
    {
        // if credentials are not valid send unauthorized status code in response
        loginResponse.responseMsg.StatusCode = HttpStatusCode.Unauthorized;
        response = ResponseMessage(loginResponse.responseMsg);
        return response;
    }
}

private string createToken(string username)
{
    //Set issued at date
    DateTime issuedAt = DateTime.UtcNow;
    //set the time when it expires
    DateTime expires = DateTime.UtcNow.AddSeconds(30);

    //http://stackoverflow.com/questions/18223868/how-to-encrypt-jwt-security-token
    var tokenHandler = new JwtSecurityTokenHandler();

    //create a identity and add claims to the user which we want to log in
    ClaimsIdentity claimsIdentity = new ClaimsIdentity(new[]
    {
        new Claim(ClaimTypes.Name, username)                
    });

    const string sec = "401b09eab3c013d4ca54922bb802bec8fd5318192b0a75f201d8b3727429090fb337591abd3e44453b954555b7a0812e1081c39b740293f765eae731f5a65ed1";
    var now = DateTime.UtcNow;
    var securityKey = new Microsoft.IdentityModel.Tokens.SymmetricSecurityKey(System.Text.Encoding.Default.GetBytes(sec));
    var signingCredentials = new Microsoft.IdentityModel.Tokens.SigningCredentials(securityKey,Microsoft.IdentityModel.Tokens.SecurityAlgorithms.HmacSha256Signature);


    //create the jwt
    var token =
        (JwtSecurityToken)
            tokenHandler.CreateJwtSecurityToken(issuer:"http://localhost:50191",audience:"http://localhost:50191",
                subject: claimsIdentity, notBefore: issuedAt, expires: expires, signingCredentials: signingCredentials);
    var tokenString = tokenHandler.WriteToken(token);

    return tokenString;
}
}

1 个答案:

答案 0 :(得分:0)

首先,JavaScript 无法访问 httponly cookie。

其次,请参考下面的代码将 cookie 与响应一起返回。

private HttpResponseMessage setTokenCookie(LoginResponse response)
        {
            var responseMessage = Request.CreateResponse(HttpStatusCode.OK, response);

            var cookie = new CookieHeaderValue("token", response.Token)
            {
                Expires = DateTimeOffset.Now.AddDays(7),
                HttpOnly = true
            };

            responseMessage.Headers.AddCookies(new CookieHeaderValue[] { cookie });

            return responseMessage;
        }

您可以在控制器操作方法中使用上面提到的函数,如下所示返回cookie。

var responseWithCookie = setTokenCookie(response);

return ResponseMessage(responseWithCookie);

我假设 LoginResponse 类具有 Token 属性。