password reset table column name override laravel 5 - php

Hello friends i have modified password reset table column name 'created_at' instead of 'created'. if i am changing column name 'created' on migration, But i am getting the error column not found 'created_at'.
\vendor\laravel\framework\src\Illuminate\Auth\Passwords\DatabaseTokenRepository.php
protected function getPayload($email, $token)
{
return ['email' => $email, 'token' => $token, 'created_at' => new Carbon];
}
this is the file coming from column name 'created_at' where i can override this function please suggest me..

I think I've found a way to do this without touching the vendor directory.
For Laravel 5.2
Create a class that extends Illuminate\Auth\Passwords\DatabaseTokenRepository
Overwrite the getPayload() method there
Create a class that extends Illuminate\Auth\Passwords\PasswordBrokerManager
Overwrite the resolve() method to return a new PasswordBroker with your token repository from step 1
Open config/app.php and comment out PasswordResetServiceProvider from the providers array
In your app service provider register an instance of your password broker manager from step 3
$this->app->singleton('auth.password', function ($app) {
return new YourPasswordBrokerManager($app);
});
$this->app->bind('auth.password.broker', function ($app) {
return $app->make('auth.password')->broker();
});
For Lravel 5
Create a class that extends Illuminate\Auth\Passwords\DatabaseTokenRepository
Overwrite the getPayload() method there
Create a class that extends Illuminate\Auth\Passwords\PasswordResetServiceProvider
Overwrite the registerTokenRepository() to return your repository from step 1
Open config/app.php and comment out PasswordResetServiceProvider from the providers array
Add your provider from step 3 to the providers array
Please note that I haven't tested this, but it should work on theory.

Solved: I applied the 5.2 steps in my Laravel 5.4 project:
ForgotPasswordHelperRepository.php
<?PHP
namespace App\Helpers;
use Carbon\Carbon;
class ForgotPasswordHelperRepository extends \Illuminate\Auth\Passwords\DatabaseTokenRepository
{
/**
* Build the record payload for the table.
* I wanted to add an extra column organization_id
* organizationId() is a helper method I created
* #param string $email
* #param string $token
* #return array
*/
protected function getPayload($email, $token)
{
return ['email' => $email, 'token' => $this->hasher->make($token), 'created_at' => new Carbon,'organization_id' => organizationId()];
}
}
PasswordBrokerManagerHeler.php
<?PHP
namespace App\Helpers;
use Closure;
use Illuminate\Auth\Passwords\DatabaseTokenRepository;
use Illuminate\Auth\Passwords\PasswordBroker;
use Illuminate\Support\Str;
class PasswordBrokerManagerHelper extends \Illuminate\Auth\Passwords\PasswordBrokerManager
{
/**
* #inheritDoc
*/
public function sendResetLink(array $credentials)
{
// TODO: Implement sendResetLink() method.
}
/**
* #inheritDoc
*/
public function reset(array $credentials, Closure $callback)
{
// TODO: Implement reset() method.
}
/**
* #inheritDoc
*/
public function validator(Closure $callback)
{
// TODO: Implement validator() method.
}
/**
* #inheritDoc
*/
public function validateNewPassword(array $credentials)
{
// TODO: Implement validateNewPassword() method.
}
/**
* Resolve the given broker.
*
* #param string $name
* #return \Illuminate\Contracts\Auth\PasswordBroker
*
* #throws \InvalidArgumentException
*/
protected function resolve($name)
{
$config = $this->getConfig($name);
if (is_null($config)) {
throw new \InvalidArgumentException("Password resetter [{$name}] is not defined.");
}
// The password broker uses a token repository to validate tokens and send user
// password e-mails, as well as validating that password reset process as an
// aggregate service of sorts providing a convenient interface for resets.
return new PasswordBroker(
$this->createTokenRepository($config),
$this->app['auth']->createUserProvider($config['provider'])
);
}
protected function createTokenRepository(array $config)
{
$key = $this->app['config']['app.key'];
if (Str::startsWith($key, 'base64:')) {
$key = base64_decode(substr($key, 7));
}
$connection = isset($config['connection']) ? $config['connection'] : null;
// return new DatabaseTokenRepository(
return new ForgotPasswordHelperRepository(
$this->app['db']->connection($connection),
$this->app['hash'],
$config['table'],
$key,
$config['expire']
);
}
}
Next, just copy and paste the following in the AppServiceProvider#register method
$this->app->singleton('auth.password', function ($app) { return new PasswordBrokerManagerHelper($app); });
$this->app->bind('auth.password.broker', function ($app) { return $app->make('auth.password')->broker(); });

Related

why I can't store new column in laravel notification table?

any way every thing is save in data column
<?php
namespace App\Notifications;
class SendNotification extends Notification implements ShouldQueue
{
use Queueable;
public $message;
public $model_instance;
private $log;
/**
* Create a new notification instance.
*
* #param $message
* #param array $log
* #param Model $model_instance
*/
public function __construct($message, array $log = [],Model $model_instance = null )
{
$this->message = $message;
$this->log = $log;
$this->model_instance = $model_instance->id;
}
/**
* Get the notification's delivery channels.
*
* #param mixed $notifiable
* #return array
*/
public function via($notifiable)
{
return [MicroserviceChannel::class, 'database'];
}
public function toMicroservice($notifiable)
{
return $this->message;
}
public function toDatabase($notifiable)
{
return $this->log;
}
public function toArray() {
return [
'group_id' => $this->model_instance
];
}
}
this is all of my notification class
but I add new column as group_id to this table
now nothing isn't store in data column
detailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetailsdetails
because it need more details :)
make sure add group_id in fillable in your model
toArray and toDatabase methods of notification classes must return a plain Array as explain here Formatting Database Notifications.
Just ensure toDatabase return a plain Array like toArray.
I can presume $this->id is the ID of the Model instance which the Notification is related to. So you must pass that model when you instanciate the notification class like this
$user->notify(new NotificationClass($model_instance));
Here I use $user->notify you can use any Model of classes which use Notifiable.
And in the NotificationClass you'll receive the $model_instance in the Constructor like this
class NotificationClass extends Notification {
public $model_instance;
public function __construct(Model $model_instance){
$this->model_instance = $model_instance;
}
public function toArray() {
return [
'group_id' => $this->model_instance->group_id;
];
}
}
You will have to pass the $group_id value when you call your notification like
$group_id=1;
$user->notify(new ActionsNotification($group_id));
and then in your created notification
protected $group_id;
public function __construct($group_id)
{
$this->group_id= $group_id;
}
public function toDatabase($notifiable)
{
return [
'group_id' => $this->group_id
];
}

Laravel Echo - Allow guests to connect to presence channel

I am using laravel-echo-server to run Laravel Echo to broadcast events.
I have a user counter channel which shows all the users on the app. For this I am using a presence channel. This works fine for logged in users, but guests just never get connected.
I've setup the below in the BroadcastServiceProvider:
Broadcast::channel('global', function () {
return ['name' => 'guest'];
});
Which from what I can tell, should allow everyone in as 'guests'. I'm guessing there's some middleware or auth that's being checked before this that I need to disable for this channel.
Any help on getting all clients joining this presence channel would be much appreciated!
The other solutions didn't work for me for a guest presence channel, this is what I ended up with:
// routes/channels.php
<?php
use Illuminate\Auth\GenericUser;
/*
|--------------------------------------------------------------------------
| Broadcast Channels
|--------------------------------------------------------------------------
|
| Here you may register all of the event broadcasting channels that your
| application supports. The given channel authorization callbacks are
| used to check if an authenticated user can listen to the channel.
|
*/
Route::post('/custom/broadcast/auth/route', function () {
$user = new GenericUser(['id' => microtime()]);
request()->setUserResolver(function () use ($user) {
return $user;
});
return Broadcast::auth(request());
});
Broadcast::channel('online.{uuid}', function ($user, $uuid) {
return [
'id' => $user->id,
'uuid' => $uuid
];
});
You may create a temporary user with factory(User::class)->make(...) and authenticate it with a middleware to use it as a guest.
Step 1: Creating the middleware
Run: php artisan make:middleware AuthenticateGuest
In app/Http/Middleware/AuthenticateGuest.php:
public function handle($request, Closure $next)
{
Auth::login(factory(User::class)->make([
'id' => (int) str_replace('.', '', microtime(true))
]));
return $next($request);
}
Now setup the AuthenticateGuest middleware in Kernel.php.
In app\Http\Kernel.php:
protected $routeMiddleware = [
...
'authenticate-guest' => \App\Http\Middleware\AuthenticateGuest::class,
];
Step 2: Setup Broadcast::channel route
In routes/channels.php:
Broadcast::channel('chatroom', function ($user) {
return $user; // here will return the guest user object
});
More at: https://laravel.com/docs/8.x/broadcasting#authorizing-presence-channels
For anyone looking for answers to this. It is indeed possible to auth guests into presence channels you just need to override the Broadcast::routes() from the service provider with your own.
As an example my presence channel 'global' accepts guests:
Route::post('/broadcasting/auth', function(Illuminate\Http\Request $req) {
if($req->channel_name == 'presence-global'){return 'global';}
return abort(403);
});
This could be extended in various directions, or could continue to pass other presence and private channels through to the default Broadcast::auth method
You can create your own auth guard and it's also pretty simple but more complex.
Create a class which will implement Authenticable Interface.
Create UserProvider.
Create a new Guard.
Register Guard and UserProvider in AuthServiceProvider.
Add provider and guard in config/auth.php
Use your new guard.
Advantages
You don't have to modify auth endpoint
You don't have to change default guard
You base on Laravel Auth system
Keep support of multiple tabs in the browser
Can be used with web guard at the same time
Keep all the advantages of using PresenceChannel
Disadvantages
A lot to code
So,
1. Create a new class which will implement Authenticable interface.
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Contracts\Support\Jsonable;
use JsonSerializable;
/**
* #property string $id
* #property string $name
*/
class Session implements Authenticatable, Jsonable, Arrayable, JsonSerializable
{
private $id;
private $attributes = [];
public function __construct($id)
{
$this->id = $id;
$this->name = "Guest";
}
/**
* Get the name of the unique identifier for the user.
*
* #return string
*/
public function getAuthIdentifierName()
{
return 'id';
}
/**
* Get the unique identifier for the user.
*
* #return mixed
*/
public function getAuthIdentifier()
{
return $this->{$this->getAuthIdentifierName()};
}
/**
* Get the password for the user.
*
* #return string
*/
public function getAuthPassword()
{
return "";
}
/**
* Get the token value for the "remember me" session.
*
* #return string
*/
public function getRememberToken()
{
return $this->{$this->getAuthIdentifierName()};
}
/**
* Set the token value for the "remember me" session.
*
* #param string $value
* #return void
*/
public function setRememberToken($value)
{
$this->{$this->getRememberToken()} = $value;
}
/**
* Get the column name for the "remember me" token.
*
* #return string
*/
public function getRememberTokenName()
{
return "token";
}
public function __get($name)
{
return $this->attributes[$name];
}
public function __set($name, $value)
{
$this->attributes[$name] = $value;
}
/**
* Convert the object to its JSON representation.
*
* #param int $options
* #return string
*/
public function toJson($options = 0)
{
return json_encode($this);
}
/**
* Get the instance as an array.
*
* #return array
*/
public function toArray()
{
return $this->attributes;
}
/**
* Specify data which should be serialized to JSON
* #link https://php.net/manual/en/jsonserializable.jsonserialize.php
* #return mixed data which can be serialized by <b>json_encode</b>,
* which is a value of any type other than a resource.
* #since 5.4.0
*/
public function jsonSerialize()
{
return $this->attributes;
}
}
Modify this as you wish, but you shouldn't serialize $id property
2. Create UserProvider
<?php namespace App\Extensions;
use App\Models\Session;
use Illuminate\Cache\Repository;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Support\Fluent;
use Illuminate\Support\Str;
class SessionUserProvider implements UserProvider
{
private $store;
/**
* SessionUserProvider constructor.
* #param Repository $store
*/
public function __construct(Repository $store)
{
$this->store = $store;
}
/**
* Retrieve a user by their unique identifier.
*
* #param mixed $identifier
* #return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveById($identifier)
{
return new Session(
$this->getUniqueTokenForSession($identifier)
);
}
/**
* Retrieve a user by their unique identifier and "remember me" token.
*
* #param mixed $identifier
* #param string $token
* #return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByToken($identifier, $token)
{
return null;
}
/**
* Update the "remember me" token for the given user in storage.
*
* #param \Illuminate\Contracts\Auth\Authenticatable $user
* #param string $token
* #return void
*/
public function updateRememberToken(Authenticatable $user, $token)
{
return;
}
/**
* Retrieve a user by the given credentials.
*
* #param array $credentials
* #return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByCredentials(array $credentials)
{
return null;
}
private function unpack($data)
{
return json_decode($data);
}
private function getUniqueTokenForSession($id)
{
return $this->retrieveCacheDataForSession($id)
->get('uuid');
}
private function retrieveCacheDataForSession($id)
{
$fluent = new Fluent(
$this->unpack(
$this->store->has($id) ? $this->store->get($id) : "[]"
)
);
if(!$fluent->__isset('uuid')) {
$fluent->__set('uuid', Str::random(128));
}
$this->store->put($id, $fluent->toJson(), 60 * 60 * 60);
return $fluent;
}
/**
* Validate a user against the given credentials.
*
* #param \Illuminate\Contracts\Auth\Authenticatable $user
* #param array $credentials
* #return bool
*/
public function validateCredentials(Authenticatable $user, array $credentials)
{
return null;
}
}
Identifier property in retrieveById method is always session id if you are using broadcasting so you can also use this as a token.
3. Create new Guard
<?php namespace App\Services\Auth;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Contracts\Auth\UserProvider;
use Illuminate\Http\Request;
class GuestGuard implements Guard
{
private $user;
protected $request;
protected $provider;
/**
* GuestGuard constructor.
* #param UserProvider $provider
* #param Request $request
*/
public function __construct(UserProvider $provider, Request $request)
{
$this->provider = $provider;
$this->request = $request;
}
/**
* Determine if the current user is authenticated.
*
* #return bool
*/
public function check()
{
return !is_null($this->user);
}
/**
* Determine if the current user is a guest.
*
* #return bool
*/
public function guest()
{
return !$this->check();
}
/**
* Get the currently authenticated user.
*
* #return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function user()
{
if($this->check()) {
return $this->user;
}
$this->setUser(
$this->provider->retrieveById(
$this->request->session()->getId()
)
);
return $this->user;
}
/**
* Get the ID for the currently authenticated user.
*
* #return int|null
*/
public function id()
{
return !is_null($this->user) ? $this->user->id : null;
}
/**
* Validate a user's credentials.
*
* #param array $credentials
* #return bool
*/
public function validate(array $credentials = [])
{
return false;
}
/**
* Set the current user.
*
* #param \Illuminate\Contracts\Auth\Authenticatable $user
* #return void
*/
public function setUser(Authenticatable $user)
{
$this->user = $user;
}
}
Here in user method you pass session id as identifier, using broadcasting only this method is nessesary.
4. Register Guard and UserProvider in AuthServiceProvider.
// app/Providers/AuthServiceProvider.php
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
Auth::provider('sessions', function (Application $app) {
return new SessionUserProvider(
$app->make('cache.store')
);
});
Auth::extend('guest', function (Application $app, $name, array $config) {
return new GuestGuard(Auth::createUserProvider($config['provider']), $app->make('request'));
});
}
5.1 Add provider in config/auth.php
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
// New
'sessions' => [
'driver' => 'sessions',
'model' => App\Models\Session::class,
],
],
5.2 Add guard in config/auth.php
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
// New
'guest' => [
'driver' => 'guest',
'provider' => 'sessions'
]
],
6. Use your new guard
// routes/channels.php
Broadcast::channel('chat.{id}', function (Authenticatable $user){
return $user;
}, ['guards' => ['guest']]);
Notice that you can use 'web' as a guard at the same time ('web' should be before 'guest'). It allows you to find out who is a guest and who is a logged in user - you can just check instance of Authenticable in channel callback.
And that how it looks in the laravel-echo-server database
With the help of Renan Coelho i got it to work. The missing part for me was to override the Broadcast::routes() method with the following:
Route::post('/broadcasting/auth', function (Illuminate\Http\Request $req) {
return Broadcast::auth($req);
});
Route::post('/broadcasting/auth'... is actually a route that gets added through the "Broadcast::routes()" method. This is why we override it here. You can see the active routes by typing php artisan route:list in your terminal.
Then, Renan Coelho already said, i had to add a custom Middleware (AuthenticateGuest) that creates a random user for me. (This is the hacky part) and add it to the $middleware array in the kernel.php:
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
\App\Http\Middleware\TrimStrings::class,
\Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
\App\Http\Middleware\TrustProxies::class,
\Barryvdh\Cors\HandleCors::class,
\App\Http\Middleware\AuthenticateGuest::class
];
The AuthenticateGuest Middleware looks like the following:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
use App\User;
class AuthenticateGuest
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
Auth::login(factory(User::class)->make([
'id' => (int)str_replace('.', '', microtime(true))
]));
return $next($request);
}
}
Hope that helps someone,
Sebastian
My solution to issue:
BroadcastServiceProvider.php (~/app/Providers/)
public function boot()
{
if (request()->hasHeader('V-Auth')) { /* Virtual client. */
Broadcast::routes(['middleware' => 'client_chat.broadcast.auth']);
} else {
Broadcast::routes();
}
require base_path('routes/channels.php');
}
Kernel.php (~/app/Http/)
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
...
'client_chat.broadcast.auth' => \App\Http\Middleware\ClientChatBroadcasting::class,
];
ClientChatBroadcasting.php (~/app/Http/Middleware/)
public function handle($request, Closure $next)
{
if (/** your condition **/) {
$fakeUser = new User;
$fakeUser->virtual_client = true;
$fakeUser->id = /** whatever you want **/;
$fakeUser->name = '[virtual_client]';
$fakeUser->asdasdasdasdasd = 'asdasdasdasdasd';
$request->merge(['user' => $fakeUser]);
$request->setUserResolver(function () use ($fakeUser) {
return $fakeUser;
});
}
return $next($request);
}
ChatChannel.php (~/app/Broadcasting/Chat/)
Broadcast::channel('chat.{chatId}', ChatChannel::class); Channel Classes
public function join($member/**($fakeUser)**/, $chatId)
{
$memberData = [/** your data **/];
/* If there is no member data (null), then there will be an authentication error. */
return $memberData;
}
[place in your js file, where you want connect to broadcasting]
this.Echo = new Echo({
broadcaster: 'socket.io',
host: /** your host **/,
reconnectionAttempts: 60,
encrypted: true,
auth: {
headers: {
'V-Auth': true,
'Access-Token': accessToken,
'Virtual-Id': virtualId,
'Chat-Id': chatId
}
}
});
I made it here reading this blog, getting the /broadcasting/auth error. The answers were very helpful but I didn't find the complete answer I needed.
I did this in Laravel 9.x so FYI it will work in that version too.
The major missing piece of code I needed was in the routes/web.php:
use Illuminate\Support\Facades\Route;
Broadcast::routes([
'middleware' => ['web', 'authenticate-guest'],
]);
Route::get('/', function () {
return view('welcome');
});
However I will add the rest down here in case anyone needs the whole thing:
Remove comment in app.config provider:
App\Providers\BroadcastServiceProvider::class,
Make middleware: php artisan make:middleware AuthenticateGuest.php
Then update it, in app/Http/Middleware
public function handle(Request $request, Closure $next)
{
Auth::login(User::factory()->make([
'id' => (int) str_replace('.', '', microtime(true))
]));
return $next($request);
}
app/Http/Kernel.php File..
protected $routeMiddleware = [
...
'authenticate-guest' => \App\Http\Middleware\AuthenticateGuest::class
];
app/Providers/BroadcastServiceProvider.php file should be this, but check:
public function boot()
{
Broadcast::routes();
require base_path('routes/channels.php');
}
Lastly, the routes/channel.php file:
use Illuminate\Support\Facades\Broadcast;
Broadcast::channel('common_room', function ($user) {
return true;
});
To finish everything off, do a npm run dev, followed by php artisan route:clear and maybe php artisan cache:clear/php artisan config:clear as well. Hope that helps!

Changing Laravel 5.4 password encryption and table column names

I am trying to integrate the auth in laravel 5.4 within an existing database where the user and password fields have other names (memberid, passwordnew_enc). With the bellow changes and forcing the create function in RegisterController to use MD5 I managed to make the registration work. It also logins fine after registration. However the actual login form returns:
These credentials do not match our records.
So far I have changed the User.php
public function getAuthPassword()
{
return $this->passwordnew_enc;
}
and
public function setPasswordAttribute($value)
{
$this->attributes['password'] = md5($value);
}
Also on LoginController.php
public function username()
{
return 'memberid';
}
Did I miss something ?
I only need to change the two column names to fit and the password encryption from bcrypt to md5
I would make custom user provider php artisan make:provider CustomUserProvider:
<?php
namespace App\Providers;
use Illuminate\Auth\EloquentUserProvider;
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
class CustomUserProvider extends EloquentUserProvider {
/**
* Validate a user against the given credentials.
*
* #param \Illuminate\Contracts\Auth\Authenticatable $user
* #param array $credentials
* #return bool
*/
public function validateCredentials(UserContract $user, array $credentials)
{
$plain = $credentials['password']; // will depend on the name of the input on the login form
$hashedValue = $user->getAuthPassword();
if ($this->hasher->needsRehash($hashedValue) && $hashedValue === md5($plain)) {
$user->passwordnew_enc = bcrypt($plain);
$user->save();
}
return $this->hasher->check($plain, $user->getAuthPassword());
}
}
This way if the password exists using md5 it will allow it to work once and then rehash it.
You will register the CustomUserProvider in App\Providers\AuthServiceProvider boot() as follows:
$this->app['auth']->provider('custom', function ($app, array $config) {
$model = $app['config']['auth.providers.users.model'];
return new CustomUserProvider($app['hash'], $model);
});
Edit your config/auth.php
'providers' => [
'users' => [
'driver' => 'custom',
'model' => App\User::class,
],
],
You will also need to add the following as mentioned previously...
app\Http\Controllers\Auth\LoginController.php
public function username()
{
return 'memberid';
}
app\User.php
public function getAuthIdentifierName()
{
return 'memberid';
}
public function getAuthIdentifier()
{
return $this->memberid;
}
public function getAuthPassword()
{
return $this->passwordnew_enc;
}
Alright I got it
app\User.php
public function setPasswordAttribute($value)
{
$this->attributes['password'] = md5($value);
}
public function getAuthPassword()
{
return $this->passwordnew_enc;
}
public function getAuthIdentifierName()
{
return 'memberid';
}
app\Http\Controllers\Auth\LoginController.php
public function username()
{
return 'memb___id';
}
config\app.php
// Illuminate\Hashing\HashServiceProvider::class,
App\Providers\MD5HashServiceProvider::class,
app\Providers\MD5HashServiceProvider.php
<?php namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class MD5HashServiceProvider extends ServiceProvider
{
/**
* Indicates if loading of the provider is deferred.
*
* #var bool
*/
protected $defer = true;
/**
* Register the service provider.
*
* #return void
*/
public function register()
{
$this->app->singleton('hash', function () {
return new \MD5Hasher;
});
}
/**
* Get the services provided by the provider.
*
* #return array
*/
public function provides()
{
return ['hash'];
}
}
lib\MD5Hasher\MD5Hasher.php
<?php
class MD5Hasher implements Illuminate\Contracts\Hashing\Hasher
{
/**
* Hash the given value.
*
* #param string $value
* #return array $options
* #return string
*/
public function make($value, array $options = array())
{
return md5($value); //hash('md5', $value);
}
/**
* Check the given plain value against a hash.
*
* #param string $value
* #param string $hashedValue
* #param array $options
* #return bool
*/
public function check($value, $hashedValue, array $options = array())
{
return $this->make($value) === $hashedValue;
}
/**
* Check if the given hash has been hashed using the given options.
*
* #param string $hashedValue
* #param array $options
* #return bool
*/
public function needsRehash($hashedValue, array $options = array())
{
return false;
}
}
composer.json
...
"autoload": {
"classmap": [
...
"app/Lib"
],
...
upful's code worked for me (in Laravel 5.4)
But I needed to add:
use Illuminate\Contracts\Auth\Authenticatable as UserContract;
in the CustomUserProvider class.

PHP Trait Override Protected Trait Method

I am having problems with a composer package I am dealing with. It implements a trait Billable.
trait Billable
{
/**
* Update the payment method token for all of the user's subscriptions.
*
* #param string $token
* #return void
*/
protected function updateSubscriptionsToPaymentMethod($token)
{
foreach ($this->subscriptions as $subscription) {
if ($subscription->active()) {
BraintreeSubscription::update($subscription->braintree_id, [
'paymentMethodToken' => $token,
]);
}
}
}
}
I am trying to override this method in my class
class Organisation extends Model
{
use Billable;
/**
* Update the payment method token for all of the user's subscriptions.
*
* #param string $token
* #return void
*/
protected function updateSubscriptionsToPaymentMethod($token)
{
foreach ($this->subscriptions as $subscription) {
if ($subscription->active()) {
BrntreeSubscription::update($subscription->braintree_id, [
'paymentMethodToken' => $token,
]);
}
}
}
}
But the method is not overridden. As a test I overrode some of the public functions and they work fine, it this a limitation of traits? I have tried to find the answer online but have come up short.
I am trying to override this function because I need to customize the behaviour of the BraintreeSubscription class.
Any help would be greatly appreciated.
in your class you could do the following notice the T before the function name you may change this to be aliased as anything really.
use billable {
updateSubscriptionsToPaymentMethod as tUpdateSubscriptionsToPaymentMethod;
}
then simply in the class add the desired function:
public function updateSubscriptionsToPaymentMethod(){
...
}

Unable to get Policies working in Laravel 5.3

I've been following the Laravel Authorization docs trying to build "is the user allowed to do this" functionality by using Policies, but I can't get it to work. I keep getting This action is unauthorized and I've tried with route middleware too.
PagePolicy.php:
namespace App\Policies;
use App\Models\User;
use App\Models\Page;
use Illuminate\Auth\Access\HandlesAuthorization;
class PagePolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view the page.
*
* #param App\Models\User $user
* #param App\Models\Page $page
* #return mixed
*/
public function view(User $user, Page $page)
{
return $user->id === $page->user_id;
}
/**
* Determine whether the user can create pages.
*
* #param App\Models\User $user
* #return mixed
*/
public function create(User $user)
{
}
/**
* Determine whether the user can update the page.
*
* #param App\Models\User $user
* #param App\Models\Page $page
* #return mixed
*/
public function update(User $user, Page $page)
{
//
}
/**
* Determine whether the user can delete the page.
*
* #param App\Models\User $user
* #param App\Models\Page $page
* #return mixed
*/
public function delete(User $user, Page $page)
{
//
}
}
PageController.php:
namespace App\Http\Controllers;
use Auth;
use Carbon\Carbon;
use App\Models\Page;
use App\Http\Requests\PageRequest;
class PageController extends ApiController
{
public function createNewPage(PageRequest $request)
{
$this->authorize('create', Page::class);
$request->merge([
'user_id' => Auth::id(),
'published_at' => Carbon::now(),
]);
if (Page::create($request->all())) {
return response()->json('success', 201);
}
return response()->json('error', 500);
}
}
AuthServiceProvidor.php:
namespace App\Providers;
use App\Models\Page;
use App\Policies\PagePolicy;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* #var array
*/
protected $policies = [
Page::class => PagePolicy::class,
];
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
//
}
}
I managed to figure it out. I wasn't using Route Model Binding. So I added authorize() after the page call and used the $page variable instead of Page::class.
public function update(PageUpdateRequest $request, $pageSlug)
{
$page = Page::where(['user_id' => Auth::id(), 'slug' => $pageSlug])->first();
$this->authorize('update', $page);
$page->update($request->all());
return fractal()->item($page, new PageTransformer())->toArray();
}
It's not totally clear to me which action you're attempting to authorize since you've provided the call to create in the controller but only provided a policy check in place for viewing a page. Having said that, I would be sure to var_dump/dd the values you're attempting to do a type comparison of to verify they're of the same type. If anything's been explicitly cast, it may cause issues with certain database drivers that return integers as strings.
I think the problem is not in your policies, rather in your PageRequest class. Make sure the authorize() method in your App\Http\Requests\PageRequest class returns true .
class PageRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true; // you can also check the authorization using PagePolicy here
}
}
Current code:
protected $policies = [
Task::class => TaskPolicy::class,
];
Solution code:
protected $policies = [
'App\Task' => 'App\Policies\TaskPolicy',
];
I experienced the same problem, while following the Intermediate Task List Tutorial on the Laravel website.
The solution is actually present in the Github code for this tutorial.

Categories