Better Code for Authentication in Laravel - php

I am really new to PHP and Laravel and i am a little embarrassed for asking this Questions but none of the things i am trying to reuse code in my Controllers work.
I have this function in my PagesController for setting up the welcome-view of my Laravel Web Application:
public function welcome(Request $request)
{
$cities = City::all();
$user_id = $request->session()->pull('user_id');
$user = User::find($user_id);
if($user !== null )$request->session()->put('user_id', $user->id);
return view('welcome',[
'cities' => $cities,
'user_id' => $user_id,
'user' => $user
]);
}
the important stuff are the three lines which gets the user_id and finds the fitting User from the Database.
I'd like to define a function in my BaseController and use it in every other Controller as well.
What would be the easiest way to do this?

Related

How to validate data, protect routes, authorize routes/actions in Laravel 8

This will be a bit long question, I'm finishing my application, but there are few left things to be done before ending.
At first: I did few POST forms/functions. They works well, but in case I would not pass one of the $request data, it comes with SQL bug, I read that to manage that I need validation, so I made Request model with validation rules, but I dont know how to implement it into my Controller class.
This is how looks like my request model and create class inside of controller:
public function create(Request $request)
{
$id = Auth::id();
$event = new Event;
$event->name = $request->name;
$event->description = $request->description;
$event->address = $request->address;
$event->date_of_event = $request->date_of_event;
$event->displayed = 0;
$event->photo_patch = $request->photo_patch->store('images','public');
$event->club_id = $request->club_id;
$event->user_id = $id;
$event->save();
return redirect('events');
}
------------Request---------------------------
return [
'name' => 'required|max:50',
'description' => 'required|max:100',
'address' => 'required|max:63',
'date_of_event' =>'required',
'photo_patch' =>'required',
'club_id' =>'required',
];
Second thing to protect is to split views for admin and for user, Since I did authorization via Gate(admin-level) with column in db admin(boolean)
I'm thinking about doing validation like this:
public function index()
{
$id = Auth::id();
if (Gate::authorize('admin-level')){
$events = Event::get();
}
else{
$events = Event::where('user_id',$id)->get();
}
return view('backend/event/index', ['events' => $events]);
}
but then, comes error:
Non static method 'authorize' should not be called statically.
Is there any way to bypass that? Or, is there any better/easier way to authorize?
My third problem is to protect users from making changes by other users.
What do I mean by that.
Every user got acces only to his own club/events BUT if someone would put url for example other ID, he can edit every single club/event he want. How can I prevent it?
And my final question
I'm protecting my routes with middleware auth is there any better way to do it?
Route::middleware(['auth'])->group(function() {
Thank you in advance for anwsers.
Your gate should be called on the facade, which i do not believe you are doing. Please use the following gate class.
use Illuminate\Support\Facades\Gate;
Validation can be implemented by calling validate() on your request object. This will also automatically throw exceptions if failed.
$validated = $request->validate([
'name' => 'required|max:50',
'description' => 'required|max:100',
'address' => 'required|max:63',
'date_of_event' =>'required',
'photo_patch' =>'required',
'club_id' =>'required',
]);
Disallowing users from editing clubs. In general you control the access to objects, either with policies or with queries. This is an example with a policy.
public function find(Club $club) {
$this->authorize('view', $club);
}
class ClubPolicy {
public function view(User $user, Club $club)
{
return $club->user_id === $user->id;
}
}

Handle form submission Laravel 5

I just start learning Laravel 5, and I want to know what the proper way to handle submitted forms. I found many tutorials where we create two separate actions, where first render form, and the second actually handle form. I am came from Symfony2, where we create a single action for both, render and handle submitted form, so I want to know I need to create two separate actions because thats Laravel-way, or I can place all logic into single action, I do this like the folowing, but I dont like code what I get:
public function create(Request $request)
{
if (Input::get('title') !== null) {
$v = Validator::make($request->all(), [
'title' => 'required|unique:posts',
'content' => 'required',
]);
if ($v->fails()) {
return redirect()->back()->withErrors($v->errors());
}
$post = new Post(Input::all());
if ($post->save()) {
return redirect('posts');
}
}
return view('add_post');
}
So can somebody give me advice how I need do this properly? Thanks!
One of the most important reason to create two actions is to avoid duplicate form submissions . You can read more about Post/Redirect/Get pattern.
Another important reason is the way you keep the code cleaner. Take a look at this first change:
public function showForm(){
return view('add_post');
}
public function create(Request $request)
{
$v = Validator::make($request->all(), [
'title' => 'required|unique:posts',
'content' => 'required',
]);
if ($v->fails()) {
return redirect()->back()->withErrors($v->errors());
}
$post = new Post(Input::all());
if ($post->save()) {
return redirect('posts');
}
return redirect()->route('show_form')->withMessage();
}
The first thing that you can notice is that create() function is not rendering any view, it is used to manage the creation logic (as the name itself suggests). That is OK if you plan to stay in low-profile, but what happens when you do need to add some others validations or even better, re-utilize the code in other controllers. For example, your form is a help tool to publish a comment and you want to allow only "authors-ranked" users to comment. This consideration can be manage more easily separating the code in specific actions instead making an if-if-if-if spaghetti. Again...
public function showForm(){
return view('add_post');
}
public function create(PublishPostRequest $request)
{
$post = new Post($request->all());
$post->save()
return redirect('posts');
}
Take a look on how PublishPostRequest request takes place in the appropriated function. Finally, in order to get the best of Laravel 5 you could create a request class to keep all the code related with validation and authorization inside it:
class PublishPostRequest extends Request{
public function rules(){
return [
'title' => 'required|unique:posts',
'content' => 'required',
]
}
public function authorize(){
$allowedToPost = \Auth::user()->isAuthor();
// if the user is not an author he can't post
return $allowedToPost;
}
}
One nice thing about custom request class class is that once is injected in the controller via function parameter, it runs automatically, so you do not need to worry about $v->fails()

Laravel 4 database actions - controller or model

just started using Laravel but want to make sure I am using it correctly.
Most of my work is CMS based so read / write / update etc to a database.
An example of what I have done so far is an insertion into the DB:
On the view I have a form with a URL of 'addNewUser'.
In my routes I then do:
Route::post('addnewuser', array('uses' => 'UserController#addNewUser'));
My user controller 'addNewUser' method is (simplified):
public function addNewUser() {
$data = Input::all();
$rules = array(
'username' => 'required|alpha_dash|max:16|unique:users,username',
);
$validator = Validator::make($data, $rules, $messages);
if ($validator->fails())
{
Input::flash();
$errors = $validator->messages();
return Redirect::to('/register')->withErrors($validator)->withInput();
}
$user = new User;
$user->save();
return Redirect::to('/login')->with('successLogin', '1');
}
Is this correct? I have read somewhere that all DB interaction should be in the model?
Likewise when reading from the DB to display a foreach for example, I do the following directly in the view:
$builds = DB::table('blogs')->orderBy('id', 'desc')->get();
if ($builds) {
foreach ($builds as $build)
{
$safeURLSlug = stringHelpers::safeURLSlug($build->blogtitle);
echo "
// stuff
";
}
} else {
// no stuff
}
Should I be doing these sort of queries and showing of data directly in the view? or in a model / controller function etc?
Want to check im doing things 100% correct / the standard way of doing things before I get too involved.
I can see a few things that I personally would have done differently.
For example I usually put $rules as a class variable so it can be used in different functions related to your Users.
Have you tested your code yet? Any errors?
In your addNewUser function does it save any data? I know you have "simplified" above the code snippet but there should be $user->username = $data['username']; etc. in between creating your $user variable and running $user->save();, so if you excluded this on purpose then I don't see anything else with your model.
In your view code, $builds = DB::table('blogs')->orderBy('id', 'desc')->get(); should be done in your controller and passed to your view like so return View::make('example', array('builds' => $builds))
I'd also change
$builds = DB::table('blogs')->orderBy('id', 'desc')->get();
to
$builds = Blog::orderby('id','desc')->get(); if you have a Blog model, otherwise your code is fine.
You could move:
$rules = array(
'username' => 'required|alpha_dash|max:16|unique:users,username',
);
to User model as static variable, and instead of:
$validator = Validator::make($data, $rules, $messages);
you could use:
$validator = Validator::make($data, User::$rules, $messages);
But definitely you shouldn't get data from database in your View, this code should be in controller, for example:
$builds = DB::table('blogs')->orderBy('id', 'desc')->get();
return View::make('someview')->with('builds', $builds);
of course if you have Blog model, you should use here:
$builds = Blog::orderBy('id', 'desc')->get();
return View::make('someview')->with('builds', $builds);
It's also unclear what the following code does:
$safeURLSlug = stringHelpers::safeURLSlug($build->blogtitle);
but probably you could move it to your Blog model and use accessor to make the change:
public function getSafeSlugAttribute($value) {
return stringHelpers::safeURLSlug($this->blogtitle);
}
and now your view could look like this:
#foreach ($builds as $build)
{{{ $build->title }}} {{{ $build->safeSlug }}}
#endforeach
I suggest you take a look on Laravel Generators.
https://github.com/JeffreyWay/Laravel-4-Generators
Install and then run:
php artisan generate:scaffold customer
Laravel line command generator create a basic CRUD for you with controller, model, views and database migrations. That's good to safe time and keep your project with some default organization.

laravel 4.1 storing URL parameter, is it possible?

I'm still a student and still new with these frameworks
so I have two controllers in my routes:
Route::resource('homeworks', 'HomeworkController');
Route::resource('submithomeworks', 'SubmithomeworkController');
in views/Homework/show.blade.php, I have:
href="{{ URL::action('submithomeworks.create', $homeworks->id) }}"
so the URL will go from
http://localhost:8000/homeworks/1
to
http://localhost:8000/submithomeworks/create?1
so is there a way I can just store $homework->id which is just 1 in this situation to the submithomeworks table?
I tried this on the SubmithomeworksController
public function store()
{
$rules = array(
'homework_id' => 'required',
'homework_body' => 'required'
);
$submithomework = new Submithomework;
$submithomework->homework_id = Input::get('homework_id');
$submithomework->homework_body = Input::get('homework_body');
$submithomework->student_id = Auth::user()->id;
$submithomework->save();
Session::flash('message', 'Homework successfully added.');
return Redirect::to('homeworks');
}
but what do I do after that in the view? it won't store the homework_id says its still NULL
If you need to access a route parameter you can use the Route facade. For example:
Route::input('id');
You can check the Laravel Docs.

Laravel 4: Unique(database) not validating

I am creating a basic CMS to teach myself the fundamentals of Laravel and PHP.
I have a 'pages' table and I am storing a url_title. I want this URL title to be unique for obvious reasons. However, whatever I do to validate it, fails. It just saves anyway. I'm sure it is something simple. Can you spot what is wrong with this code?
I am also using Former in the view, that doesn't validate either. I have tried hard-coding a value as the last option in the unique method and it fails also.
http://anahkiasen.github.io/former/
http://laravel.com/docs/validation#rule-unique
States: unique:table,column,except,idColumn
Here is my Controller:
public function store()
{
$validation = Pages::validate(Input::all());
if($validation->fails()) {
Former::withErrors($validation);
return View::make('myview');
} else {
Pages::create(array(
'title' => Input::get('title'),
'url_title' => Input::get('url_title'),
'status' => Input::get('status'),
'body' => Input::get('body'),
'seo_title' => Input::get('seo_title'),
'seo_description' => Input::get('seo_description')
));
//check which submit was clicked on
if(Input::get('save')) {
return Redirect::route('admin_pages')->with('message', 'Woo-hoo! page was created successfully!')->with('message_status', 'success');
}
elseif(Input::get('continue')) {
$id = $page->id;
return Redirect::route('admin_pages_edit', $id)->with('message', 'Woo-hoo! page was created successfully!')->with('message_status', 'success');
}
}
}
Here is my model:
class Pages extends Eloquent {
protected $guarded = array('id');
public static $rules = array(
'id' => 'unique:pages,url_title,{{$id}}'
);
public static function validate($data) {
return Validator::make($data, static::$rules);
}
}
I have tried the following:
public static $rules = array(
// 'id'=> 'unique:pages,url_title,{{$id}}'
// 'id'=> 'unique:pages,url_title,$id'
// 'id'=> 'unique:pages,url_title,:id'
// 'id'=> 'unique:pages,url_title,'. {{$id}}
// 'id'=> 'unique:pages,url_title,'. $id
);
Any ideas? I spoke to the guy who created Former. He can't make head nor tail about it either. He suggested tracking it back to find our what query Laravel uses to check the uniqueness and try running that directly in my DB to see what happens. I can't find the query to do this. Does anyone know where to track it down?
Many thanks
Your rule should be:
public static $rules = array(
'url_title' => 'unique:pages,url_title,{{$id}}'
);
As I guessed from your code Input::get('url_title')
You have to use the field name used in the form.
Thanks peeps. I have been using the Laravel unique solutions and it hasn't been working well. I found this package which solves the issue brilliantly.
https://github.com/cviebrock/eloquent-sluggable#eloquent
Definitely worth a look.
Thanks for your feedback.

Categories