skip to Main Content

I have a website where users log in on an external website and are redirected back with a token in the querystring. I then validate the token and create the authentication ticket. How would I check on subsequent requests that the user is now logged in? And how would I log a user out?

    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        var token = Request.Query["token"].FirstOrDefault();

        if (token != null)
        {
            var validator = new JwtSecurityTokenHandler();

            var region = "us-xxx-x";
            var userPoolId = "us-xxx-xxxxxxx";
            var appClientId = "xxxxxxxxxxxxxxxxxxxx";

            var cognitoIssuer = $"https://cognito-idp.{region}.amazonaws.com/{userPoolId}";
            var jwtKeySetUrl = $"{cognitoIssuer}/.well-known/jwks.json";

            var validationParameters = new TokenValidationParameters
            {
                IssuerSigningKeyResolver = (s, securityToken, identifier, parameters) =>
                {
                    var json = new WebClient().DownloadString(jwtKeySetUrl);
                    var keys = JsonConvert.DeserializeObject<JsonWebKeySet>(json).Keys;
                    return (IEnumerable<SecurityKey>)keys;
                },
                ValidIssuer = cognitoIssuer,
                ValidateIssuerSigningKey = true,
                ValidateIssuer = true,
                ValidateLifetime = true,
                ValidAudience = appClientId
            };

            // validate the token 
            var principal = validator.ValidateToken(token, validationParameters, out var validatedToken);
            if (principal.HasClaim(c => c.Type == ClaimTypes.NameIdentifier))
            {
                var claims = new[] { new Claim("token", token) };
                var identity = new ClaimsIdentity(claims, nameof(TokenAuthenticationHandler));
                var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), this.Scheme.Name);
                return Task.FromResult(AuthenticateResult.Success(ticket));
            }
            else
                return Task.FromResult(AuthenticateResult.Fail("Token validation failed"));
        }
        else
            return Task.FromResult(AuthenticateResult.Fail("No token"));
    }

2

Answers


  1. Full disclosure, I’m not very knowledgeable on the library you are using or on what exactly you are trying to do here, but I can tell you how these things work, generally speaking. Conceptually logging in and out on a web service works as follows:

    1. Client sends authentication information to the server (Username, password hash, 2FA info, etc.)

    2. The server checks the authentication information against the stored information about the user (e.g. compare password hash to the stored password hash)

    3. If authentication is sucessful, the server creates and stores a cookie (a long randomly generated string). The server stores the cookie along with information such as the user who the cookie belongs to, and when the cookie was created.

    4. The server sends the cookie to the client. The client is now "logged in".

    5. Now when the client wants to send some http request to the web service, they send the cookie along with the request. The server then looks up who the cookie belongs to and handles the http request appropriately.

    6. When the user wants to log out they send an http request to the server asking to log out, and pass the cookie along with the message. The server then invalidates the cookie, and further http requests are handled as if the user is logged out.

    Login or Signup to reply.
  2. I tried with the code:
    In controller:

         [Authorize(AuthenticationSchemes = "Cookies,Bearer")]
                    public IActionResult Index()
                    {
                        
                        return View();
                    }
        
            public IActionResult CreateToken()
                    {
                        var claims = new Claim[]
                        {
                            new Claim(ClaimTypes.Name, "Jeffcky"),
                        };
                        var token = GenerateToken(claims);
                        Response.Cookies.Append("x-access-token", token);
                        return RedirectToAction("Login");
                     }
        
        private string GenerateToken(Claim[] claims)
                    {
                        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("1234567890123456"));
            
                        var token = new JwtSecurityToken(
                          issuer: "http://localhost:5000",
                          audience: "http://localhost:5001",
                          claims: claims,
                          notBefore: DateTime.Now,
                          expires: DateTime.Now.AddMinutes(5),
                          signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)
                        );
            
                        return new JwtSecurityTokenHandler().WriteToken(token);
                    }
    
        [HttpPost]        
    public async Task<IActionResult> Login(User user)
                {
        
                    var token = Request.Cookies["x-access-token"];
                    var jsonToken = new JwtSecurityTokenHandler().ReadToken(token) as JwtSecurityToken;
                    var username = jsonToken.Claims.FirstOrDefault(m => m.Type == ClaimTypes.Name).Value;
                    if (username!=user.Name)
                    {
                        var claims = new Claim[]
                        {
                        new Claim(ClaimTypes.Name, "Jeffcky"),
                         };
                        var claimsIdentity = new ClaimsIdentity(claims, "Login");
                        await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity));
                    }
                    return RedirectToAction("Index");
                }
    

    In startup:

    services.AddAuthentication(options =>
                {
                    options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
                })
                .AddCookie( m =>
                {
                    m.LoginPath = new Microsoft.AspNetCore.Http.PathString("/Home/Login");
                    m.AccessDeniedPath = new Microsoft.AspNetCore.Http.PathString("....");
                    m.SlidingExpiration = true;
                    m.ExpireTimeSpan = TimeSpan.FromMinutes(120);
                })
                .AddJwtBearer(options =>
                 {
                     options.TokenValidationParameters = new TokenValidationParameters
                     {
                         ValidateIssuerSigningKey = true,
                         IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("1234567890123456")),
                         ValidateIssuer = true,
                         ValidIssuer = "http://localhost:5000",
                         ValidateAudience = true,
                         ValidAudience = "http://localhost:5001",
                         ValidateLifetime = true,
                         ClockSkew = TimeSpan.FromMinutes(5)
                     };
                     options.Events = new JwtBearerEvents
                     {
                         OnMessageReceived = context =>
                         {
                             var accessToken = context.Request.Cookies["x-access-token"];
    
                             if (!string.IsNullOrEmpty(accessToken))
                             {
                                 context.Token = accessToken;
                             }
    
                             return Task.CompletedTask;
                         }
                     };
                 });
    

    The Result:
    enter image description here

    enter image description here

    you could modify the codes in login controller to pool data from database and varify the userinformation to meet your requirement.

    And the Attribute[Authorize(AuthenticationSchemes = "Cookies,Bearer")] allows you Authentication with cookie or jwt,it may help in some situation

    and if you want to logout,you could delete the cookie which strores the token or ticket

    UpDate:

    Accroding to your description,I think you could use jwt Authentication and set in your startup as follow:

    options.Events = new JwtBearerEvents
                     {
                         OnMessageReceived = context =>
                         {
    
                             var accessToken = context.Request.Query["tookn"];
    
                             if (!string.IsNullOrEmpty(accessToken))
                             {
                                 context.Token = accessToken;
                             }
    
                             return Task.CompletedTask;
                         }
                     };
    

    Is it the result you excepted?
    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search