wixLocation.to() - how to transfer to a dynamic page by using wixLoation.to() - velo

I have a login page and I want to check the username and password in a database called ProfileInfo ( there are only two columns in this database- username and password), and if it is matched, the page will shift to a dynamic Profile page.
I have two questions
How to query from the database and check the username and password?
How to use wixLocation.to() to shift to the dynamic page?

First off, this is not a very secure way to deal with user logins. You might want to consider the built-in Wix members functionality instead.
That being said, you definitely want to make sure your ProfileInfo collection is set with very restrictive permissions. Also, you'll want to query and check the passwords in the backend.
So, in some backend web module (here I will assume it is authenticate.jsw), you should write a function similar to this:
import wixData from 'wix-data';
export function authenticate(username, password) {
return wixData.query("ProfileInfo")
.eq("username", username)
.find({"supressAuth": true})
.then( (results) => {
if(results.items.length > 0) {
return password === results.items[0].password;
}
} );
}
Then, from your page code you can call it like this. It's impossible to say exactly what the wixLocation.to() should contain without knowing how you set up your dynamic page. Here I assume you set it up with the prefix Profile and it is based on the username.
import {authenticate} from 'backend/authenticate';
import wixLocation from 'wix-location';
export function button_click() {
authenticate($w("#username").text, $w("#password").text)
.then( (authenticated) => {
if(authenticated) {
wixLocation.to(`/Profile/${$w("#username")}`)
}
} );
}

Related

KeystoneJS: How to set a field to receive randomly generated value?

I'm creating a model that I will use to authenticate users for API access, and I have a secret field where I want to store a Base64 encoded uuid/v4 generated value.
I went through the different field types and options, but still not seeing how I could achieve this.
Is there a way to hook in model instance creation, and set the value of my secret field ?
Yes, you can use the pre hooks.
In your situation, the basics would be:
AuthenticationModel.schema.pre("save", function(next) {
const secretValue = generateSecretValue();
this.secret = secretValue;
next();
});
That would go before your final AuthenticationModel.register(); in your model.js file.
This is how I set it up, also with the pre-save hook. My problem before was that I was getting the same random number again until I restarted the server.
Store.schema.pre('save', function (next) {
if (!this.updateId && this.isNew) {
// generates a random ID when the item is created
this.updateId = Math.random().toString(36).slice(-8);
}
next();
});
Using this.isNew was also useful in my case.

How could I save users' login state in a nativescript application

Recently I'm programing an app with nativescript, and now I have a problem that I don't know how to save the user's login state. For example, if user login at the first time, he will not need to login in the future. So how could I achieve this?
I do use application-settings on my apps, the same module that the other answers suggest.
You can get code samples for Angular and vanilla JS.
Also, in one of my apps, I've created a config.ts class that handles my app's settings:
import {
getBoolean,
setBoolean,
getNumber,
setNumber,
getString,
setString,
hasKey,
remove,
clear
} from "application-settings";
export class Config {
clear() {
clear()
}
get token(): string {
return getString('token')
}
set token(token: string) {
setString('token', token)
}
get userId(): string {
return getString('userId')
}
set userId(userId: string) {
setString('userId', userId)
}
}
Use application-settings module to store your session key or something, if no value is there consider it's first time login.
Docs: https://docs.nativescript.org/cookbook/application-settings
You can use the application-settings module to store different type of values (e.g. number, string, boolean) and use the module to check if the user has already logged in.

The proper way to skip the dashboard for non-master users in a User Frosting site

I want any user who isn't the master user to be redirected to a separate page at /profiles.
I've achieved this by editing the admin sprinkle, adding this simple statement to the pageDashboard function in AdminController.php:
if(!$currentUser->isMaster()){
header("Location: /profiles");
exit;
}
I want to move this to my own sprinkle, but I'm not clear on how best to do this. Would I create my own controller that extends AdminController, and just replace the function? Or is there a neater way of doing it? What I have now works but obviously isn't future-proof as this file will be overwritten in future updates.
You can change where the users are redirected after login using the determineRedirectOnLogin service. See : https://learn.userfrosting.com/services/default-services#determineredirectonlogin. In your sprinkle ServicesProvider, simply overwrite the default service with something similar:
$container['determineRedirectOnLogin'] = function ($c) {
return function ($response) use ($c)
{
if (!$c->currentUser->isMaster()) {
return $response->withHeader('UF-Redirect', '/dashboard');
} else {
return $response->withHeader('UF-Redirect', '/profiles');
}
};
};
You can then use the permission system to remove access to the dashboard for the non root users if you wish so.
Side note, like you pointed out, you shouldn't edit any core sprinkles and move that code to your own sprinkle.

working with session on zf2 (recover container)

PRECEDENTS:
using a custom hack OF ZfcUserLdap to authenticate against a LDAP server (include zfcUser too as dependency)
the hack is due the Ldap server uses a ldapc wrapper, so the bind and search process doesn't belong to Ldap standards but through a ldapc library
the login/password box works great against the Ldap server by modifying the bind and findbyuser methods
NEED:
add country selection at login step
check if the user has the permission to work with this country (so to have the country here has sense, don't need ACL, it will be check through LDAP user groups)
store the selected country to use along the whole application
WORK IN PROGRESS:
add SELECT dropdown with available countries to login box [OK]
get the country selected at the login form [OK]
-> at authenticate method on ZfcUserLdap\Authentication\Adapter\Ldap.php class I get correctly the country set at the form
PROBLEM:
how to store the country into a session variable,
-> since zfcUser has an Storage defined and the country is defined at the login step, I would like to use that Storage
I will appreciate any kind of clarification or tips to accomplish this task.
SOLUTION:
The logic is more at zfcUserLdap module, since the auth is against an LDAP Server.
I added to the Entity extended at zfcUserLdap a new property, country that is set to the Entity object along the findByUsername method.
public function findByUsername($username, $country = null)
{
$pUser = $this->ldap->findByUsername($username);
if (isObjectNotNull($pUser))
{
$this->entity->setDisplayName(getLdapUserFirstName($pUser) . ' ' . getLdapUserLastName($pUser));
$this->entity->setEmail(getLdapUserMail($pUser));
$this->entity->setId(getLdapUserUid($pUser));
$this->entity->setUsername(getLdapUserUid($pUser));
$this->entity->setLdapcObject($pUser);
$this->entity->setUserCountry($country);
return $this->entity;
}
else {
return null;
}
}
To have the country here will be useful because the authentication process might check if the username has permission to work within that country. I'll need to add that check later.
Like this, the country is part of the entity object, so I can get the country at the same way I was able to get the username.
For now, I have create a View Helper very similar to ZfcUserDisplayName. I just update the get metohd to get the country property.
$countryName = $user->getUserCountry();
I plan to create a Controller Plugin to get the country from any Controller.
ZFCUser has an authenticate event that you should leverage for this. IN your Module's main bootstrap:
$sm = $e->getApplication()->getServiceManager();
$zfcAuthEvents = $e->getApplication()->getServiceManager()->get('ZfcUser\Authentication\Adapter\AdapterChain')->getEventManager();
$zfcAuthEvents->attach( 'authenticate', function( $authEvent ) use( $sm ){
try
{
// use $authEvent->getIdentity() to get country and stick it in a session
return true;
}
catch( \Exception $x )
{
// handle it
}
});
How you store in session is up to you, there's 400 ways to skin that cat.

Symfony2 shared users across multiple apps

I have multiple symfony2 applications which share common entities, but use different database settings. Each of these databases has tables user, user_role and role.
Here's the catch: I would like that user to be able to login to app1 by visiting www.myproject.com/app1/login and after changing URL to /app2/ to use existing token ONLY if identical user exists in app2's database (same username, password and salt). Currently it checks only for same username which is, you must agree, quite inconvenient...
I can't really see when refreshUser() is being called... :-/
All apps use same User and Role entities and UserRepository.
Any help would be much appreciated!
UserRepository:
class UserRepository extends EntityRepository implements \Symfony\Component\Security\Core\User\UserProviderInterface{
/** #var User */
private $user;
public function loadUserByUsername($username) {
/** #var $Q \Doctrine\ORM\Query */
$Q = $this->getEntityManager()
->createQuery('SELECT u FROM CommonsBundle:User u WHERE u.username = :username')
->setParameters(array(
'username' => $username
));
$user = $Q->getOneOrNullResult();
if ( $user == null ){
throw new UsernameNotFoundException("");
}
return $this->user = $user;
}
public function refreshUser(UserInterface $user) {
return $this->loadUserByUsername($user->getUsername());
}
public function supportsClass($class) {
return $class === 'CommonsBundle\Entity\User';
}
public function findById($id){
return $this->getEntityManager()
->createQuery('SELECT u FROM CommonsBundle:User u WHERE u.id = :id')
->setParameters(array(
'id' => $id
))
->getOneOrNullResult();
}
}
User#equals(UserInterface):
I know there is a prettier way to write this method but I will rewrite it after see this working :)
public function equals(UserInterface $user)
{
if (!$user instanceof User) {
return false;
}
if ($this->password !== $user->getPassword()) {
return false;
}
if ($this->getSalt() !== $user->getSalt()) {
return false;
}
if ($this->username !== $user->getUsername()) {
return false;
}
return true;
}
Your question made me think. When using symfony2 security, you got one problem: Either a session is valid, meaning the user is authenticated as either anonymous or real user, or the session is invalid.
So, with this in mind, I don't see your approach working as you would like it, because let's say user1 logs in and is using app1. Now he switches to app2 and is not in the database, meaning he should not have access. What to do now? Invalidate the session? This would mean he has to log in again in app1.
If you would use subdomains, you could tie your session to that subdomain, but this would mean the user has to log in again for each application.
There is another problem: It seems like symfony2 stores the id of the user into the session, so without access to the app1 database, you cannot know what the password and the roles of the user in the app1 database are and cannot check for it.
I guess the security of symfony2 was simply not made for such behaviour. It expects the session to relate to the same user within your whole application.
I don't think that symfony2 is the big problem here but the overall handling with php. Let's think for one moment what I would suggest without symfony2:
When a user logs in, store user and roles into a specific array in the session, like:
user.app1 = array('username','password',array('role1','role2'))
Now, on each request to app1 I would check if user.app1 is in the session and read the roles from there. If not, I would check for user.app2, user.app3 and so on. If I find none, redirect to login. If I find one, I would query the database to find the user with the same username and compare the other values. If match, store everything into the database. If not, check next user from session.
I looked up the symfony security reference, and you got some extension points, so maybe you can work from there on. The form_login got a success_handler, so adding the array to the session as suggested above should be done there. The firewall itself has some parameters like request_matcher and entry_point which could be used to add additional checks like the ones I mentioned above. All are defined as services, so injecting the entity manager and the security context should be no problem.
I personally think the design itself is not optimal here and you might be better of refactoring your code to either use one user for all apps and different roles (remember that you can define many entity managers and use different databases) or even consolidating all databases and storing everything into one database, using acl to prevent users from viewing the "wrong" content.

Resources