protected void Application_PostAuthenticateRequest()
{
HttpCookie authoCookies = Request.Cookies[FormsAuthentication.FormsCookieName];
if (authoCookies != null)
{
FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(authoCookies.Value);
JavaScriptSerializer js = new JavaScriptSerializer();
User1 user = js.Deserialize<User1>(ticket.UserData);
MyIdentity myIdentity = new MyIdentity(user);
MyPrincipal myPrincipal = new MyPrincipal(myIdentity);
HttpContext.Current.User = myPrincipal; //here
}
}
Error is in the very last line...
Here is MyPrincipal class.
public class MyPrincipal
{
private readonly MyIdentity MyIdentity;
public MyPrincipal(MyIdentity _myIdentity)
{
MyIdentity = _myIdentity;
}
public IIdentity Identity
{
get { return MyIdentity; }
}
public bool IsInRole(string role)
{
return Roles.IsUserInRole(role);
}
}
What to do? I am following this tutorial
http://www.dotnetawesome.com/2015/06/part4-how-to-implement-custom-forms-authentication-in-aspnet-mvc.html
Your class MyPrincipal misses to declare the implemented interface IPricipal:
public class MyPrincipal : IPrincipal
{ //...
There is no duck typing in C#.
Related
I have a DtoClass which has properties of a specific class, I don't want to have a CustomModelBinder for the DtoClass but for the class of its properties; I am using asp.net core 3.1.
My ModelBinder Class is:
public class SessionIdModelBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
Guard.Against.Null(bindingContext, nameof(bindingContext));
var modelName = bindingContext.ModelName;
var valueProviderResult = bindingContext.ValueProvider.GetValue(modelName);
if (valueProviderResult == ValueProviderResult.None)
return Task.CompletedTask;
var sessionId = SessionId.Parse(valueProviderResult.FirstValue);
if (sessionId.IsFailure)
{
bindingContext.ModelState.AddModelError(modelName, sessionId.Errors.First().Message);
bindingContext.Result = ModelBindingResult.Failed();
return Task.CompletedTask;
}
bindingContext.Result = ModelBindingResult.Success(sessionId.Data);
return Task.CompletedTask;
}
}
The Dto class is like:
public class MergeSessionsDto
{
[ModelBinder(BinderType = typeof(SessionIdModelBinder), Name = nameof(OldSession))]
public SessionId OldSession { get; set; }
[ModelBinder(BinderType = typeof(SessionIdModelBinder), Name = nameof(NewSession))]
// [BindProperty(BinderType = typeof(SessionIdModelBinder), Name = nameof(NewSession))]
public SessionId NewSession { get; set; }
}
The action in my controller is:
public async Task<IActionResult> MergeSessions([FromBody] MergeSessionsDto dto)
{
var result = DoTheMerge(dto.OldSession, dto.NewSession);
return result;
}
in the startup class I also registered the ModelBinderProvider :
services.AddControllers(options=> options.ModelBinderProviders.Insert(0, new MyCustomModelBinderProvider()))
which is like:
public sealed class MyCustomModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
Guard.Against.Null(context, nameof(context));
if (context.Metadata.ModelType == typeof(SessionId))
return new BinderTypeModelBinder(typeof(SessionIdModelBinder));
return null;
}
}
No matter which approach I am using, either [ModelBinder], [BindProperty] attributes, or global registration, SessionModelBinder is not called, and I am getting this error:
Exception: Invalid error serialization: 'The dto field is required.'
I am beginner with SignalR and SQLDepedency. I am trying to implement SignalR using EF Code First Approach. I am getting the error The sqlparameter is already contained by another sqlparametercollection if I am using where condition in LINQ class.
public class MessageHub : Hub
{
internal NotifierEntity NotifierEntity { get; private set; }
private MyDbContext db = new MyDbContext();
public void DispatchToClient()
{
Clients.All.broadcastMessage("Refresh");
}
public void Initialize(String userName)
{
if (!string.IsNullOrEmpty(userName))
{
NotifierEntity = db.GetNotifierEntity<Messages>(db.Messages.Where(x=>x.ApplicationUser.UserName== userName && !x.Status));
if (NotifierEntity == null)
return;
Action<String> dispatcher = (t) => { DispatchToClient(); };
PushSqlDependency.Instance(NotifierEntity, dispatcher);
}
}
}
The NotifierEntity Class
public class NotifierEntity
{
ICollection<SqlParameter> sqlParameters = new List<SqlParameter>();
public String SqlQuery { get; set; }
public String SqlConnectionString { get; set; }
public ICollection<SqlParameter> SqlParameters
{
get
{
return sqlParameters;
}
set
{
sqlParameters = value;
}
}
public static NotifierEntity FromJson(String value)
{
if (String.IsNullOrEmpty(value))
throw new ArgumentNullException("NotifierEntity Value can not be null!");
return new JavaScriptSerializer().Deserialize<NotifierEntity>(value);
}
}
public static class NotifierEntityExtentions
{
public static String ToJson(this NotifierEntity entity)
{
if (entity == null)
throw new ArgumentNullException("NotifierEntity can not be null!");
return new JavaScriptSerializer().Serialize(entity);
}
}
public class PushSqlDependency
{
static PushSqlDependency instance = null;
readonly SqlDependencyRegister sqlDependencyNotifier;
readonly Action<String> dispatcher;
public static PushSqlDependency Instance(NotifierEntity notifierEntity, Action<String> dispatcher)
{
if (instance == null)
instance = new PushSqlDependency(notifierEntity, dispatcher);
return instance;
}
private PushSqlDependency(NotifierEntity notifierEntity, Action<String> dispatcher)
{
this.dispatcher = dispatcher;
sqlDependencyNotifier = new SqlDependencyRegister(notifierEntity);
sqlDependencyNotifier.SqlNotification += OnSqlNotification;
}
internal void OnSqlNotification(object sender, SqlNotificationEventArgs e)
{
dispatcher("Refresh123");
}
}
public class SqlDependencyRegister
{
public event SqlNotificationEventHandler SqlNotification;
readonly NotifierEntity notificationEntity;
internal SqlDependencyRegister(NotifierEntity notificationEntity)
{
this.notificationEntity = notificationEntity;
RegisterForNotifications();
}
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security",
"CA2100:Review SQL queries for security vulnerabilities")]
void RegisterForNotifications()
{
using (var sqlConnection = new SqlConnection(notificationEntity.SqlConnectionString))
using (var sqlCommand = new SqlCommand(notificationEntity.SqlQuery, sqlConnection))
{
foreach (var sqlParameter in notificationEntity.SqlParameters)
{
sqlCommand.Parameters.Add(sqlParameter);
}
sqlCommand.Notification = null;
var sqlDependency = new SqlDependency(sqlCommand);
sqlDependency.OnChange += OnSqlDependencyChange;
if (sqlConnection.State == ConnectionState.Closed)
sqlConnection.Open();
sqlCommand.ExecuteNonQuery();
}
}
void OnSqlDependencyChange(object sender, SqlNotificationEventArgs e)
{
if (SqlNotification != null)
SqlNotification(sender, e);
RegisterForNotifications();
}
}
public delegate void SqlNotificationEventHandler(object sender, SqlNotificationEventArgs e);
If I am using the same query without any parameters, the code is working perfectly. I can see the database changes instantly in frontend. The issue is coming after added a parameter in Where clause.
I got this idea from below link
https://www.codeproject.com/Tips/1075852/ASP-NET-MVC-SignalR-SqlDependency-and-EntityFramew
Sourcecode link
we.tl/njwwLl8g36
Is it possible to use an IOC framework like Castle Windsor to inject into the Startup method. I mean something like this:
public class Startup()
{
IMyObject MyObject = new MyObject();
public Startup(MyObject myObject)
{
MyObject = myObject();
}
}
I am trying to drop and create a database on startup using NHibernate. Alternatively is there a "better" place to drop and create the database using NHibernate?
I do something like this for integration tests using specflow.
I have a NHibernateInitializer class that I inherit in all my projects that looks like this
public abstract class NHibernateInitializer : IDomainMapper
{
protected Configuration Configure;
private ISessionFactory _sessionFactory;
private readonly ModelMapper _mapper = new ModelMapper();
private Assembly _mappingAssembly;
private readonly String _mappingAssemblyName;
private readonly String _connectionString;
protected NHibernateInitializer(String connectionString, String mappingAssemblyName)
{
if (String.IsNullOrWhiteSpace(connectionString))
throw new ArgumentNullException("connectionString", "connectionString is empty.");
if (String.IsNullOrWhiteSpace(mappingAssemblyName))
throw new ArgumentNullException("mappingAssemblyName", "mappingAssemblyName is empty.");
_mappingAssemblyName = mappingAssemblyName;
_connectionString = connectionString;
}
public ISessionFactory SessionFactory
{
get
{
return _sessionFactory ?? (_sessionFactory = Configure.BuildSessionFactory());
}
}
private Assembly MappingAssembly
{
get
{
return _mappingAssembly ?? (_mappingAssembly = Assembly.Load(_mappingAssemblyName));
}
}
public void Initialize()
{
Configure = new Configuration();
Configure.EventListeners.PreInsertEventListeners = new IPreInsertEventListener[] { new EventListener() };
Configure.EventListeners.PreUpdateEventListeners = new IPreUpdateEventListener[] { new EventListener() };
Configure.SessionFactoryName(System.Configuration.ConfigurationManager.AppSettings["SessionFactoryName"]);
Configure.DataBaseIntegration(db =>
{
db.Dialect<MsSql2008Dialect>();
db.Driver<SqlClientDriver>();
db.KeywordsAutoImport = Hbm2DDLKeyWords.AutoQuote;
db.IsolationLevel = IsolationLevel.ReadCommitted;
db.ConnectionString = _connectionString;
db.BatchSize = 20;
db.Timeout = 10;
db.HqlToSqlSubstitutions = "true 1, false 0, yes 'Y', no 'N'";
});
Configure.SessionFactory().GenerateStatistics();
Map();
}
public virtual void InitializeAudit()
{
var enversConf = new Envers.Configuration.Fluent.FluentConfiguration();
enversConf.Audit(GetDomainEntities());
Configure.IntegrateWithEnvers(enversConf);
}
public void CreateSchema()
{
new SchemaExport(Configure).Create(false, true);
}
public void DropSchema()
{
new SchemaExport(Configure).Drop(false, true);
}
private void Map()
{
_mapper.AddMappings(MappingAssembly.GetExportedTypes());
Configure.AddDeserializedMapping(_mapper.CompileMappingForAllExplicitlyAddedEntities(), "MyWholeDomain");
}
public HbmMapping HbmMapping
{
get { return _mapper.CompileMappingFor(MappingAssembly.GetExportedTypes()); }
}
public IList<HbmMapping> HbmMappings
{
get { return _mapper.CompileMappingForEach(MappingAssembly.GetExportedTypes()).ToList(); }
}
/// <summary>
/// Gets the domain entities.
/// </summary>
/// <returns></returns>
/// <remarks>by default anything that derives from EntityBase and isn't abstract or generic</remarks>
protected virtual IEnumerable<System.Type> GetDomainEntities()
{
List<System.Type> domainEntities = (from t in MappingAssembly.GetExportedTypes()
where typeof(EntityBase<Guid>).IsAssignableFrom(t)
&& (!t.IsGenericType || !t.IsAbstract)
select t
).ToList();
return domainEntities;
}
}
Then in my global.asax Application_Begin event handler I configure it
public class MvcApplication : HttpApplication
{
private const String Sessionkey = "current.session";
private static IWindsorContainer Container { get; set; }
private static ISessionFactory SessionFactory { get; set; }
public static ISession CurrentSession
{
get { return (ISession) HttpContext.Current.Items[Sessionkey]; }
private set { HttpContext.Current.Items[Sessionkey] = value; }
}
protected void Application_Start()
{
Version version = Assembly.GetExecutingAssembly().GetName().Version;
Application["Version"] = String.Format("{0}.{1}", version.Major, version.Minor);
Application["Name"] = ConfigurationManager.AppSettings["ApplicationName"];
//create empty container
//scan this assembly for any installers to register services/components with Windsor
Container = new WindsorContainer().Install(FromAssembly.This());
//API controllers use the dependency resolver and need to be initialized differently than the mvc controllers
GlobalConfiguration.Configuration.DependencyResolver = new WindsorDependencyResolver(Container.Kernel);
//tell ASP.NET to get its controllers from Castle
ControllerBuilder.Current.SetControllerFactory(new WindsorControllerFactory(Container.Kernel));
//initialize NHibernate
ConnectionStringSettings connectionString = ConfigurationManager.ConnectionStrings[Environment.MachineName];
if (connectionString == null)
throw new ConfigurationErrorsException(String.Format("Connection string {0} is empty.",
Environment.MachineName));
if (String.IsNullOrWhiteSpace(connectionString.ConnectionString))
throw new ConfigurationErrorsException(String.Format("Connection string {0} is empty.",
Environment.MachineName));
string mappingAssemblyName = ConfigurationManager.AppSettings["NHibernate.Mapping.Assembly"];
if (String.IsNullOrWhiteSpace(mappingAssemblyName))
throw new ConfigurationErrorsException(
"NHibernate.Mapping.Assembly key not set in application config file.");
var nh = new NHInit(connectionString.ConnectionString, mappingAssemblyName);
nh.Initialize();
nh.InitializeAudit();
SessionFactory = nh.SessionFactory;
AutoMapConfig.RegisterMaps();
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
ModelBinderConfig.RegisterModelBinders(ModelBinders.Binders);
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
}
protected void Application_OnEnd()
{
//dispose Castle container and all the stuff it contains
Container.Dispose();
}
protected void Application_BeginRequest() { CurrentSession = SessionFactory.OpenSession(); }
protected void Application_EndRequest()
{
if (CurrentSession != null)
CurrentSession.Dispose();
}
}
}
I've create a base class for my Views like this:
public abstract class BaseViewPage : WebViewPage
{
public virtual new CustomPrincipal User
{
get
{
if (base.User == null) return null;
return base.User as CustomPrincipal;
}
}
}
public abstract class BaseViewPage<TModel> : WebViewPage<TModel>
{
public virtual new CustomPrincipal User
{
get
{
if (base.User == null) return null;
return base.User as CustomPrincipal;
}
}
public override void Execute()
{
throw new NotImplementedException();
}
}
and in my model I have:
public class SecureAreaModel : BaseViewPage
{
public int MyUserID
{
get { return User.ID; }
private set { }
}
public SecureAreaModel(ControllerContext controllerContext)
{
}
public override void Execute()
{
throw new NotImplementedException();
}
}
I want to use the propertiy MyUserID but I receive this error:
Error
At this point the user is autenticated
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
JavaScriptSerializer serializer = new JavaScriptSerializer();
CustomPrincipalSerializeModel serializeModel = serializer.Deserialize<CustomPrincipalSerializeModel>(authTicket.UserData);
CustomPrincipal customer = new CustomPrincipal(serializeModel.Email);
customer.ID = serializeModel.ID;
customer.Email = serializeModel.Email;
customer.FirstName = serializeModel.FirstName;
customer.LastName = serializeModel.LastName;
customer.Roles = serializeModel.Roles;
HttpContext.Current.User = customer;
}
else
{
HttpContext.Current.User = new CustomPrincipal(string.Empty);
}
}
Any help will be appreciated! Thx
I am trying to get some custom field values from my authentication ticket by running the following code in my controller -
[HttpPost]
public ActionResult Add(AddCustomerModel customer)
{
customer.DateCreated = DateTime.Now;
customer.CreatedBy = ((CustomPrincipal)(HttpContext.User)).Id;
customer.LastUpdated = DateTime.Now;
customer.LastUpdateBy = ((CustomPrincipal)(HttpContext.User)).Id;
if (ModelState.IsValid)
{
_customerService.AddCustomer(customer);
return RedirectToAction("Index");
}
return View(customer);
}
When I try and set the CreatedBy field for the new customer, I get the following error -
Unable to cast object of type 'System.Security.Principal.GenericPrincipal' to type 'GMS.Core.Models.CustomPrincipal'.
My userData field within the FormsAuthenticationTicket is set with a JSON string which contains two fields - Id and FullName.
Here is my login method on the controller -
[HttpPost]
[AllowAnonymous]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (Membership.ValidateUser(model.EmailAddress, model.Password))
{
LoginModel user = _userService.GetUserByEmail(model.EmailAddress);
CustomPrincipalSerializeModel serializeModel = new CustomPrincipalSerializeModel();
serializeModel.Id = user.ID;
serializeModel.FullName = user.EmailAddress;
//serializeModel.MergedRights = user.MergedRights;
JavaScriptSerializer serializer = new JavaScriptSerializer();
string userData = serializer.Serialize(serializeModel);
FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(
1,
user.EmailAddress,
DateTime.Now,
DateTime.Now.AddHours(12),
false,
userData);
string encTicket = FormsAuthentication.Encrypt(authTicket);
HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
Response.Cookies.Add(faCookie);
return RedirectToAction("Index", "Dashboard");
}
return RedirectToAction("Index");
}
Any ideas where I am going wrong?
To retrieve the userdata from cookies you can use the following code
FormsIdentity formsIdentity = HttpContext.Current.User.Identity as FormsIdentity;
FormsAuthenticationTicket ticket = formsIdentity.Ticket;
string userData = ticket.UserData;
You need to create and AuthenticationFilter to change your GenericPrincipal to your CustomPrincipal
public class FormAuthenticationFilter : ActionFilterAttribute, IAuthenticationFilter
{
private readonly IResolver<HttpContextWrapper> httpContextWrapper;
private readonly IResolver<ISecurityProvider> securityProviderResolver;
public FormAuthenticationFilter(IResolver<HttpContextWrapper> httpContextWrapper, IResolver<ISecurityProvider> securityProviderResolver)
{
this.httpContextWrapper = httpContextWrapper;
this.securityProviderResolver = securityProviderResolver;
}
public void OnAuthentication(AuthenticationContext filterContext)
{
if (filterContext.Principal != null && !filterContext.IsChildAction)
{
if (filterContext.Principal.Identity.IsAuthenticated &&
filterContext.Principal.Identity.AuthenticationType.Equals("Forms", StringComparison.InvariantCultureIgnoreCase))
{
// Replace form authenticate identity
var formIdentity = filterContext.Principal.Identity as FormsIdentity;
if (formIdentity != null)
{
var securityProvider = this.securityProviderResolver.Resolve();
var principal = securityProvider.GetPrincipal(filterContext.Principal.Identity.Name, formIdentity.Ticket.UserData);
if (principal != null)
{
filterContext.Principal = principal;
this.httpContextWrapper.Resolve().User = principal;
}
}
}
}
}
public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
{
}
}
And then register that filter to GlobalFilter
GlobalFilters.Filters.Add(new FormAuthenticationFilter());
The HttpContextWrapper in my code is just the wrapper of HttpContext.Current. You can change it to whatever you need. And the IAuthenticationFilter only exist in MVC 5.