How do I make the email field not required to signin but required for signup? - asp.net-core-webapi

I have the User class with the Id, Username, Password and Email properties.
In Swagger UI, when trying to signin, if success, I get a JWT token in return as well with a bool: that's the case, when I got the Email commented out from user class,
Since both Task<AutheticatedUser> SignIn(User user); and
Task<AutheticatedUser> SignUp(User user);
takes the user as input.
Is it a way to make the email not being required when I sign in, to still be able to User user as input?
It works when I comment out the email from the User class, but I want the email to be required when I sign up.

You may use .NET 6/.NET 7. From .NET 6 the non-nullable property must be required, otherwise the ModelState will be invalid.
To achieve your requirement, the first way is you can remove <Nullable>enable</Nullable> from your project file(double-click the project name or right-click the project to choose Edit Project File).
The second way, you can add ? to allow nullable:
public class User
{
public int Id { get; set; }
//other properties....
public string? Email{ get; set; } //change here...
}

Related

Can I Bind to Something Global in Xamarin Forms?

I would like to display the current user in a custom view, which most of my ContentPage's contain. I currently store the current user in the App instance as a property, after login. Attempting to just update the Label in the constructor is too early in the lifecycle.
Is there a way with Xamarin Forms to bind to this object or otherwise get the current user to update a Label in my custom view? I am using Xamarin.Forms 3.5 with the standard MVVM.
There are a multiple approaches you could take, but the short answer is that you need something sitting between the global (static) variable and the views in order to make things work smoothly. The property on your view model must be a non-static property.
However it can have a custom implementation so that the getter retrieves the value from some global location, and in your case, you may not need a setter. The only other piece you need is to tell the view model to fire a PropertyChanged event when the user information is available, then you can use standard Binding from the Label to the view model.
Assuming you have some CurrentUser static class that has members like:
public static class CurrentUser
{
public event Action OnLogin; // login code needs to fire this on login
public string Username { get; set; }
// etc.
}
Then view models would hook up to that by doing something like:
class UserViewModel : INotifyPropertyChanged
{
public UserViewModel()
{
CurrentUser.OnLogin += CurrentUser_Login;
}
private void CurrentUser_Login()
{
PropertyChanged?.Invoke(nameof(Username));
}
public string Username {
get {
return CurrentUser.Username;
}
}
// etc.
}
Then the view would use <Label Text="{Binding Username}" . . .> and then when OnLogin is fired, all views would be automatically updated with the new username.

Implement multiple roles on the same data in MVC (ASP)

Example:
We have two user types.
SupplierUser
FactoryUser
They both interface with basically the same data, but in general FactoryUsers can edit much more of this information than the SupplierUser.
Using ASP.NET 4.5, I am implementing all of this using MVC.
Some summarized use cases: (Assume logged in)
FactoryUser:
Editable messages page, which shows suppliers their latest announcements.
Order confirmation page, and order view page.
Supplier edit page (for updating addresses etc of multiple suppliers)
SupplierUser:
- Can see messages from specific Factory.
- Can create orders, send and view.
- Can edit their own information
As you can see this is just a lot of editing of information with various permission. My question is, Where should I be starting the separations?
With regards to:
Models - I think this one stays as one with the database
ViewModels - Do I write different views for each role? If so, 2 files/classes?
Controllers - Same, do I write different functions?? Classes? If so then what is the point is having [Authorize role], just to protect from unauthorized access & not intended to split?
Views - Do I try to use the same views for most parts and just somehow include logic about if they have "edit" buttons or not?
Partial Views - Can they be used for the "edit" buttons that may or may not be on the view?
View Layouts - ?
Filters - I can do some fancy logic and put everything in entirely 2 different folders (the whole MVC) and then split it at route/authorize level
Routing - ?
At each one of the above, I can see a possibility to split the logic depending on the type of user. But of course, I want to do this in the simplest and most sane way possible.
Is there some document somewhere which specifies how this should be done, or otherwise any wise people out there who have done this before and encountered all the issues?
Thanks
(first question!)
One way to do this is to create features. e.g View Orders, Create Order, Update Order, Delete Order
These features will then be assigned to a Role - and the Role can be assigned to a User
So the DB will look something like this:
Now when the user logs in, you read all the features assigned to the user and save them in the session (Create a SessionHandler Class).
// Login Function - You can call from Controller
public UserDTO Login(string username, string password)
{
var user = dbContext.Users.FirstOrDefault(s => s.Username == username && s.Password == password);
if(user == null) return null; // login failed
var model = new UserDTO()
{
UserId = user.UserId,
Features = user.Role.Features.Select(s => s.FeatureName).ToList()
};
return model;
}
Sample of UserDTO class
public class UserDTO
{
public int UserId {get;set;}
public List<string> Features {get;set;}
}
Sample of SessionHandler
public class SessionHandler
{
private const string SessionKey = "UserSession";
public static UserDTO UserSession
{
get
{
return HttpContext.Current.Session[SessionKey] != null
? (UserDTO)HttpContext.Current.Session[SessionKey]
: null;
}
set { HttpContext.Current.Session[SessionKey] = value; }
}
}
So in your controller call the Login Function and assign to UserSession in SessionHandler
[HttpPost]
public ActionResult Login(LoginModel model)
{
var user = Login(model.username, model.password);
if(user == null) return View(model);
SessionHandler.UserSession = user;
// TODO: redirect to Home Page - after login
return RedirectToAction("Index", "Home");
}
Then what you can do in your views is check if the user can perform a certain action, so e.g. if you are on the View Orders page - you can hide the Create Order Button if user does NOT have permission:
#model WhateverDTO
// Check if user has Create Order Feature in Role
#if (SessionHandler.UserSession.Features.Contains("Create Order"))
{
// Yes, User has permission - then Render the Button
<button> Create Order </button>
}
Also you can add checks in the Controller(Server side) - Which will provide extra security to your application, using the Authorise Attribute:
public class CustomAuthorizeAttribute : AuthorizeAttribute
{
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
throw new ArgumentNullException("httpContext");
if (httpContext.Session == null)
return false;
// Checking Authenticaiton
var userSettings = SessionHandler.UserSession;
if (userSettings == null)
return true;
//Checking Authorization
if (Roles.Length == 0)
return true;
var actionFeatures = Roles.Split(',');
if (!actionFeatures.Any(s => userSettings.Features.Contains(s)))
throw new UnauthorizedAccessException("You do not have permission to perform this action.");
return true;
}
}
and then decorate your Actions,
[CustomAuthorize(Roles = "Create Order")]
// Pass feature name for Roles - if user doesn't have permission to Create Order - the "You do not have permission to perform this action." exception will get thrown
public ActionResult CreateOrder()
{
return View(new CreateOrderDTO());
}
[HttpPost]
[CustomAuthorize(Roles = "Create Order")]
// Pass feature name for Roles - if user doesn't have permission to Create Order - the "You do not have permission to perform this action." exception will get thrown
public ActionResult CreateOrder(CreateOrderDTO model)
{
return View(model);
}
The good thing about the above method - is that you can add as many user Roles as you need - without changing the Code.
Models - I think this one stays as one with the database
Models are same - same DB same models
ViewModels - Do I write different views for each role? If so, 2 files/classes?
No, don't complicate things - use same ViewModel / DTO
Controllers - Same, do I write different functions?? Classes? If so then what is the point is having [Authorize role], just to protect from unauthorized access & not intended to split?
No need for separate actions/views or controllers
Views - Do I try to use the same views for most parts and just somehow include logic about if they have "edit" buttons or not?
Yes, use same views - Hide/Show actions based on User Role/ Feature
Partial Views - Can they be used for the "edit" buttons that may or may not be on the view?
No need for Partial Views for buttons
View Layouts - ?
Filters - I can do some fancy logic and put everything in entirely 2 different folders (the whole MVC) and then split it at route/authorize level
Routing - ?
No

Using a Custom Authentication/Authorization attribute for an action

We have a website that uses ASP Identity and works great with the [Authorize] attribute sprinkled on all the appropriate classes.
What i'm looking to do is create a separate authentication system for a specific set of actions. It's a page that isn't exactly anonymous, but can be viewed if a PIN is entered correctly.
I started looking into Authentication/Authorization attributes and got to a point where it redirects to my PIN entry page if not authenticated.
So I guess what i'm asking is how do I authenticate a virtual user (aka: not in the database) to be able to access those pages after entering in the correct PIN?
You could create your own version of the AuthorizeAttribute by inheriting from it and overriding the AuthorizeCore method.
public class PinAuthorizeAttribute : AuthorizeAttribute
{
private readonly string _password;
public PinAuthorizeAttribute(string password)
{
_password = password;
}
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
//Check if user has entered the correct PIN, perhaps
//by keeping the PIN in the Session
if(Session["PIN") == _password)
return true;
return false;
}
}
Now add it to your action method:
[PinAuthorize("1234")]
public ActionResult ProtectedIndex()
{
//snip
}

Sharing the same model between Get and Post conroller methods

I develop a Change Password form which controller has simply two methods:
public ActionResult ChangePassword(string email, Guid code)
{
var model = new PasswordChangeModel { Email = email, ConfirmationCode = code };
return View(model);
}
[HttpPost]
public ActionResult ChangePassword(PasswordChangeModel model)
{
// use model class
}
Here GET method is invoked by direct link from confirmation e-mail. The POST method in invoked when submit button is clicked. The problem is that the model instance isn't shared between these two methods - the POST method is always has empy Guid ConfirmationCode property.
How can I force ASP.NET to use the same instance of model class? Or more generally, what is the best way to do the following: user clicks the link in his confirmation e-mail, then it is redirected to Change Password form, and after he clicks submit button, it is fired some action (save new password to DB, etc.)
Please make sure you have this property - "Guid code" in your PasswordChangeModel. And on your view you can have a hidden field to keep the Guid string like this below-
#Html.HiddenFor(x=>x.Code)
After you will post the model to the controller it will have the Guid string in the "Code" property of the model.

Storing a value globally across all pages

This is an ASP.NET Forms project. When user enters his/her user name and password (in the Login page) I want to save the user name such that it can be retrieved in the code of any page of the project. I know that I can do it via a session variable.
But is it possible to create a Static Public class with Get Set and store the value there and retrieve it using this class?
If you are using master page create a hidden field in that store that information in that hidden value so you can access in any page where you are using that master page.
Static classes are shared across instances/sessions in your app, which means you could end up with something akin to race conditions; for instance, a request from User_A could read values that were set in your static class by User_B. (see this SO answer)
Shooting from the hip, it might be easier to write a wrapper/abstraction class for your users' info that makes accessing their details easier. Something like:
public class UserDetails{
public string Name;
public string Age;
public string Gender;
public UserDetails(HttpContext context){
this.Name = context.User.Identity.Name;
this.Age = ...;
this.Gender = ...;
// Alternatively, you could perform your own data access to
// get/set these details. It depends on how you're storing your
// users' info.
}
}
Then in your code behind...
UserDetails userDetails = new UserDetails(context.Current);
Response.Write(userDetails.Name); // user's name
Response.Write(userDetails.Age); // user's age
...

Categories

Resources