I copied an example from the laravel documentation:
public function postResetPassword() {
$credentials = array('email' => Input::get('email'));
return Password::reset($credentials, function($user, $password) {
$user->password = Hash::make($password);
$user->save();
return Redirect::to('/');
});
}
But it seems that returning Redirect::to('/') doesn't work, because instead of home page I get an error which tells that controller method is not found.
But if I write the code this way:
$credentials = array('email' => Input::get('email'));
Password::reset($credentials, function($user, $password) {
$user->password = Hash::make($password);
$user->save();
});
return Redirect::back();
It works, though I can't understand how do I get session flash variables (actually I get them).
Another question is where are the rules about password length (6 chars) are written? Can I change them?
To answer why your first code example doesn't work is because if your look at your app/routes.php file you should see something along the lines of Route::get('/', 'HomeController#index');. The part that comes before the # symbol is the name of your controller while the part after it is the method that is being called in your controller when the route is requested. Make sure that method is defined.
After looking at the following. I think you should put the redirect inside of the closure you give as a return statement.
Then how you retrieve data that has been flashed to the session after redirecting the user you use the following Session::get('key');.
For your last question look at the following documentation.
Example:
$validator = Validator::make(
array('email' => Input::get('email'), 'password' => Input::get('password'), 'password_confirm' => Input::get('password_confirm')),
array('email' => 'required|unique:users,email|email', 'password' => 'required|min:3|max:20|same:password_confirm')
);
The second array passed is where you can modify the rules for the validator.
To answer your second question regarding changing the rules for password validation.
The Password facade extends PasswordBroker.php which has this function on line 208:
/**
* Set a custom password validator.
*
* #param \Closure $callback
* #return void
*/
public function validator(Closure $callback)
{
$this->passwordValidator = $callback;
}
Therefore, to override the default password validator, simply make this call from your controller:
Password::validator(function(){
//validator in here
});
Related
I am working on an assignment in laravel where I've an Application form. I want to submit application form with email, mobileNo, customerId etc.
What I want is to insert form data into users table and then user will be logged in with auto generated password and redirect to Customer's dashboard. Where will be a modal will be open and ask for add password.
On the other hand there is also a login page from where user can login as usual. The login functionality is working properly.
Can someone help me to achieve the above functionality. Thanks in advance.
**Data is : **
email='user#gmail.com'
mobile='9875425698'
customerId='CI10001';
ApplicationForm Controller Where I am getting data successfully
class ApplicationForm extends Controller
{
public function saveApplicationForm(Request $request){
return $request;
}
}
Add user by submiting form
$password = bcrypt('secret'); //add here random password
$user = new User();
$user->email = 'xyz#gmail.com';
$user->mobileNo = '123456789';
$user->customerId = '1245';
$user->password = $password;
$user->save();
after you insert raw on user table login by user id without password
Auth::loginUsingId($user->id);
Auth::loginUsingId($user->id,true); // Login and "remember" the given user...
by otherwise login with email and password
Auth::attempt(['email' => $user->email, 'password' => $password], $remember);
all action do in one method(action)
Following my comment:
In the RegisterController (App\Http\Controllers\Auth)
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'institution' => $data['institution'],
'password' => 'NOT_SET',
]);
}
Then create a middleware (e.g. php artisan make:middleware Must_have_password)
namespace App\Http\Middleware;
use Closure;
use Auth;
class Must_have_password
{
/**
* Verify if password is set, otherwise redirect to password-set page.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$user = Auth::user();
if ($user && $user->password !== 'NOT_SET') {
return $next($request);
}
else return redirect('/set-password');
}
}
Of course, you then need to create a password setting view and hook that to the /set-password route. As I said in the comment, you want to make sure that /set-password route is well protected because you don't want people hijacking accounts that way. The good thing about this approach (using NOT_SET) is that people can always use the password_reset infrastructure to reset their password if they don't do it initially.
This is a bit hacky, but because Laravel always encrypts the passwords, there is no way the value can become NOT_SET in another way. Alternatively, you could add a boolean to your user-model (something like Must_Reset) that redirects to the password-reset page.
You can also hook in the password-reset functionality of Laravel, look for 'One Time Password Laravel' (e.g. here).
I am using Crypt:: for registration and login. My registration is successful but login is not successful. Please check the code and help me.
public function Login(Request $request)
{
$this->validate($request, [
'email' => 'required',
'password' => 'required',
]);
$userdata = array(
'email' => $request->email,
'password' => \Crypt::encrypt($request->password)
);
if (Auth::attempt($userdata) {
echo "success";die();
}
return "Ops! snap! seems like you provide an invalid login credentials";
}
Originial
You need to use Hashing, not Encryption.
Registration
...
$userdata = [
'email' => $request->email
'password' => Hash::make($request->password)
];
...
// User saved..
Login
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials) {
// It work
}
Ref :
https://laravel.com/docs/5.6/authentication
https://laravel.com/docs/5.6/hashing
Update
OP : I need to Crypt::decrypt to decode the password and send on email. Using hash i couldn't decode it. Thats the reason i need Crypt.
I really don't recommend it. That's why we have the "forgot password" feature to create new password.
Is it secure to store passwords with 2 way encryption?
Okay, back to the topic, How to login with Crypt encryption?
You need to add login() method in Auth\LoginController :
/**
* Handle a login request to the application.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\RedirectResponse|\Illuminate\Http\Response|\Illuminate\Http\JsonResponse
*
* #throws \Illuminate\Validation\ValidationException
*/
public function login(Request $request)
{
$decrypted = $request->input('password');
$user = User::where('email', $request->input('email'))->first();
if ($user) {
if (Crypt::decryptString($user->password) == $decrypted) {
Auth::login($user);
return $this->sendLoginResponse($request);
}
}
return $this->sendFailedLoginResponse($request);
}
WARNING!
All of Laravel's encrypted values are signed using a message authentication code (MAC) so that their underlying value can not be modified once encrypted.
You must have the same key. If you change the key (artisan key:generate), it means you will not be able to login.
I really don't recommend it.
I have this problem before.
I used Crypt Encryption because I need to display the password from encrypted to decrypted in laravel blade input element.
I deeply look at laravel references in projects and found a solution.
In default laravel used HASH for encryption, since I used Crypt to Register and Login.
When I try to Login this returns false.
What I did is edited one laravel function located in
vendor\laravel\framework\src\Illuminate\Auth\EloquentServiceProvider.php
and change this function from these
public function validateCredentials(UserContract $user, array $credentials)
{
$plain = $credentials['password'];
return $this->hasher->check($plain, $user->getAuthPassword());
}
to these
public function validateCredentials(UserContract $user, array $credentials)
{
$plain = $credentials['password'];
return \Crypt::decrypt($user->getAuthPassword());
}
I am trying to pass a pageTitle variable to the password reset template (/resources/views/auth/passwords/reset.blade.php) in Laravel 5.3 in the following way:
return view('auth.passwords.reset')
->with('pageTitle', 'Change title')
->with(['token' => $token, 'email' => $request->email]);
this goes in the showResetForm method inside ResetsPasswords trait - and it doesn't work. Google doesn't come up with any helpful results. I've tried removing the line:
->with(['token' => $token, 'email' => $request->email]);
but it still doesn't work. I've also tried
$pageTitle = 'Change me';
return view('auth.passwords.reset', compact('pageTitle'));
but it doesn't work. Also, I've realized that the ResetsPassword trait is found in the vendor folder so it's a bad idea to change the code there, how do you suggest I do this instead? Can I overwrite the showResetForm method somewhere? - I found that for the registration trait I can put the showRegistrationForm in the RegistrationController and pass whatever variables I want to the view there; however that doesn't work for the ResetPasswordController
EDIT:
Here is the whole method from the ResetsPasswords trait, as requested:
/**
* Display the password reset view for the given token.
*
* If no token is present, display the link request form.
*
* #param \Illuminate\Http\Request $request
* #param string|null $token
* #return \Illuminate\Contracts\View\Factory|\Illuminate\View\View
*/
public function showResetForm(Request $request, $token = null)
{
return view('auth.passwords.reset')->with(['token' => $token, 'email' => $request->email]);
}
Try using compact
return view('auth.passwords.reset', compact('token', 'email', etc..));
return view('auth.passwords.reset')
->with(['pageTitle' => 'Change Title','token' => $token, 'email' => $request->email]);
have you tried it like this?
EDIT
$pageTitle = 'Change Title';
$token = 'token';
$email = 'email';
return view('auth.passwords.reset', compact('pageTitle','token','email'));
The problem was I was editing the wrong trait, I need to edit the SendsPasswordResetEmails trait and not the ResetsPassword.
Heyo!
I know it's a common problem people having problems with custom providers and web service authentication. I'm spending hours trying to figure out how to do that but I'm almost freaking out.
So, the thing is: I'm using the Symfony Firewalls with a custom UserProvider and a AbstractGuardAuthenticator as well. The problem is in the loadUserByUsername($username) function inside the UserProvider implementation.
For security reasons I can't retrieve the user password from Parse (my web service), and the loadUserByUsername($username) function asks for that. Even in the documentation about how to create a custom user provider using web services they are retrieving the user password from the database.
So what's the solution in that case? What can I do when I don't have access to the user password?
My current code is something like that:
$app['app.authenticator'] = function () {
return new Authenticator($app);
};
$app['security.firewalls'] = array(
'login' => array(
'pattern' => '^/login/$',
),
'secured' => array(
'pattern' => '^.*$',
'form' => array('login_path' => '/login/', 'check_path' => '/login/auth/'),
'logout' => array('logout_path' => '/logout/', 'invalidate_session' => true),
'guard' => array(
'authenticators' => array(
'app.authenticator'
),
),
'users' => function () use ($app) {
return new UserProvider($app);
},
)
);
The Authenticator.php is quite big code because extends the AbstractGuardAuthenticator class. But I'm basically using this one from Symfony docs. The only thing Is that I'm sending to the UserProvider class the username AND the password as well, because that way I can check if the user and password are right. Like this:
public function getUser($credentials, UserProviderInterface $userProvider) {
return $userProvider->loadUserByUsername($credentials);
}
And my UserProvider class is the default one, I'm just checking inside the loadUserByUsername function if the credentials comming from my Authenticator are right. Something like this:
public function loadUserByUsername($credentials) {
$encoder = new BCryptPasswordEncoder(13);
try {
$user = ParseUser::logIn($credentials['username'], $credentials['password']);
} catch (ParseException $error) {
throw new UsernameNotFoundException(sprintf('Invalid Credentials.'));
}
return new User($credentials['username'], $encoder->encodePassword($credentials['password'], ''), explode(',', 'ROLE_USER'), true, true, true, true);
}
The problem is: after the login (everything with the login is working fine), Silex calls the loadUserByUsername function in every page which needs to be secured, but just sending the username parameter.
So basically, I don't know what to do guys. I'm really trying to figure out how to get this thing working.
Thanks for your help!
I have a similar implementation and this issue is well known. In my user provider I have the methods loadUserByUsername($username) and refreshUser(UserInterface $user). Since I have the same issue like you, I don't check the user in loadUserByUsername but simple return a new Object with only the username in it to not disturb the flow. loadUserByUsername doesn't make sense for external APIs, so I simply jump over it. The method refreshUser is either beeing called on every request, this is usefull.
In your AbstractGuardAuthenticator you have the method createAuthenticatedToken, which returns an token. There you should have the full authentificated user:
abstract class AbstractGuardAuthenticator implements GuardAuthenticatorInterface
{
/**
* Shortcut to create a PostAuthenticationGuardToken for you, if you don't really
* care about which authenticated token you're using.
*
* #param UserInterface $user
* #param string $providerKey
*
* #return PostAuthenticationGuardToken
*/
public function createAuthenticatedToken(UserInterface $user, $providerKey)
{
//do login stuff
//save password in user
return new PostAuthenticationGuardToken(
$user,
$providerKey,
$user->getRoles()
);
}
}
Then, I would't use loadUserByUsername but refreshUser instead. Both are called on every request:
/**
* Don't use
* #codeCoverageIgnore
* #param string $username
* #return User
*/
public function loadUserByUsername($username)
{
return new User($username, null, '', ['ROLE_USER'], '');
}
/**
* Refresh user on every subrequest after login
* #param UserInterface $user
* #return User
*/
public function refreshUser(UserInterface $user)
{
$password = $user->getPassword();
$username = $user->getUsername();
//login check
}
I'm building a Laravel 5.3 app and using the basic auth of laravel (artisan make:auth). Now, the "Forgot Password" functionality works fine, so if a user can't login because he doesn't know his password, he can get a mail to reset it. But now I want that logged in users can change their password as well. I found that, but this doesn't really help me. I also know that there's a ResetsPasswords trait but how do I use it? And is there already a view as well I can use?
Can somebody help me here?
You don't actually need to use the default password controller to achieve this, you can write your own function to get the same result, for example:
public function postUpdatePassword() {
$user = Auth::user();
$password = $this->request->only([
'current_password', 'new_password', 'new_password_confirmation'
]);
$validator = Validator::make($password, [
'current_password' => 'required|current_password_match',
'new_password' => 'required|min:6|confirmed',
]);
if ( $validator->fails() )
return back()
->withErrors($validator)
->withInput();
$updated = $user->update([ 'password' => bcrypt($password['new_password']) ]);
if($updated)
return back()->with('success', 1);
return back()->with('success', 0);
}
As you can see I registered a new custom validation rule to check if the new passowrd match the old one, to register the rule just go to "app/Providers/AppServiceProvider.php" and add to the boot function the next lines:
Validator::extend('current_password_match', function($attribute, $value, $parameters, $validator) {
return Hash::check($value, Auth::user()->password);
});
Now the validation rule works but you won't get the error message, to add an error message to the new rule you just created you will have to modify these lines in "resources/lang/en/validation.php":
'custom' => [
'current_password' => [
'current_password_match' => 'Current password is incorrect.',
],
],
That's it, now you can use this function to change your the current user password :)
If you want to keep your AppServiceProvider.php file clean of closures (for whatever reason; personally I like these small files neat and tidy) you can add perform the following two things:
1) Add the following to the boot() method of the AppServiceProvider.php
Validator::extend('current_password_match', 'App\Validators\PasswordMatch#check');
2) Add a new file 'app/Validators/PasswordMatch.php' in line with the closure mentioned above.
<?php
namespace App\Validators;
use Hash;
use Auth;
class PasswordMatch
{
public function check($attribute, $value, $parameters, $validator){
return Hash::check($value, Auth::user()->password);
}
}
You can then also add the validation rule messages to your extended FormRequest class messages() method like:
'current_password_match' => 'Current password is incorrect',