I am trying to use Laravel's built in authentication, but it is not working. If I hash a password at the registration process, it does not match the hash in the login process, because Laravel's auth generates a totally different hash than Hash:make().
I made a test route and function, to make everything clear
(I tried to use the Auth::attempt() function with Hash::make() and without Hash::make() too, If I pass the Hashed password, it generates a totally different one, If I pass the raw password the Auth doesn't even bother to hash it):
Route::get('/test', function() {
$email = rand(1, 1000) . "test#mail.com";
$password = $email;
$now = new DateTime();
Felhasznalo::create(array(
'teljesnev' => 'valami',
'email' => $email,
'jelszo' => Hash::make($password),
'FelFelhasznaloiSzint_id' => 2,
'created_at' => $now->getTimestamp(),
'aktiv' => 1
));
if (Auth::attempt(array(
'email' => $email,
'jelszo' => Hash:make($password)
))) {
echo 'Working';
} else {
echo 'Not working';
}
});
The first part generates this row to my mysql server:
39test#mail.com, $2y$10$gkzQ2BEuDWN05RQ/OyBH8u4aKRqdL5zSIthUO4BUyEKcscgzRwZzG, valami ....etc
I intentionally mistyped the password field's name to jelszo1 (means password1 in english), when attempting login, to get an sql error.
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'jelszo1' in 'where clause' (SQL: select * from `Felhasznalo` where `email` = 39test#mail.com and `jelszo1` = y$XAnnnGNKrOQOxBiX2BnEPOq86Y9mh5h./xwUlfCTPpzW.jzzt3YiO limit 1)
First part (in mysql):
$2y$10$gkzQ2BEuDWN05RQ/OyBH8u4aKRqdL5zSIthUO4BUyEKcscgzRwZzG
Second part (when attempting login):
y$XAnnnGNKrOQOxBiX2BnEPOq86Y9mh5h./xwUlfCTPpzW.jzzt3YiO
and the User model (named as Felhasznalo)
<?php
use Illuminate\Auth\UserTrait;
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableTrait;
use Illuminate\Auth\Reminders\RemindableInterface;
class Felhasznalo extends \Eloquent implements UserInterface, RemindableInterface {
use UserTrait,
RemindableTrait;
protected $fillable = [
'id', 'email', 'jelszo', 'teljesnev', 'jelszoreset',
'hash', 'aktiv', 'ban', 'FelFelhasznaloiSzint_id',
'remember_token'
];
protected $guarded = [
];
protected $hidden = [
'jelszo', 'jelszoreset', 'hash'
];
protected $table = 'Felhasznalo';
public $timestamps = true;
protected $softDelete = true;
//----------------------------
//----------------------------
// RELATIONSHIP FUNCTIONS
//----------------------------
//----------------------------
/**
* Get the unique identifier for the user.
*
* #return mixed
*/
public function getAuthIdentifier() {
return $this->getKey();
}
/**
* Get the password for the user.
*
* #return string
*/
public function getAuthPassword() {
return $this->jelszo;
}
/**
* Get the e-mail address where password reminders are sent.
*
* #return string
*/
public function getReminderEmail() {
return $this->email;
}
public function getRememberToken() {
return $this->remember_token;
}
public function setRememberToken($value) {
$this->remember_token = $value;
}
public function getRememberTokenName() {
return 'remember_token';
}
}
The auth config.:
'model' => 'Felhasznalo',
'table' => 'Felhasznalo',
SQL Error error when using raw password in attempt():
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'jelszo1' in 'where clause' (SQL: select * from `Felhasznalo` where `email` = 832test#mail.com and `jelszo1` = 832test#mail.com limit 1)
The answer to Your question from the post's title (Which Hash function laravel's Auth is using?) can be found on mnshankar.wordpress.com - Laravel Hash::make() explained.
Here is the first sentence from the "How?" section of the linked blog post:
Internally, Hash::make() encrypts using the bcrypt function and Blowfish algorithm.
Also, You can see on the Laravel 5.4 docs - Hashing page that they say:
The Laravel Hash facade provides secure Bcrypt hashing for storing user passwords.
I just checked the Auth code, your password column MUST be called password. You cannot use jelszo
Also - yourr login code is incorrect. You just do this:
if (Auth::attempt(array(
'email' => $email,
'password' => $password
))) {
echo 'Working';
} else {
echo 'Not working';
}
Auth::attempt() will do the hashing for you.
Related
I have implemented Laravel 6 API and used Laravel's inbuilt Illuminate\Foundation\Auth\VerifiesEmails based on tutorial here but the email verification link is not expired and still accessible after successful email verification. I have found many tutorials regarding laravel frontend but how to implement it on API.
VerificationApiController
class VerificationApiController extends Controller
{
use VerifiesEmails;
/**
* Mark the authenticated user's email address as verified.
* #param Request $request
* #return JsonResponse
*/
public function verify(Request $request): JsonResponse
{
$userID = $request['id'];
$user = User::findOrFail($userID);
$date = date('Y-m-d g:i:s');
// to enable the “email_verified_at field of that
// user be a current time stamp by mimicking the
// must verify email feature
$user->email_verified_at = $date;
$user->save();
return response()->json('Email verified!');
}
/**
* Resend the email verification notification.
* #param Request $request
* #return JsonResponse|Response
*/
public function resend(Request $request)
{
if ($request->user()->hasVerifiedEmail()) {
return response()->json('User already have verified email!', 422);
}
$request->user()->sendEmailVerificationNotification();
return response()->json('The notification has been resubmitted');
// return back()->with(‘resent’, true);
}
}
User model
class User extends Authenticatable implements MustVerifyEmail
{
use HasApiTokens, Notifiable;
protected $fillable = [
'name', 'email', 'password'
];
/**
* The attributes that should be hidden for arrays.
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
/**
* Send email verification notification
*/
public function sendApiEmailVerificationNotification()
{
$this->notify(new VerifyApiEmail); // my notification
}
}
Here are verification api routes
Route::get(‘email/verify/{id}’, ‘VerificationApiController#verify’)->name(‘verificationapi.verify’);
Route::get(‘email/resend’, ‘VerificationApiController#resend’)->name(‘verificationapi.resend’)
Here is UsersApiController
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\User;
use Illuminate\Support\Facades\Hash;
use Auth;
use Validator;
use Illuminate\Foundation\Auth\VerifiesEmails;
use Illuminate\Auth\Events\Verified;
class UsersApiController extends Controller
{
use VerifiesEmails;
public $successStatus = 200;
/**
* login api
*
* #return \Illuminate\Http\Response
*/
public function login(){
if(Auth::attempt([‘email’ => request(‘email’), ‘password’ => request(‘password’)])){
$user = Auth::user();
if($user->email_verified_at !== NULL){
$success[‘message’] = “Login successfull”;
return response()->json([‘success’ => $success], $this-> successStatus);
}else{
return response()->json([‘error’=>’Please Verify Email’], 401);
}
}
else{
return response()->json([‘error’=>’Unauthorised’], 401);
}
}
/**
* Register api
*
* #return \Illuminate\Http\Response
*/
public function register(Request $request)
{
$validator = Validator::make($request->all(), [
‘name’ => ‘required’,
‘email’ => ‘required|email’,
‘password’ => ‘required’,
‘c_password’ => ‘required|same:password’,
]);
if ($validator->fails()) {
return response()->json([‘error’=>$validator->errors()], 401);
}
$input = $request->all();
$input[‘password’] = Hash::make($input[‘password’]);
$user = User::create($input);
$user->sendApiEmailVerificationNotification();
$success[‘message’] = ‘Please confirm yourself by clicking on verify user button sent to you on your email’;
return response()->json([‘success’=>$success], $this-> successStatus);
}
/**
* details api
*
* #return \Illuminate\Http\Response
*/
public function details()
{
$user = Auth::user();
return response()->json([‘success’ => $user], $this-> successStatus);
}
}
Here are user and auth routes
Route::post(‘login’, ‘UsersApiController#login’);
Route::post(‘register’, ‘UsersApiController#register’);
Route::group([‘middleware’ => ‘auth:api’], function(){
Route::post(‘details’, ‘UsersApiController#details’)->middleware(‘verified’);
}); // will work only when user has verified the email
so the problem is that when I click on verification link on email the user is verified but the link is not expired . I want the link to be expired as soon as user is verified. How to do that?
Have you implemented the VerifyApiEmail class?
namespace App\Notifications;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\URL;
use Illuminate\Auth\Notifications\VerifyEmail as VerifyEmailBase;
class VerifyApiEmail extends VerifyEmailBase
{
protected function verificationUrl($notifiable)
{
return URL::temporarySignedRoute(
'api.auth.verify', Carbon::now()->addMinutes(60), ['id' => $notifiable->getKey()]
);
}
}
Here you can add the expiration time in minutes, seconds or hours.
Save crypt hash security:
$usuario = new User();
$usuario->password = $this->security->hash($this->request->getPost("pass"));
if (!$usuario->save()) {
foreach ($usuario->getMessages() as $message) {
$this->flash->error($message);
}
$this->dispatcher->forward([
'controller' => "usuario",
'action' => 'new'
]);
return;
}
now, How to decrypt hash security to send my form:
$usuario = User::findFirstByid($iduser);
$this->tag->setDefault("pass", $this->encryption->decrypt($usuario->password));
I having this: Notice: Access to undefined property encryption in ...
As #Juri said Hashes are only one way. You can however use encryptBase64() which is two way and you can decode it back. Do not use it for passwords, use it for some data you need to pass to someone and read it back, like api token etc..
Here is how to set it up:
$di->setShared('crypt', function () use ($config) {
$crypt = new \Phalcon\Crypt();
$crypt->setKey('i$4^&/:%2#k50ROQ<#{(e=*!<7u|rI~0');
return $crypt;
});
Helper functions I created, but you can use it directly:
...
...
private static $cryptKey = 'i$4^&/:%2#k50ROQ<#{(e=*!<7u|rI~0';
/**
* Generate url safe encoded string
*
* #param string $string string to be encoded
* #return encoded string
*/
public static function encodeString($string)
{
$crypt = new \Phalcon\Crypt();
return $crypt->encryptBase64($string, self::$cryptKey, true);
}
/**
* Decode string generated with Common::encodeString()
*
* #param string $string Encoded string
* #return decoded string
*/
public static function decodeString($string)
{
$crypt = new \Phalcon\Crypt();
return $crypt->decryptBase64($string, self::$cryptKey, true);
}
I'm using Laravel 5.1 to build back-end system with RESTFUl resources which will be consumed by some mobile applications.
Forgot Password Story
if someone forgot password then the server has to send an email with the temporary password to his registered email. From the next time on words server has to authenticate the user either with temp password or with the password
Can someone guide me how to do this
You can modify your PasswordController located in app\http\controllers\auth
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\ResetsPasswords;
use App\Models\User; //yours is probably App\User;
use Mail, Hash;
class PasswordController extends Controller
{
/*
|--------------------------------------------------------------------------
| Password Reset Controller
|--------------------------------------------------------------------------
|
| This controller is responsible for handling password reset requests
| and uses a simple trait to include this behavior. You're free to
| explore this trait and override any methods you wish to tweak.
|
*/
use ResetsPasswords;
/**
* Create a new password controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest');
}
public function postEmail(Request $request)
{
$this->validate($request, ['email' => 'required|email']);
$email = $request->get('email');
if(!$user = User::where('email', $email)->first()) return redirect()->back()->with('error', 'Email does not exists');
//create temporal password
$temp_password = str_random(8); //generates random 8 characters long string
//hash password and save in database
//I assume you have `temp_password` in your users column
$user->temp_password = Hash::make($temp_password);
$user->save();
//data to be used in mail
$data['subject'] = 'Password Reminder'; //$this->getEmailSubject();
$data['email'] = $email;
$data['temp_password'] = $temp_password;
//send mail to user
Mail::send('emails.password_reminder', $data, function($message) use ($data)
{
$message->from('no-reply#site.com', $data['subject']);
$message->subject($data['subject']);
$message->to($data['email']);
});
}
}
Then in resource/views/emails create password_reminder.blade.php
Your temporal password is {{$temp_password}}
NB:Someone requested a password reminder, if you are not the one kindly ignore
For User Authentication
try - (not tested)
$email = \Request::get('email');
$password = \Request::get('password');
if (Auth::attempt(['email' =>$email, 'password' => $password])){
return true;
}elseif(Auth::attempt(['email' =>$email, 'temp_password' => $password])){
return true;
}else{
return false;
}
or try this
$email = \Request::get('email');
$password = \Request::get('password');
$user = User::where('email',$email)->first();
if(!$user) return false;
if (Auth::attempt(['email' =>$email, 'password' => $password])){
return true;
}elseif(\Hash::check($password, $user->temp_password)){
Auth::loginUsingId($user->id); return true;
}else{
return false;
}
I use Cartalyst Sentry for authentication. When I try to seed my database from command line, I get this error:
[Cartalyst\Sentry\Users\LoginRequiredException]
A login is required for a user, none given.
This is my DatabaseSeeder.php file:
<?php
class DatabaseSeeder extends Seeder {
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
Eloquent::unguard();
$this->call('PriceChangeOccuredTableSeeder');
}
}
And this is my PriceChangeOccuredTableSeeder.php file:
<?php
// Composer: "fzaninotto/faker": "v1.3.0"
use Faker\Factory as Faker;
class PriceChangeOccuredTableSeeder extends Seeder {
public function run() {
DB::table('price_change_occured')->delete();
User::create(array('product_id' => 1, 'owner_id' => 2, 'change_occured' => 1));
}
}
And this is my PriceChangeOccured model
<?php
class PriceChangeOccured extends \Eloquent {
public $table = 'price_change_occured';
}
if change your login from "EMAIL" to "USERNAME" ,and every thing was good,you should change these too:
in your seed add username too:
class UserSeeder extends Seeder
{
protected $admin_email = "admin#admin.com";
protected $admin_password = "password";
protected $admin_username = "naghipour.me";
}
find SentryUserRepository.php and find create function and change to this:
$data = array(
"email" => $input["email"],
"password" => $input["password"],
"username" => $input["username"]
);
Attention: you should add username filed in migration :
$table->string('username', 100)->unique();
and every where there is email you should add username too.
The error says that you are not adding a login to the user. And it seems that you aren't. Thus, you only need to add the login (or email) depending on how your User table works.
I'm assuming that a email/login and password woud be required for your user table. And you are not providing any of those when you create the user on this example.
I am new at Laravel and having some struggles with simple login and authorization pages.
I followed an awesome video tutorial by laracasts.com (credits for that one, really helpful).
My situation:
When implementing authorization to my page, the page after the login succeeds the authorization check.
So: loginform > press button > You are now logged in.
My problem:
After I press the back button and refresh, it still gives the login form. It shouldn't.
routes.php
<?php
Route::get('login', 'SessionsController#create');
Route::get('logout', 'SessionsController#destroy');
Route::resource('users', 'UsersController');
Route::resource('sessions', 'SessionsController');
Route::get('admin', function(){
return 'Admin page';
})->before('auth');
Route::get('dashboard', ['before' => 'auth', function(){
return 'Dashboard';
}]);
SessionsController.php:
<?php
class SessionsController extends BaseController{
public function create()
{
if ( Auth::check() )
{
Redirect::to('/admin');
}
return View::make('sessions.create');
}
public function store()
{
if( Auth::attempt(Input::only('email', 'password')) )
{
// if(Auth::check())
// {
// return 'check worked!';
// }
return 'Welcome ' . Auth::user()->username; //You are now logged in
}
return 'Failed';
}
public function destroy()
{
Auth::logout();
return Redirect::to('sessions.create');
}
}
User.php
<?php
use Illuminate\Auth\UserInterface;
use Illuminate\Auth\Reminders\RemindableInterface;
class User extends Eloquent implements UserInterface, RemindableInterface {
public $timestamps = true;
protected $fillable = ['username', 'email', 'password'];
protected $guarded = ['id'];
public static $rules = [
'username' => 'required',
'password' => 'required'
];
public $errors;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = array('password');
/**
* Get the unique identifier for the user.
*
* #return mixed
*/
public function getAuthIdentifier()
{
return $this->getKey();
}
/**
* Get the password for the user.
*
* #return string
*/
public function getAuthPassword()
{
return $this->password;
}
/**
* Get the e-mail address where password reminders are sent.
*
* #return string
*/
public function getReminderEmail()
{
return $this->email;
}
public function isValid()
{
$validation = Validator::make($this->attributes, static::$rules );
if($validation->passes() )
return true;
$this->errors = $validation->messages();
return false;
}
}
create.blade.php
#extends('layouts.default')
#section('content')
<h1>Create new user</h1>
{{Form::open([ 'route' => 'users.store' ]) }}
<div>
{{Form::label('username', 'Username: ')}}
{{Form::text('username')}}
{{$errors->first('username')}}
</div>
<div>
{{Form::label('password', 'Password: ')}}
{{Form::password('password')}}
{{$errors->first('password')}}
</div>
<div>
{{Form::submit('Create User')}}
</div>
{{Form::close() }}
#stop
So to speak: It never goes to the 'admin' route.
Your authentication code is correct and working. What you have is something going wrong in any other part of your Laravel application, web server or even PHP.
Since we are not seeing all your code, we can just guess, so my first one would be the Session not being stored correctly. Currently logged users are stored in Laravel Session. So, check your session driver, if it's in 'native', change it to 'database', but you'll have to create a sessions table, look at the docs. If you are already using 'database', change it back to 'native' or even 'file'.
Instead of run
return 'Welcome ' . Auth::user()->username; //You are now logged in
Please try
return Redirect::to('admin');