Token Based Authentication using ASP.NET Web API 2, Owin, AspNet.Identity.MongoDB and mongocsharpdriver - mongodb

+after successfully implementing Token Based Authentication using ASP.NET Web API 2, Owin, and Identity, i wished to change my implementation to use MongoDB instead of MSSQL with Entity Framework, with the help of this application here....truth be said, i dont fully understand how this should be done, but at least i know what i want my application to behave. i want to follow this IMPLEMENTATION HERE, using AspNet.Identity.MongoDB and mongocsharpdriver...and so far, here,s what I've done:
Account Controller
using Microsoft.AspNet.Identity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using System.Web.Http;
using withMongoDB.HelperClasses.Services;
using withMongoDB.Models.Account;
namespace withMongoDB.Controllers
{
[RoutePrefix("api/Account")]
public class AccountsController : ApiController
{
AccountsService _accountsService = new AccountsService();
// POST api/Account/Register
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(UserModel userModel)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
await _accountsService.Register(userModel);
return Ok();
}
private IHttpActionResult GetErrorResult(IdentityResult result)
{
if (result == null)
{
return InternalServerError();
}
if (!result.Succeeded)
{
if (result.Errors != null)
{
foreach (string error in result.Errors)
{
ModelState.AddModelError("", error);
}
}
if (ModelState.IsValid)
{
// No ModelState errors are available to send, so just return an empty BadRequest.
return BadRequest();
}
return BadRequest(ModelState);
}
return null;
}
}
}
then the register method from the controller should be taken by the accounts Service
using AspNet.Identity.MongoDB;
using Microsoft.AspNet.Identity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Web;
using withMongoDB.Models.Account;
namespace withMongoDB.HelperClasses.Services
{
public class AccountsService
{
private readonly MongoAccountsConnectionHelper<UserProfile> _accounts;
public AccountsService()
{
_accounts = new MongoAccountsConnectionHelper<UserProfile>();
}
public async Task<IdentityResult> Register(UserModel userModel)
{
var userprofile = new UserProfile
{
UserName = userModel.UserName
};
var result = await _accounts.CreateAsync(userprofile, userModel.Password);
return result;
}
}
}
and finally the MongoAccountsConnectionHelper takes the result of the accounts service class to mongo database....
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace withMongoDB.HelperClasses
{
using AspNet.Identity.MongoDB;
//using Entities;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Conventions;
using MongoDB.Driver;
using System.Configuration;
using withMongoDB.Models.Account;
public class MongoAccountsConnectionHelper
{
private readonly MongoCollection<UserProfile> userProfileCollection;
public MongoDatabase Database { get; private set; }
public MongoAccountsConnectionHelper()
{
var pack = new ConventionPack()
{
new CamelCaseElementNameConvention(),
new EnumRepresentationConvention(BsonType.String)
};
ConventionRegistry.Register("CamelCaseConvensions", pack, t => true);
var mongoUrlBuilder = new MongoConnectionStringBuilder(ConfigurationManager.ConnectionStrings["MongoDB"].ConnectionString);
Database = new MongoClient().GetServer().GetDatabase(mongoUrlBuilder.DatabaseName);
userProfileCollection = Database.GetCollection<UserProfile>("users");
}
public MongoCollection<UserProfile> Users
{
get { return userProfileCollection; }
}
}
}
any help, tips, ideas, or opinions will be highly appreciated....{should i consider alternatives like MembershipReboot and IdentityReboot by brockallen?}

To do it smoothly, you need first to remove the dependency on "Microsoft.AspNet.Identity.EntityFramework", by providing your own user class/table (which should implements IUser as a minimum), and Also you need to implement the UserManager class (which should imeplements UserManager, and finally you need to implement the UserStore class (which should implement IUserStore as minimum) where T is the Id type in the User Table.
Once you done the above, then it is the UserStore where you can change to use MongoDB.
Hope that helps.

Related

How can I Insert data from code to Db and create POST method

Entity framework
I have to insert the data from code to Db and I have to create POST method. For this I have made the Employee controller but I am getting some error in code. This is my code:
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using VENUS.HRMS.DATA.Models;
namespace VENUS.HRMS.API.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class EmployeeController : ControllerBase
{
[HttpPost]
public TblEmployee InsertTblEmployee(TblEmployee _tblemployee)
{
using (TblEmployeesEntities entities = new TblEmployeesEntities())
{
entities.TblEmployees.Add(_tblemployee);
entities.SaveChanges();
}
return _tblemployee;
}
}
}
I am getting error on TblEmployeesEntities entities = new TblEmployeesEntities.
Please help me out.
I guess this sample code could help you. Write your DBcontext like below:
public partial class TblEmployeesEntities : DbContext
{
public TblEmployeesEntities ()
{ }
public TblEmployeesEntities (DbContextOptions<TblEmployeesEntities> options)
: base(options)
{ }
public virtual DbSet<TblEmployee> TblEmployees{ get; set; }
}
Then it's time to inject dbcontext in the startup if your DBMS is SQL server.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TblEmployeesEntities >(options =>
options.UseSqlServer("ConnectionString"));
}
Now just create a constructor in the controller and use DbContext:
private readonly TblEmployeesEntities _context;
public EmployeeController (TblEmployeesEntities context)
{
_context = context;
}
[HttpPost]
public TblEmployee InsertTblEmployee(TblEmployee _tblemployee)
{
_context.TblEmployees.Add(_tblemployee);
_context.SaveChanges();
return _tblemployee;
}

How to add custom JWT token authentication to a .NET Framework SignalR server?

I have created a SignalR Server using .NET Framework (not .NET Core). It works fine. Now, I want to add custom JWT authentication to it.
Chat Hub:
public class ChatHub : Hub
{
[Authorize]
public void Send(string name, string message)
{
Clients.All.broadcastMessage(name, message);
}
}
I added Authorize attribute in the Hub method.
Startup.cs:
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using Microsoft.Owin;
using Microsoft.Owin.Cors;
using Microsoft.Owin.Security.OAuth;
using Owin;
using SignalRServer.Authorization;
using SignalRServer.Providers;
[assembly: OwinStartup(typeof(SignalRServer.Startup))]
namespace SignalRServer
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
map.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
Provider = new QueryStringOAuthBearerProvider()
});
map.RunSignalR();
});
}
}
}
QueryStringOAuthBearerProvider:
using System;
using System.Threading.Tasks;
using Microsoft.Owin.Security.OAuth;
namespace SignalRServer.Providers
{
public class QueryStringOAuthBearerProvider : OAuthBearerAuthenticationProvider
{
public override Task RequestToken(OAuthRequestTokenContext context)
{
var value = context.Request.Query.Get("token");
if (!string.IsNullOrEmpty(value))
{
context.Token = value;
}
return Task.FromResult<object>(null);
}
}
}
What I want to do?
I want all the SignalR clients to send a JWT token in query string. I will custom validate this token in QueryStringOAuthBearerProvider's RequestToken method. If the validation succeeds, then the Hub method protected by Authorize attribute should be called otherwise the request is denied.
Please advise how to achieve this and what I am missing here.
PS: I want to do exactly the same thing done here but using .NET Framework (not .NET Core)

Asp.net MVC entity framework Path is not working in - WebAPI Controller Class

Filename: DemoController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;
namespace MVCEntityFramework.Controllers.Api
{
public class DemoController : ApiController
{
// GET api/<controller>
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET api/<controller>/5
public string Get(int id)
{
return "value";
}
// POST api/<controller>
public void Post([FromBody] string value)
{
}
// PUT api/<controller>/5
public void Put(int id, [FromBody] string value)
{
}
// DELETE api/<controller>/5
public void Delete(int id)
{
}
}
}
ScreenShot 1: https://i.stack.imgur.com/lDQ4O.png
ScreenShot 2: https://i.stack.imgur.com/ObG6W.png
Path Not Working:
https://localhost:44310/api/demo/get/2
https://localhost:44310/api/democontroller/get/2
Response:
HTTP Error 404.0 - Not Found
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
It'll work by convention so if you need to call Get by id just use https://localhost:44310/api/demo/2 without action name but you need to specify verb HttpGet if you need to call Post also you will call https://localhost:44310/api/demo with specify verb HttpPost
This is how to call post action using postman for example
or add [Route("[controller]")] attribute to class like
[Route("[controller]")]
public class DemoController : ApiController
{
// GET api/<controller>
[Route("Get")]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
so in this case you can add controller name to your endpoint like https://localhost:44310/api/demo/get/2

Unable to Send email via .Net core 2.0

I wrote the following and was running perfectly. But after updates stops running, I have already setup a mail server I had not any problem.
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using SportsStore.Data;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Security.Claims;
using System.Threading.Tasks;
namespace SportsStore.Helper
{
public class Email: IEmail
{
private SmtpClient Client;
private string MessageBody, Subject, UserEmail;
private MailAddress MailFrom, MailTo;
private MailMessage Message;
public Email(IServiceProvider service)
{
this.Client = new SmtpClient("localhost");
this.Client.Port = 25;
this.Client.UseDefaultCredentials = false;
this.Client.Credentials = new NetworkCredential("postmaster", "xxxxxxx!");
this.MailFrom = new MailAddress("xxxxx.xxxxx#yandex.com");
this.UserEmail = service.GetRequiredService<IHttpContextAccessor>().HttpContext.User.Identity.Name;
this.MailTo = new MailAddress(UserEmail);
}
public void SetMessageBody(string orderName)
{
MessageBody = String.Format("The order with id {0} has been placed and is ready to ship", orderName);
}
public string GetMessageBody()
{
return MessageBody;
}
public void SetSubject()
{
Subject = "Order Details";
}
public string GetSubject()
{
return Subject;
}
public bool SendMessageAsync()
{
this.Message = new MailMessage(this.MailFrom.ToString(), this.MailTo.ToString(), this.GetSubject(), this.GetMessageBody());
if (this.Client.SendMailAsync(this.Message).IsCompletedSuccessfully)
{
return true;
}
return false;
}
}
}
The Client.SendEmailAsync() now return false.
Any suggestion?Please give a quick answer or I have to jump to nuget packages for a package to install.
The method SendMailAsync is Async in your Send Mail in your application.
What are best practices for using SmtpClient, SendAsync and Dispose under .NET 4.0

Adding Custom Filters for Dynamic Data Website (VS2010, EF4)

Trying to add some different filters (in addition to the ForeignKey filter) to a Dynamic Data Website in VS2010 using EF4. I can add the new Filter templates, but how do I specify which template will get displayed for each property in my model?
Thanks
Here are the steps for how to do this:
1) Create a new UserControl for the filter you want under DynamicData\Filters. I created a TextFilter.ascx:
<%# Control Language="C#" AutoEventWireup="true" CodeBehind="TextFilter.ascx.cs" Inherits="Test.Prototype.Web.DynamicData.DynamicData.Filters.TextFilter" %>
<asp:TextBox runat="server" ID="TextBox1" AutoPostBack="true" OnTextChanged="TextBox1_OnTextChanged" CssClass="DDFilter">
</asp:TextBox>
and the code behind:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Linq.Expressions;
using System.Web.DynamicData;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace Test.Prototype.Web.DynamicData.DynamicData.Filters
{
public partial class TextFilter : System.Web.DynamicData.QueryableFilterUserControl
{
private const string NullValueString = "[null]";
protected void Page_Load(object sender, EventArgs e)
{
}
public override Control FilterControl
{
get
{
return TextBox1;
}
}
protected void TextBox1_OnTextChanged(object sender, EventArgs e)
{
OnFilterChanged();
}
public override IQueryable GetQueryable(IQueryable source)
{
string selectedValue = TextBox1.Text;
if (String.IsNullOrEmpty(selectedValue))
{
return source;
}
object value = selectedValue;
if (selectedValue == NullValueString)
{
value = null;
}
if (DefaultValues != null)
{
DefaultValues[Column.Name] = value;
}
return ApplyEqualityFilter(source, Column.Name, value);
}
}
}
Then in your model, just annotate your properties with the FilterUIHint attribute pointing to the next filter and you're good to go:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel.DataAnnotations;
namespace Test.Model
{
public partial class Asset
{
#region Primitive Properties
public virtual int Id
{
get;
set;
}
[FilterUIHint("TextFilter")]
public virtual string Name
{
get;
set;
}
...