简体   繁体   中英

How to integrate JWT authentication with Web API?

I am having problem integrating JWT with my Web API.. I tried to follow this tutorial and example

It seems pretty straight forward, but I am having difficulties integrating it with my project. You should know that I have a bunch of .aspx (Web Form) files that makes my website. This website is consuming my Web API using javascript (Ajax). I have installed jose-jwt package so I can use it in my code.

Server Side

WebApiConfig.cs:

public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "defaultApiRoutes",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { id = RouteParameter.Optional },
                constraints: new { id = @"\d+" }   // Only matches if "id" is one or more digits.
            );

            config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));

        }
    }

Example of one of my actions inside 'Request' Controller:

[HttpPost]
        [ActionName("createRequest")]
        public IHttpActionResult createRequest(Request request)
        {
            if (userIsAuthorized) // I am guessing that for each action there will be this kinda condition to check the token of the user
            if (ModelState.IsValid) {
                using (SqlConnection connection = WebApiApplication.reqeustConnection("ConStrMRR")) {
                    using (SqlCommand command = new SqlCommand("createRequest", connection)) {
                        try {
                            command.CommandType = CommandType.StoredProcedure;
                            command.Parameters.Add(new SqlParameter("@status_id", request.StatusID));
                            command.Parameters.Add(new SqlParameter("@patient_firstname", request.PatientFirstName));
                            command.Parameters.Add(new SqlParameter("@patient_lastname", request.PatientLastName));
                            command.Parameters.Add(new SqlParameter("@patient_url", request.PatientURL));
                            command.Parameters.Add(new SqlParameter("@facility", request.Facility));
                            connection.Open();
                            int request_id = (int)command.ExecuteScalar();
                            return Ok(request_id);
                        } catch (Exception e) {
                            throw e;
                        } finally {
                            connection.Close();
                        }
                    }
                }
            }
            return Content(HttpStatusCode.BadRequest, "Request has not been created.");
        }

Client Side

Create-request.js

$.ajax({
            url: "http://" + window.myLocalVar + "/api/requests/createRequest",
            type: "POST",
            dataType: 'json',
            contentType: 'application/json',
            data: request,
            success: function (request_id, state) {
                    console.log(request_id);
            },
            error: function (err) {
                if (err) {
                    notyMessage(err.responseJSON, 'error');
                }
            }
        });      

I am guessing that the previous request will be updated to have the following after the 'success' function:

beforeSend: function(xhr)
              {
                xhr.setRequestHeader("Authorization", "Bearer " + localStorage.getItem('token'));
              },

My login page is like the following:

<body id="cover">

<div class="container">
    <div class="row">
        <div class="col-md-4 col-md-offset-4">
            <div class="login-panel panel panel-primary">
                <div class="panel-heading">
                    <h3 class="panel-title">Please Sign In</h3>
                </div>
                <div class="panel-body">
                    <div align="center" style="margin-bottom: 50px;"><img class="img-responsive" src="../img/logo.jpg"/></div>
                    <form role="form" runat="server">
                        <fieldset>
                            <div class="form-group">
                                <asp:TextBox ID="usernameTextBox" CssClass="form-control" runat="server" placeholder="Username"></asp:TextBox>
                            </div>
                            <div class="form-group">
                                <asp:TextBox ID="passwordTextBox" CssClass="form-control" runat="server" placeholder="Password" TextMode="Password"></asp:TextBox>
                            </div>
                            <div class="checkbox">
                                <label>
                                    <asp:CheckBox ID="rememberMeCheckBox" runat="server"/>Remember Me
                                </label>
                            </div>
                            <!-- Change this to a button or input when using this as a form -->
                            <asp:Button CssClass="btn btn-primary btn-block" Text="Login" ID="Login" runat="server"/>
                        </fieldset>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

I am having difficulties to integrate JWT authentication with my code. Could you please help with that.

Thanks!

So, you will have:

  1. One Web API server (the "API")
  2. One Web forms application (the "Client")

Web API Server

The API will be protected by JWT. Every client of the API should provide a JWT in the HTTP header (a Bearer token). This JWT will be given by the Identity Provider at the time of authentication.

The Web API needs some kind of middleware to get the JWT token from the request, validate it (verify audience, issuer, expiration and signature) and set a ClaimsPrincipal that will be valid for the request. That way you can use .Net standard authorization attributes and procedures, such as:

[Authorize] // requires the user to be authenticated
public IActionResult SomeProtectedAction()
{
}

If your Web API is for ASP.Net Core, you can use the Microsoft.AspNetCore.Authentication.JwtBearer to do that, configured like this:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    var options = new JwtBearerOptions
    {
        Audience = "[Your API ID]",
        Authority = $"[URL for your identity provider]/",
        // certificate public keys will be read automatically from
        // the identity provider if possible
        // If using symmetric keys, you will have to provide them
    };
    app.UseJwtBearerAuthentication(options);

}

Regular ASP.Net applications with OWIN can use the Microsoft.Owin.Security.ActiveDirectory package, with configuration code like this:

public void Configuration(IAppBuilder app)
{
    var issuer = $"[url to identity provider]/";
    var audience = "[your API id];

    app.UseActiveDirectoryFederationServicesBearerAuthentication(
        new ActiveDirectoryFederationServicesBearerAuthenticationOptions
        {
            TokenValidationParameters = new TokenValidationParameters
            {
                ValidAudience = audience,
                ValidIssuer = issuer
                // you will also have to configure the keys/certificates
            }
        });

Client

Your client application will be a webforms app. After the user signs in (usually by redirecting the user to the identity provider's login page), you will get an access token back. You can store the token in the client (local storage), and use it when making calls to the API as you showed:

beforeSend: function(xhr) {
    xhr.setRequestHeader("Authorization", "Bearer " + localStorage.getItem('token'));
},

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM