How to use role based claims in mogodb using asp.net core 1.1? - mongodb

I am working in Asp.net core Application.I want to use role based claims in my application, i have tried following code, but its not working.Its not creating aspnetrolesclaim table in db. Did i do any think wrong?
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
CreateRolesAndAdminUser(app);
}
private async Task CreateRolesAndAdminUser(IApplicationBuilder app)
{
var _roleManager = app.ApplicationServices.GetRequiredService<RoleManager<ApplicationRole>>();
var roleExists = await _roleManager.RoleExistsAsync("Admin");
if (!roleExists)
{
var role = new ApplicationRole()
{
Name = RoleName.SuperUser,
NormalizedName = RoleName.SuperUser.ToUpper(),
};
await _roleManager.CreateAsync(role);
await _roleManager.AddClaimAsync(role, new Claim("User","Create"));
await _roleManager.AddClaimAsync(role, new Claim("User","Edit"));
await _roleManager.AddClaimAsync(role, new Claim("User", "Delete"));
}
string adminUserEmail = "admin#adminstore.com";
string adminPwd = "admin#123";
var _userManager = app.ApplicationServices.GetRequiredService<UserManager<ApplicationUser>>();
var checkAppUser = await _userManager.FindByEmailAsync(adminUserEmail);
if (checkAppUser == null)
{
ApplicationUser newAppUser = new ApplicationUser
{
Email = adminUserEmail,
UserName = adminUserEmail,
NormalizedEmail = adminUserEmail.ToUpper(),
NormalizedUserName = adminUserEmail.ToUpper(),
};
await _userManager.CreateAsync(newAppUser, adminPwd);
await _userManager.AddToRoleAsync(newAppUser,"Admin");
}
}

Related

Npgsql Performance

I am trying to implement Npgsql in our DAL and running into issues under heavy load. the following sample application is a decent representation of just a simple query that under heavy load, throws a 'A command is already in progress' exception. I am assuming this is due to the lack of MARS support so I also tried creating a connection each time with a using statement around each command only to have the performance become unusable. I checked that the username is indexed so that shouldn't be an issue.
Not sure what I am doing wrong here but I need some advice on how to get this performing well.
OS: Docker Container: microsoft/dotnet:2.1.301-sdk
using Npgsql;
using System;
using System.Collections.Generic;
using System.Data.Common;
using System.Linq;
using System.Threading.Tasks;
namespace npgsqlTest
{
class Program
{
static async Task Main(string[] args)
{
DAL dal = new DAL();
dal.Prepare();
var tasks = dal.Users.Select(async user =>
{
Console.WriteLine(await dal.RunTest(user));
});
await Task.WhenAll(tasks);
}
}
public class DAL
{
private static string _ConnectionString;
private NpgsqlConnection _Connection;
public List<string> Users { get; set; } = new List<string>();
public DAL()
{
_ConnectionString = $"Host=192.168.1.1;Username=admin;Port=5432;Password=password;Database=BigDB;";
_Connection = new NpgsqlConnection(_ConnectionString);
_Connection.Open();
}
public void Prepare()
{
string query = "SELECT username FROM usertable;";
using (var cmd = new NpgsqlCommand(query, _Connection))
{
var reader = cmd.ExecuteReader();
using (reader)
{
while (reader.Read())
{
Users.Add(reader[0].ToString());
}
}
}
}
public async Task<string> RunTest(string user)
{
var parameters = new Dictionary<string, Object> { { "username", user } };
var query = $"SELECT name FROM usertable WHERE username = (#username);";
var reader = await QueryAsync(query, parameters);
using (reader)
{
if (reader.HasRows)
{
while (await reader.ReadAsync())
{
var name = reader["name"];
if (!(hash is DBNull))
return (string)name;
}
}
}
return String.Empty;
}
public async Task<DbDataReader> QueryAsync(string query, Dictionary<string, Object> parameters)
{
using (var cmd = new NpgsqlCommand(query, _Connection))
{
foreach (var parameter in parameters)
{
cmd.Parameters.AddWithValue(parameter.Key, parameter.Value == null ? DBNull.Value : parameter.Value);
}
cmd.Prepare();
return await cmd.ExecuteReaderAsync();
}
}
}
}

How to Access using Xamarin.Forms local Web API with Emulator for Visual Studio?

I've created .NET Framework API which contains authentication, I launch the Web API using Jetbrains Rider and I run my Xamarin.Forms application using Visual Studio and I can't access any data from my Web API nor post any.
The Webservice class:
private readonly HttpClient _client;
public AccountService()
{
_client = new HttpClient
{
MaxResponseContentBufferSize = 256000
};
}
public async Task RegisterAsync(string email, string password, string confirmPassword)
{
var url = "http://169.254.80.80:61348/api/Account/Register";
var model = new RegisterBindingModel()
{
Email = email,
Password = password,
ConfirmPassword = confirmPassword
};
var json = JsonConvert.SerializeObject(model);
HttpContent content = new StringContent(json);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var response = await _client.PostAsync(url, content);
}
The initiation of the registration
private async void Register()
{
try
{
using (UserDialogs.Instance.Loading())
{
await _accountServices.RegisterAsync
(Email, Password, ConfirmPassword);
}
UserDialogs.Instance.Alert("Register Successful");
await _navigation.PushAsync(new LoginPage());
}
catch
{
UserDialogs.Instance.Alert("Something wrong happened, Try again");
}
}
I've tried to access the localhost through Emulator using these IPs:
10.0.3.2
10.0.2.2
169.254.80.80
And I've tried my default gateways and my local IP address with and without ports, in regardless using postman i can work with my api flawlessly.
I don't get errors but the connection status code is not successful and I don't get any data and the newly registered account won't be posted to the api.
EDIT:
As for the answers I've changed my method to this:
public async Task<string> RegisterAsync(string email, string password, string confirmPassword)
{
var client = new HttpClient()
{
BaseAddress = new Uri("http://169.254.80.80:61348/")
};
var postData = new List<KeyValuePair<string, string>>();
var nvc = new List<KeyValuePair<string, string>>();
nvc.Add(new KeyValuePair<string, string>("email", email));
nvc.Add(new KeyValuePair<string, string>("password", password));
nvc.Add(new KeyValuePair<string, string>("confirmPassword", confirmPassword));
var req = new HttpRequestMessage(HttpMethod.Post, "api/Account/Register") { Content = new FormUrlEncodedContent(nvc) };
var res = await client.SendAsync(req);
if (res.IsSuccessStatusCode)
{
string result = await res.Content.ReadAsStringAsync();
string test = JsonConvert.DeserializeObject<string>(result);
return test;
}
return null;
}
and i call the web api using postman like this:
http://localhost:61348/api/Account/Register
I always prefer Newtonsoft Json.NET to carry out web request here is the code I have implemented in my case and it works great for me.
public static async Task<string> ResgisterUser(string email, string password, string confirmPassword)
{
var client = new HttpClient(new NativeMessageHandler());
client.BaseAddress = new Uri("http://192.168.101.119:8475/");
var postData = new List<KeyValuePair<string, string>>();
var nvc = new List<KeyValuePair<string, string>>();
nvc.Add(new KeyValuePair<string, string>("email", email));
nvc.Add(new KeyValuePair<string, string>("password", password));
nvc.Add(new KeyValuePair<string, string>("confirmPassword",confirmPassword));
var req = new HttpRequestMessage(HttpMethod.Post, "api/Vendor/Register") { Content = new FormUrlEncodedContent(nvc) };
var res = await client.SendAsync(req);
if (res.IsSuccessStatusCode)
{
string result = await res.Content.ReadAsStringAsync();
string test= JsonConvert.DeserializeObject<string>(result);
return test;
}
}
Hope it works for you.

Asp.Net-Core + MongoDb - How to search database by "code" and return the original url?

I am unsure how to go about searching for the "Code" stored in my Database in order to return the "OriginalUrl".
I know I can search for the ObjectId but I want to be able to search by the "Code" assigned to that ObjectId.
Currently I have a working program that takes a Url as well as a "title" and sends it to the database:
It is assigned an Objectid _id and a randomly generated 12 character "Code":
If it helps this is my Controller class:
namespace ShortenUrls.Controllers
{
[Route("api/codes")]
public class ShortUrlsController : Controller
{
private readonly ShortUrlRepository _repo;
public ShortUrlsController(ShortUrlRepository repo)
{
_repo = repo;
}
[HttpGet("{id}")]
public async Task<IActionResult> Get(string id)
{
var su = await _repo.GetAsync(id);
if (su == null)
return NotFound();
return Ok(su);
}
[HttpPost]
public async Task<IActionResult> Create([FromBody] ShortUrl su)
{
await _repo.CreateAsync(su);
return Ok(su);
}
}
And Repository class:
namespace ShortenUrls.Models.Repository
{
public class ShortUrlRepository
{
private const string alphabet = "23456789bcdfghjkmnpqrstvwxyz-_";
private static readonly Random rand = new Random();
private readonly Database _db;
public ShortUrlRepository(Database db)
{
_db = db;
}
private static string GenerateCode()
{
const int codeLength = 12;
var chars = new char[codeLength];
for (var i = 0; i < codeLength; i++)
{
chars[i] = alphabet[rand.Next(0, alphabet.Length)];
}
return new string(chars);
}
public Task<ShortUrl> GetAsync(string id)
{
var objId = ObjectId.Parse(id);
return _db.Urls.Find(x => x.Id == objId).FirstOrDefaultAsync();
}
public Task CreateAsync(ShortUrl su)
{
su.Code = GenerateCode();
return _db.Urls.InsertOneAsync(su);
}
}
Just use a filter. Doing it this way let's you create a query specifically for the "code".
public async Task<ShortUrl> GetAsync(string code)
{
var filterBuilder = new FilterDefinitionBuilder<ShortUrl>();
var filter = filterBuilder.Eq(s => s.Code, code);
var cursor = await _db.Urls.FindAsync(filter);
return await cursor.FirstOrDefaultAsync();
}
Assuming you already know the code when calling this and that ObjectId is created on InsertOneAsync call. First change your repository to take Code as searchable input.
public Task<ShortUrl> GetAsync(string code)
{
return await _db.Urls.FirstOrDefaultAsync(x => x.Code == code);
}
Then change your controller Get to this:
[HttpGet("{code}")]
public async Task<IActionResult> Get(string code)
{
var su = await _repo.GetAsync(code);
if (su == null)
return NotFound();
return Ok(su);
}
In your controller you can access su.OriginalUrl if you need to only return that after getting the object.
Then in postman you can just call http://localhost:51767/api/codes?code=cmg3fjjr_gtv
Remember only Id works for default url parameters as setup by your default routes in Startup.cs.
app.UseMvc(routes => { /*...*/ })
So this wont work: /api/codes/cmg3fjjr_gtv unless you specifically set up routing or change {code} back to {id}. Readability of your code suffers though.

Set CookieAuthentication redirect path

I only want users with an LocationId to be able to acces my controller methods.
On the location index page the users enter their id, which is saved in a cookie.
If a user tries to acces an page without, the user should be redirecteded to the location index page.
This almost work, but I have a problem with the redirect.
I am using asp net core 2.0.
My controller looks like this
[AllowAnonymous]
public class LocationController : Controller
{
...
[HttpGet]
public IActionResult Index()
{
return View();
}
[HttpPost]
public async Task<IActionResult> Index(string id)
{
ILocationModel location = await _repo.GetLocation(id);
if (location != null)
{
var claims = new List<Claim> { new Claim(ClaimTypes.Name, location.id) };
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity));
return RedirectToAction("index", "shop");
}
return RedirectToAction("", "");
}
And in configureServices() in startup I have:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.ReturnUrlParameter = "";
options.AccessDeniedPath = "/Location/Index/";
options.LoginPath = "/Location/Index";
options.LogoutPath = "/Location/Logout";
});
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
When I access an page unauthorized I get redirected to http://localhost:54104/Location/Index?=%2FLocation%2FIndex%3F%3D%252FLocation%252FIndex%253F%253D%25252FLocation%25252FIndex%25253F%25253D%2525252FLocation%2525252FIndex%2525253F%2525253D%252525252FLocation%252525252FIndex%252525253F%252525253D%25252525252FLocation%25252525252FIndex%25252525253F%25252525253D%2525252525252FLocation%2525252525252FIndex%2525252525253F%2525252525253D%252525252525252FLocation%252525252525252FIndex%252525252525253F%252525252525253D%25252525252525252FLocation%25252525252525252FIndex%25252525252525253F%25252525252525253D%2525252525252525252FLocation%2525252525252525252FIndex%2525252525252525253F%2525252525252525253D%252525252525252525252FLocation%252525252525252525252FIndex%252525252525252525253F%252525252525252525253D%25252525252525252525252FLocation%25252525252525252525252FIndex%25252525252525252525253F%25252525252525252525253D%2525252525252525252525252FLocation%2525252525252525252525252FIndex%2525252525252525252525253F%2525252525252525252525253D%252525252525252525252525252FLocation%252525252525252525252525252FIndex%252525252525252525252525253F%252525252525252525252525253D%25252525252525252525252525252FLocation%25252525252525252525252525252FIndex%25252525252525252525252525253F%25252525252525252525252525253D%2525252525252525252525252525252FLocation%2525252525252525252525252525252FIndex%2525252525252525252525252525253F%2525252525252525252525252525253D%252525252525252525252525252525252FLocation%252525252525252525252525252525252FIndex%252525252525252525252525252525253F%252525252525252525252525252525253D%25252525252525252525252525252525252FLocation%25252525252525252525252525252525252FIndex%25252525252525252525252525252525253F%25252525252525252525252525252525253D%2525252525252525252525252525252525252FLocation%2525252525252525252525252525252525252FIndex%2525252525252525252525252525252525253F%2525252525252525252525252525252525253D%252525252525252525252525252525252525252FLocation%252525252525252525252525252525252525252FIndex%252525252525252525252525252525252525253F%252525252525252525252525252525252525253D%25252525252525252525252525252525252525252FLocation%25252525252525252525252525252525252525252FIndex
witch causes an
HTTP Error 404.15 - Not Found
The request filtering module is configured to deny a request where the query string is too long.
Why is all this appended to the path?
I had the same problem. It's creating an infinite loop. You have to set a RedirectUri in a AuthenticationProperties object, in your index method (the HttpPost one). Like so:
var auth = new AuthenticationProperties()
{
RedirectUri = "/index/shop"
};
It could be like:
[HttpPost]
public async Task<IActionResult> Index(string id)
{
ILocationModel location = await _repo.GetLocation(id);
var auth = new AuthenticationProperties()
{
RedirectUri = "/index/shop"
};
if (location != null)
{
var claims = new List<Claim> { new Claim(ClaimTypes.Name, location.id) };
var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(claimsIdentity));
// You have to create a ChallengeResult, otherwise it will be stuck there, and you send the user to where you want to
return new ChallengeResult("cookies", auth);
}
return new ChallengeResult("cookies", auth);
}
For more info: https://dotnetcoretutorials.com/2017/09/16/cookie-authentication-asp-net-core-2-0/

Seed data to UserRole table .net core

I want to seed the default DB with an admin user before I start the project on .NET Core Default MVC application. The code is as below:
public void SeedDb(ApplicationDbContext Context, IServiceProvider ServiceProvider, IConfiguration Configuration)
{
if (Context.Users.Count() > 0) return;
var UserManager = ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
var ApplicationUser = new ApplicationUser()
{
Email = Configuration["Email"],
NormalizedEmail = Configuration["Email"],
LockoutEnabled = false,
NormalizedUserName = Configuration["Email"],
SecurityStamp = "579355dd - a64c - 498d - a0b5 - 9e55754c9109",
EmailConfirmed = true,
ConcurrencyStamp = null,
Id = "977ec1a5-1ae7-4658-952a-6b5dccd75a85",
PasswordHash ="",
PhoneNumber = "333333333333",
LockoutEnd = null,
AccessFailedCount = 1,
PhoneNumberConfirmed = true,
TwoFactorEnabled = false,
UserName = Configuration["Email"]
};
var Password = HashPassword(ApplicationUser, Configuration["Password"]);
if (VerifyHashedPassword(ApplicationUser, Password, Configuration["Password"]) == PasswordVerificationResult.Success)
{
ApplicationUser.PasswordHash = Password;
}
Context.Users.Add(ApplicationUser);
Context.SaveChanges();
var RoleManager = ServiceProvider.GetRequiredService<RoleManager<IdentityRole>>();
string[] Roles = { "Admin", "Manager", "User" };
foreach (string RoleName in Roles) {
RoleManager.CreateAsync(new IdentityRole(RoleName));
}
var Admin = Context.Users.SingleOrDefault(m => m.Email == Configuration["Email"]);
var Role = Context.Roles.SingleOrDefault(m => m.Name == Configuration["Role"]);
IdentityUserRole<string> UserRole = new IdentityUserRole<string>() { UserId = Admin.Id, RoleId = Role.Id };
Context.UserRoles.Add(UserRole);
Context.SaveChanges();
}
Everything runs perfect except I can't seed the UserRole DB with Data. From DBContext I add IdentityUserRole entity and save the changes to DB. Although nothing passed under the DB. Any suggestion?
Create a class named StartupDbInitializer:
using System;
using System.Collections.Generic;
using System.Linq;
using Core.Entities;
using Microsoft.AspNetCore.Identity;
namespace Core.Startups
{
public class StartupDbInitializer
{
private const string AdminEmail = "admin#admin.com";
private const string AdminPassword = "StrongPasswordAdmin123!";
private static readonly List<IdentityRole> Roles = new List<IdentityRole>()
{
new IdentityRole {Name = "Admin", NormalizedName = "ADMIN", ConcurrencyStamp = Guid.NewGuid().ToString()}
};
public static void SeedData(ApplicationDbContext dbContext, UserManager<User> userManager)
{
dbContext.Database.EnsureCreated();
AddRoles(dbContext);
AddUser(dbContext, userManager);
AddUserRoles(dbContext, userManager);
}
private static void AddRoles(ApplicationDbContext dbContext)
{
if (!dbContext.Roles.Any())
{
foreach (var role in Roles)
{
dbContext.Roles.Add(role);
dbContext.SaveChanges();
}
}
}
private static async void AddUser(ApplicationDbContext dbContext, UserManager<User> userManager)
{
if (!dbContext.Users.Any())
{
var user = new User {
UserName = AdminEmail,
Email = AdminEmail,
IsEnabled = true,
EmailConfirmed = true,
};
await userManager.CreateAsync(user, AdminPassword);
}
}
private static void AddUserRoles(ApplicationDbContext dbContext, UserManager<User> userManager)
{
if (!dbContext.UserRoles.Any())
{
var userRole = new IdentityUserRole<string>
{
UserId = dbContext.Users.Single(r => r.Email == AdminEmail).Id,
RoleId = dbContext.Roles.Single(r => r.Name == "Admin").Id
};
dbContext.UserRoles.Add(userRole);
dbContext.SaveChanges();
}
}
}
}
Then call it in your Startup's Configure method:
public void Configure(
IApplicationBuilder app,
IHostingEnvironment env,
ApplicationDbContext dbContext,
UserManager<User> userManager,
)
{
// rest of code...
StartupDbInitializer.SeedData(dbContext, userManager);
}
Above, I inject my DbContext and UserManager<T>.
Try this line... it must work.
ApplicationUser user = await _usermanager.FindByEmailAsync("your.email#mymail.com");
if (!await _usermanager.IsInRoleAsync(user, "Admin"))
{
await _usermanager.AddToRoleAsync(user, "Admin");
}
When you tried it and it works, change it to your config parameters if you prefer them. It's not that hard to get it to work, you have everything you need in UserManager and RoleManager classes.
I still say you have to check if the role exist in table before you insert it, I got all my roles populated every time I run the application before I added the check.
if ((await _roleManager.FindByNameAsync("Admin")) == null)
{
await _roleManager.CreateAsync(new IdentityRole { Name = "Admin" });
}