CiucaS
CiucaS

Reputation: 2128

Basic Token authentification and authorization on Web.Api

So I have an MVC Application that calls WebApi method.

My Authorization on MVC App is done like this

  public class CustomAuthorizeAttribute : AuthorizeAttribute {

        private RolesEnum _role;

        public CustomAuthorizeAttribute() {
            _role = RolesEnum.User;
        }

        public CustomAuthorizeAttribute(RolesEnum role) {
            _role = role;
        }

        protected override bool AuthorizeCore(HttpContextBase httpContext) {

            User currentUser = (User)httpContext.Session["CurrentUser"];

            if (currentUser == null) {
                return false;
            }

            if (currentUser.Role == RolesEnum.User && _role == RolesEnum.Admin) {
                return false;
            }

            return true;
        }

The authentification is done calling a WebApi method

[HttpPost]
    public ActionResult Login(string username, string password)
    {

        User acc = new User();
        acc.Username = username;
        acc.Password = password;
        acc = accBL.Login(acc);

        if (acc != null) {
            Session.Add("CurrentUser", acc);
            return  RedirectToAction("Index", "Project", null);
        } else {
            return View();
        }


    }

Login method looks like this

  public User LogIn(User acc) {
            try {
                HttpClient client = new HttpClient();
                client.BaseAddress = new Uri(BASE_URL);
                client.DefaultRequestHeaders.Accept.Add(
                   new MediaTypeWithQualityHeaderValue("application/json"));
                HttpResponseMessage response = client.PostAsJsonAsync("api/Account/Login", acc).Result;

                if (response.IsSuccessStatusCode) {
                    return response.Content.ReadAsAsync<User>().Result;
                } else {
                    return null;
                }

            } catch {
                return null;
            }
        }

And WebApi method looks like this

 [Route("api/Account/Login")]
        [HttpPost]
        public IHttpActionResult Login(User userModel) {
            User user = db.Users.Where(p => p.Username == userModel.Username && p.Password == userModel.Password).FirstOrDefault();

            if (user != null) {
                return Ok(user);
            } else {
                throw new HttpResponseException(HttpStatusCode.Unauthorized);
            }

        }

How can I make a connection between the MVC App and the WebApi Services. My authorization and authentification works on MVC part, but my WebApi Services can be called without this any authorization/authenification. How can I secure my WebApi too based on my example? I've been working for about 3 weeks with MVC and WebApi and many things are not very clear too me.

Should I just create a GUID in public IHttpActionResult Login(User userModel) and check for it everytime i a method is called? How do i pass this GUID to MVC App and from MVC to WebApi?

Upvotes: 1

Views: 1536

Answers (1)

ubi
ubi

Reputation: 4399

What you can do is create some sort of a token (eg. JWT) in the WebAPI Login() method and return with the Ok() response (to the MVC app). Users calling your API endpoints have to send this token back (eg. in a custom "Token" header). You can validate the token inside a custom WebAPI authorize attribute that you use in your API endpoints.

eg.

Login endpoint

[Route("api/Account/Login")]
[HttpPost]
public object Login(User userModel) {
    User user = ...;
    string token = CreateTokenForUser(user);

    if (user != null) {
        // return user and token back 
        return new {User = user, Token = token};
    } else {
        throw new HttpResponseException(HttpStatusCode.Unauthorized);
    }
}

Custom authentication filter

public class UserAuthAttribute : ActionFilterAttribute, IAuthenticationFilter
{

    public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
    {
        string token = null;
        IEnumerable<string> tokenHeader;
        if (context.Request.Headers.TryGetValues("Token", out tokenHeader))
            token = tokenHeader.FirstOrDefault();

        if (token != null && IsTokenValid(token)
        {
            // user has been authenticated i.e. send us a token we sent back earlier
        }
        else 
        {
            // set ErrorResult - this will result in sending a 401 Unauthorized
            context.ErrorResult = new AuthenticationFailureResult(Invalid token", context.Request);
        }
    }

}

Other endpoint which only authenticated users should be allowed access

[Route("api/Values")]
[HttpGet]
[UserAuth]
public object GetValues() {

    // only requests with a valid token will be able to call this because of the [UserAuth] attribute
}

Upvotes: 2

Related Questions