.NET Framework MVC and Web Api Auth JWT
Asked Answered
E

2

12

I have a project in MVC using .NET Framework v4.7 with some WebApi on it. What I need to know is how to use a middleware between then to authorize a JWT for HTTP requests and MVC Action requests.

I've searched everywhere looking for a solution sample, but I couldn't find anything.

If anyone could help, I would be grateful.

Sorry for the English.

Ecumenicism answered 21/9, 2018 at 19:8 Comment(3)
Does Your MVC application and WebAPI reside on the same solution? if yes, what option do you have other then MVC actions?Yelmene
Yes, my MVC and WebAPI in on the same solution. I have the option to change from framework to core applicationEcumenicism
Did you find any solutions?Mailman
D
8

If I grasped your problem statement, I think OWIN might be an option: you decouple your application from underlying hosting and get an extensible pipeline that you can inject middleware into (pretty much like .net core works out of the box).

Even better - it comes with JWT support out of the box (well, you need to install a few nuget packages - see below). Then you simply enable it on your IAppBuilder and roll with standard [Authorize] attributes.

To demo this setup, I've put together a working GitHub repo here to illustrate WebApi middleware.

Apart from Microsoft.AspNet.WebApi.Owin, Microsoft.Owin.Host.SystemWeb and Microsoft.Owin.Security.Jwt nuget packages, it's pretty much a stock standard asp.net WebApi project with the following files changed:

/Startup.cs

using System.Text;
using System.Web.Http;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Jwt;
using Owin;

namespace OWIN.WebApi
{
    public class Startup
    {
        public void Configuration(IAppBuilder appBuilder)
        {
            HttpConfiguration config = new HttpConfiguration();
            WebApiConfig.Register(config); // bootstrap your existing WebApi config 

            appBuilder.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
            {
                AuthenticationMode = AuthenticationMode.Active,
                TokenValidationParameters = new TokenValidationParameters()
                {
                    ValidateIssuer = true,
                    ValidateAudience = true,
                    ValidateIssuerSigningKey = true, // I guess you don't even have to sign the token
                    ValidIssuer = "http://localhost",
                    ValidAudience = "http://localhost",
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("jwt_signing_secret_key"))
                }
            });
            appBuilder.UseWebApi(config); // instruct OWIN to take over
        }
    }
}

/Controllers/ProtectedValuesController.cs

using System.Collections.Generic;
using System.Web.Http;

namespace OWIN.WebApi.Controllers
{
    [Authorize]
    public class ProtectedValuesController : ApiController
    {
        // GET api/values
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }
    }
}

/Controllers/ObtainJwtController.cs

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Text;
using System.Web.Http;
using Microsoft.IdentityModel.Tokens;
using Claim = System.Security.Claims.Claim;

namespace OWIN.WebApi.Controllers
{
    // this class is literally just a test harness to help me generate a valid token for popping into Postman.
    public class ObtainJwtController: ApiController
    {
        private string CraftJwt()
        {
            string key = "jwt_signing_secret_key"; //Secret key which will be used later during validation    
            var issuer = "http://localhost";

            var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
            var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

            var permClaims = new List<Claim>
            {
                new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                new Claim("valid", "1"),
                new Claim("userid", "1"),
                new Claim("name", "test")
            };

            var token = new JwtSecurityToken(issuer,
                issuer,
                permClaims,
                expires: DateTime.Now.AddDays(1),
                signingCredentials: credentials);
            return new JwtSecurityTokenHandler().WriteToken(token);
        }

        public string Get()
        {
            return $"Bearer {CraftJwt()}";
        }
    }
}

This appears to work for MVC too

I have added a few extra nuget packages to do with ASP.NET Identity, which seems to have enabled me to successfully protect the following controller:

/Controllers/Home.cs

using System.Web.Mvc;

namespace OWIN.WebApi.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewBag.Title = "Home Page";

            return View();
        }

        [Authorize]
        public ActionResult Protected()
        {
            return View();
        }
    }
}

Hopefully that gives you some options to explore

Dental answered 4/3, 2020 at 3:2 Comment(10)
please, make sure you mean a classic asp.net mvc, not a netcore appCreaky
@Creaky it is exclusively a full .net framework solution as far as I’m awareDental
that doesn't work with [Authorize] attribute in mvc controllersCreaky
@Creaky okay, let me have another lookDental
there only cookie auth could be used, as it seemsCreaky
Right. It seems, this SO answer confirms your theory - MVC does not play nice with OWIN. Then you might be forced to take that second option and implement the handlerDental
are you sure about handler? seams it relates to web api onlyCreaky
I have just tested my test example with protected MVC action - seems to work as expected. will update github shortlyDental
but how could you provide the token for mvc requests and how do you able to achieve correct validation?Creaky
I was just using postman with Authorization Bearer token header for both endpoints. I think I saw it somewhere that one could store jwt in stock standard asp Auth cookie and get that passed along. Not sure if I would be able to quickly find the source for you, but it seems very doableDental
O
-4

See what I understand from your question You want to use JWT Token for your WebApi and normal process for your MVC, as for later View generated from server and its not dependent on JWT Token.

I have seen this problem. In one of my application I am hosting both MVC views and webapi, whereas MVC view rely on cookie based authentication and authorization. and WebApi call depend upon JWT token for authorization and authentication.

Sorry this solution is from .net core. you need to configure both Cookie and JWT authentication like this

services.AddCookie()
.AddJwtBearer()

Here default would be your cookie authentication. Now to enable jwt token for your webapi you need to decorate webapi with following attribute

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

Hope that's answer your question.

Outlaw answered 5/3, 2020 at 9:17 Comment(1)
Your answer is for .Net Core not .NET framweworkCtenidium

© 2022 - 2024 — McMap. All rights reserved.