4
votes

I'm new to .Net Core (currently using .Net Core 2.2) Authorization and Authentication. I have to develop the authentication and authorization mechanics in my new project. Searching around the Web I have found several ways of doing it (using Identity, not using, using Cookies, using JWT, etc etc). I would like to someone to point me in some direction that would be well fit for my scenario. Here are the requirements:

  • I'm developing the application as an API. So I need to protect my endpoints.
  • The authentication will be done by a 3rd part system my client provides. Basically, upon receiveing user and password in my Login endpoint, I will have to request this service. The service will then tell me if the user is authenticate as well as its roles.
  • Being authenticated, I will then query my own database to get information about the user: Its timezone, language, etc. I would like to have this information in a session so every request from that user that gets to my server, I get the language, for instance, in order to return data in the correct language.
  • The application will be deployed in two different servers with load balance. An user that logged in one server should be valid in the other (the servers have to somehow share the cookie/token).

I'm unfamiliar with a lot of stuff here. I don't know if it is possible to have a cookie authentication shared between servers or should I go with JWT and persist it in the database maybe...? Also, how does Session work in .Net core? Can I somehow bind the session to a JWT or something like that?

Which would be the best / recomendded approach here?

Any help/tutorial is much appreciated.

Thanks!

1

1 Answers

4
votes

Just some of the concepts:

Identity is a library used to help set up and manage the user base like signup, validate the password, password resets etc. It manages the storage, security and many required validations. This portion seems to be managed by your client. So you wouldn't need this.

Cookies/session are generally used by web applications to track the current user info. While this is possible to use these with web APIs, it is really not recommended and not done.

JWT are meant for a stateless setup. Web APIs are mostly stateless (REST). This means that minimum usage or RAM and not using the RAM or database to track the state (to understand if the previous request is related to the current). JWT that takes your user data, signs with a secret string that you can provide and creates a signature. You can read more about JWT online on websites such as these https://jwt.io.

The first stage for you would be to connect to the client's system for authentication. Since you intend to connect to another API in the server side, you need to use .NET Core's AddHttpClient feature. First, Create a class something like this:

public class MyAuthClient
{
    private readonly HttpClient httpClient;

    public MyAuthClient(HttpClient httpClient)
    {
        this.httpClient = httpClient;
    }

    public Dictionary<string, string> AuthorizeUser(string username, string password)
    {
        // use the httpClient send login and get confirmation from client's system
        if (loginFailed) return null;
        else
        {
            var result = new Dictionary<string, string>();
            result["userData1"] = "value"; // get these values from the http request you have created above.
        }
    }

}

In your startup add this:

services.AddHttpClient<MyAuthClient>(client => {
    client.BaseAddress = new Uri("https://yourclientsystem.com");
});

Now, to set up the JWT auth, there are several ways you can find online. I had set up a library called NetCore.Jwt that could be quite useful in this context. If you are not comfortable using it, you can either pull its source code or use an alternative online. Once this is done, in your startup.cs file:

Use the following in the ConfigureServices function:

services.AddAuthentication(NetCoreJwtDefaults.SchemeName).AddNetCoreJwt(options => 
{
    options.Secret = "yourVerySecretKeyThatYouWillBeSharingBetweenBothServers";
   // you can configure other options here too
});

And the following in the Configure function:

app.UseAuthentication();

The above code configures the authentication for your application(s) with JWT. Making sure the Secret string is the same in both apps will help a lot to ensure that you are sharing the same login between both apps. It is not safe to have such strings hardcoded within the code. Check this link to understand how to store something in a secure format. Now, you will need a controller and action where you take the user's login and provide a valid JWT. This would be setup something like this:

public class AuthController : Controller
{
    private readonly MyAuthClient authClient;

    public AuthController(MyAuthClient authClient)
    {
        this.authClient = authClient;
    }

    public ActionResult<string> Login(string userName, string password)
    {
        var result = authClient.AuthorizeUser(userName, password);
        if (result == null) return BadRequest("invalid login");
        var claims = new List<Claim>();
        foreach (var r in result)
        {
            claims.Add(new Claim(r.Key, r.Value));
        }
        claims.Add(new Claim(ClaimTypes.Name, "usernameHere")); // this can be later accessed using User.Identity.Name
        claims.Add(new Claim(ClaimTypes.NameIdentifier, "userId"));
        string token = HttpContext.GenerateBearerToken(claims);
        return token;
    }

}

Finally, to make your API can only be authorized and used, make sure you include [Authorize] on top of every controller.