In this blog, we'll go through a simple example of how to implement role-based authorization/access control in an ASP.NET Core API with C#.
Step 1: Create users controller that handles all routes/endpoints for the API that relate to users standard CRUD operations.
Step 2: The user class represents the data for a user in the application.
Step 3: The role class defines all the roles.
Step 4: The AppSettings class contains properties defined in the appsettings.json file as shown in step 5. The secret property get value via an IOptions<AppSettings> appSettings object that is injected into the controller constructor as shown in step 1.
Step 5: The
Step 6: The user service contains all methods and logic that is called by the Users controller.
Step 8: The startup class configures the request pipeline of the application.
Step 9: Following are the screenshot of 'Postman' by which api tested.
Step 1: Create users controller that handles all routes/endpoints for the API that relate to users standard CRUD operations.
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using System.Collections.Generic;
using WebAPIAuth.Helpers;
using WebAPIAuth.Model;
using WebAPIAuth.Service;
namespace WebAPIAuth.Controllers
{
[Produces("application/json")]
[Authorize]
[Route("[controller]")]
public class UsersController : Controller
{
private readonly AppSettings _appSettings;
private IAuthorizationService _authorizationService;
public UsersController(IOptions<AppSettings> appSettings, IAuthorizationService authorizationService)
{
_appSettings = appSettings.Value;
_authorizationService = authorizationService;
}
[HttpGet]
[AllowAnonymous]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
[AllowAnonymous]
[HttpPost("authUsers")]
public Users AuthUsers([FromBody]Users _user)
{
if(_user == null)
{
return null;
}
UserService userObj = new UserService();
Users user = userObj.GetValidUser(_user.Username, _user.Password);
if (user == null)
return null;
AuthorizeService auth = new AuthorizeService();
string _token = auth.Authenticate(_user.Username,_appSettings, Role.Admin);
user.Token = _token;
return user;
}
//Role base Authentication
[Authorize(Roles = Role.Admin)]
[HttpGet]
[Route("GetAll")]
public IActionResult GetAll()
{
UserService _users = new UserService();
var users = _users.GetAll();
return Ok(users);
}
[HttpGet("{id}")]
public IActionResult GetById(int id)
{
UserService _users = new UserService();
var user = _users.GetById(id);
if (user == null)
{
return NotFound();
}
// only allow admins to access other user records
var currentUserId = User.Identity.Name;
if (user.Username != currentUserId && !User.IsInRole("Admin"))
{
return Forbid();
}
return Ok(user);
}
}
}
Step 2: The user class represents the data for a user in the application.
namespace WebAPIAuth.Model
{
public class Users
{
public int Id { get; set; }
public string Name { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public string Role { get; set; }
public string Token { get; set; }
}
}
Step 3: The role class defines all the roles.
namespace WebAPIAuth.Model
{
public class Role
{
public const string Admin = "Admin";
public const string User = "User";
}
}
Step 4: The AppSettings class contains properties defined in the appsettings.json file as shown in step 5. The secret property get value via an IOptions<AppSettings> appSettings object that is injected into the controller constructor as shown in step 1.
namespace WebAPIAuth.Helpers
{
public class AppSettings
{
public string Secret { get; set; }
}
}
Step 5: The
"Secret"
property is used by the api to sign and verify tokens for authentication.
{
"AppSettings": {
"Secret": "THIS IS USED TO SIGN AND VERIFY PROJECT TOKENS, BY VIJAY"
},
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
}
},
"Console": {
"LogLevel": {
"Default": "Warning"
}
}
}
}
Step 6: The user service contains all methods and logic that is called by the Users controller.
using System.Collections.Generic;
using System.Linq;
using WebAPIAuth.Model;
namespace WebAPIAuth.Service
{
public class UserService
{
private List<Users> _users = new List<Users>
{
new Users { Id = 1,Name = "Admin", Username = "admin", Password = "admin", Role = Role.Admin },
new Users { Id = 2, Name = "User", Username = "user", Password = "user", Role = Role.User }
};
public Users GetValidUser(string username, string password)
{
var user = _users.SingleOrDefault(x => x.Username == username && x.Password == password);
return user;
}
public IEnumerable<Users> GetAll()
{
// return users without passwords
return _users.Select(x => {
x.Password = null;
return x;
});
}
public Users GetById(int id)
{
var user = _users.FirstOrDefault(x => x.Id == id);
// return user without password
if (user != null)
user.Password = null;
return user;
}
}
}
Step 7: The authorize service contains a method for authenticating user credentials and return a token
using Microsoft.IdentityModel.Tokens;
using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using WebAPIAuth.Helpers;
namespace WebAPIAuth.Service
{
public interface IAuthorizeService
{
string Authenticate(string username, AppSettings _appSettings, string role);
}
public class AuthorizeService: IAuthorizeService
{
public string Authenticate(string username, AppSettings _appSettings, string role)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, username),
// this is optional, If you wants role base authentication then use it
new Claim(ClaimTypes.Role,role)
}),
Expires = DateTime.UtcNow.AddDays(7),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};
var token = tokenHandler.CreateToken(tokenDescriptor);
string _token = tokenHandler.WriteToken(token);
return _token;
}
}
}
Step 8: The startup class configures the request pipeline of the application.
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.IdentityModel.Tokens;
using System.IO;
using System.Text;
using WebAPIAuth.Helpers;
using WebAPIAuth.Service;
namespace WebAPIAuth
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddMvc();
// configure strongly typed settings objects
var appSettingsSection = Configuration.GetSection("AppSettings");
services.Configure<AppSettings>(appSettingsSection);
// configure jwt authentication
var appSettings = appSettingsSection.Get<AppSettings>();
var key = Encoding.ASCII.GetBytes(appSettings.Secret);
services.AddAuthentication(x =>
{
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(x =>
{
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
});
services.AddScoped<IAuthorizeService, AuthorizeService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// global cors policy
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
app.UseAuthentication();
app.UseMvc();
}
}
}
Step 9: Following are the screenshot of 'Postman' by which api tested.
No comments:
Post a Comment