Symfony2: User entity class which implements UserInterface: Use email instead of username - authentication

I am trying to work with the symfony2 login. I have my entity class connected to the database. In my table, I have only the user's email, which is the username. Should I use the getUsername() method knowing that I don't have a real username.
When I try to delete this method, I am geting a fatal error message :
Fatal error: Class MDPI\BackendBundle\Entity\Users contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Symfony\Component\Security\Core\User\UserInterface::getUsername) in /home/milos/workspace/mdpi-login2/src/MDPI/BackendBundle/Entity/Users.php on line 768
Should I use
getUsername()
{
return this->email;
}
Or is there a nicer way of doing this ???
Thank you.

Using the native Symfony SecurityBundle, you just have to specify the entity field you use as login string, in app/config/security.yml :
security:
encoders:
MDPI\BackendBundle\Entity\User: plaintext
providers:
entity:
entity: { class: MDPI\BackendBundle\Entity\User, property: email }
firewalls:
...

Related

nestjs mongoose schema model object and an object for service layer in OOP perspective

I am developing a backend with nestjs + mongoose.
As nestjs document suggests, I wrote mongoose schema class following
(this schema has GraphQL decorators , #Prop is mongoose decorator )
#Schema({
timestamps: true,
})
#ObjectType()
#InputType('UserInput')
export class User extends BaseModel {
#Prop()
#Field()
email: string;
#Prop()
#Field({ nullable: true })
username?: string;
...
then in user service layer
async loginUser(loginDto: LoginDto) {
let user: User | undefined = await this.userRepository.findUser(loginDto);
if (!user) {
user = await this.userRepository.createUser(loginDto);
}
I use User object type that user repository returns. this must be same with User Schema that I defined for mongoose with Class.
I think the User Class and user instance ( let user: User | undefined ) returned from userRepositry.findUser violate OOP since the instance can access to all the properties since those properties are public due to use of decorators.
I think I have seen an article that nestjs can't resolve decorators used with private properties inside Class and Nestjs document also doesn't set schema class properties to private . so I didn't set properties in my schema classes to private either
what I doubt about this code is wether I need to create User object which is irrelevant to Schema Class but has same properties in private and instantiate it in service layer for business logic in OOP perspective or not. I think DTO and DAO might be for this use case ? if so , Should I strictly create DTO and DAO in this case ? or ..if there is another way to keep OOP with nestjs and decorators

How to validate email inside entity?

I got this user entity:
class User {
id: string;
name: string;
email: string;
password: string;
....
}
My business rules says that:
One user per Email
What's the purpose of this entity, It cannot have any dependencies. How can i check if email is unique or not?
The thing i don't understand is, who calls entity and pushes data inside it for validation and who can access it?(usecase or repository).
Actually, when you need to satisfy this rule? Only when you are creating a new user. It does not make sense to check it when you've got a user from a database. Or when you are doing something with the user, like changing phonen umber, blocking and so on.
It means this behavior does not belong to User class. I would suggest to create some kind of UserFactory that creates a new user and inject there a policy (or policies).
public UserFactory(EmailCheckingPolicy: emailpolicy, AnotherPolicy: somethingElse);
public User create(UserData: userData) {
if (emailPolicy.isPass(userData.email)) ...
return User(userData.email, userData.name, ...)
}
}
You can inject UserFactory to a UseCase.

How to use singleton with realm object?

I have an User model:
class User: Object, Mappable {
dynamic var account: String?
dynamic var balabala
static var current: User {
return realm.objects(User.self) ?? User()
}
}
But it throws an error: Instance member 'realm' cannot be used on type 'User'
How to use singleton with realm object?
Any help is appreciated
Your User class doesn't define an instance variable called realm, so in your current property the Swift compiler doesn't know what realm refers to.
If you just want to use the default Realm, you need to initialize a new instance of it:
try! Realm().objects(User.self)
Otherwise, as Kam referred to in the comments, set up a separate class for managing your singleton Realm and get the Realm from that class instead.

how to hide field during serialization (but not deserialization)

In our project (springMVC) Rest API project I wish to only use ONE model for both request and response (to avoid having to add tons of code to copy field from object to object)
I'd like to use Swagger to handle all the doc, but I'm running into a little problem. For example let say I have a model User
public class User {
private Long id;
private String username;
private String password;
}
And a simple controller
public void createUser(#RequestBody User user)...
public User getUser(Long id) ..
Now I would like swagger to hide the property password on deserialization but not serialization (so having it display for the Input but the output)
and the opposite for the Id field.
I have tried using #JsonIgnore coupled with #JsonProperty but on the swagager-ui it either displays everything or hides everything. I cannot manage to it work.
Could someone indicate me what is the best way of archiving my goal ? Is it possible to use a single model for request and response while using swagger? In case it is not possible to use #JsonIgnore, is there a way to archive this differently ?
Swagger doesn't want you to have different input/output models with the same name. You should simply create an interface and attach that to the input, and for the output extend that interface or add an implementation with the additional field. For example, please see here for modeling tips:
https://swaggerhub.com/api/swagger-tutorials/modeling-samples/1.0.0
Your exact use case is one of them. The solution posted in the above link is here:
definitions:
User:
description: this is a user that would be passed into the system
properties:
username:
type: string
UserResponse:
allOf:
- $ref: '#/definitions/User'
- type: object
required:
- id
properties:
id:
type: string
format: uuid
readOnly: true
where User is the input object, and UserResponse is the output object, with the additional id field.
Add #JsonIgnore with getter of the field and #JsonProperty with the setter or with the field . As Due to use of immutable code or final fields sometime setter doesn't work.
example :
public class Student {
private Float name;
private String rollnum;
private String section;
#JsonProperty
private Boolean passOrFailed;
#JsonIgnore
public Boolean getpassOrFailed {
return active;
}
}
Remember to use both else else it will lead to removing element in deserialization

CWebUser and CUserIdentity

I'm building an authentication module for my application and I don't quite understand the relation between CWebUser and CUserIdentity.
To set the user id to Yii::app()->user->id I have to do that in my UserIdentity class and create a method:
public function getId() {
return $this->_id;
}
But to set isAdmin to Yii::app()->user->isAdmin I have to create a method in my WebUser class:
function getIsAdmin() {
$user = $this->loadUser(Yii::app()->user->id);
return intval($user->user_level_id) == AccountModule::USER_LEVEL_ADMIN;
}
Why can't I just create the methods the UserIdentity class? What is the division of labour here?
The UserIdentity (UI) class is like an ID card, where as the WebUser class is the actual person plus everything you know about them.
The UI class gives you authentication via database, webservices, textfile, whatever. It lets you know what the key attributes are and allows you to manipulate them. The user however can give you more information about what they're allowed to do, there names, granular permissions and such.
OK, end metaphor
The UI class holds the key information, so when asking for the users ID it will refer to the User Identity class to get the Identifier for the user.
Anything that isn't related to identifying or authenticating a user is in the WebUser class
Clear it up at all?
Your example
You gave the getId function as an example, but that can be created on WebUser to override the default, which is to pull from the state.
So not sure what you mean here.
I like how the accepted answer used real life examples to make it easier to understand. However, I also like how Chris explained it here with example.
User information is stored in an instance of the CWebUser class and
this is created on application initialisation (ie: when the User first
connects with the website), irrespective of whether the user is logged
in or not. By default, the user is set to “ Guest”. Authentication is
managed by a class called CUserIdentity and this class checks that the
user is known and a valid user. How this validation occurs will depend
on your application, perhaps against a database, or login with
facebook, or against an ldap server etc...
And what is the benefit of using all those classes? I can do everything just by User model. If I set scenario "login", password will be checked during validation. If validation is OK, I can set to session my own variable like this:
$model = new User("login");
$model->attributes = $_POST["User"];
if ($model->validate())
{
Yii::app()->session["currentUser"] = $model;
}
else
{
// .. show error
unset(Yii::app()->session["currentUser"]);
}
In User model I have then static methods to check this variable
public static function isGuest()
{
return isset(Yii::app()->session["currentUser"]);
}
public static function getCurrent()
{
return Yii::app()->session["currentUser"];
}
And I can call it very shortly:
User::isGuest();
$model = User::getCurrent();
// instead of writing this:
Yii::app()->user->isGuest;
So why should I use so complicated hierarchy of classes that is suggested by Yii? I never understood it.