Laravel client authentification with external Laravel passport lumen api - laravel

I have been looking online but i can't find any way of doing it. Let me explain, i have an API (Laravel passport on lumen), i tested it with Postman, i get my access token with oauth, everything is fine. Now i have another Laravel application and i want to know how i can keep all my authentification stuff using the API to login. I have seen lot of apps that actualy retrieve an api_token and they use 'Auth::user()->where('api_token', $token)'. But i find this wrong because i don't want my client to have access to the database, i want every request to the database to be handled by the API. Is that possible?

Let say you want to login to a laravel backend app via api. make sure you install guzzle.
Route(api): Route::POST('/login', 'AuthController#login')
Controller: AuthController.php
public function login(Request $request)
{
$this->validate($request, [
'email' => 'required|email',
'password' => 'required|string',
]);
$http = new \GuzzleHttp\Client;
try {
$response = $http->post(config('services.passport.login_endpoint'), [
'form_params' => [
'grant_type' => 'password',
'client_id' => 'your client_id',
'client_secret' => 'your client_secret',
'username' => $request->email,
'password' => $request->password,
// 'scope' => '',
],
]);
return $response->getBody();
} catch (\GuzzleHttp\Exception\BadResponseException $e) {
if ($e->getCode() == 401) {
return response()->json(['message' => 'This action can\'t be perfomed at this time. Please try later.'], $e->getCode());
} else if ($e->getCode() == 400) {
return response()->json(['message' => 'These credentials do not match our records.'], $e->getCode());
}
return response()->json('Something went wrong on the server. Please try letar.', $e->getCode());
}
}
In your front-end app for example vuejs, even laravel using vue component. As you can see, i'm using boostrap-vue but feel free to use the regular html elements
<template>
<div>
<form #submit.prevent="login()">
<b-form-group label="Email">
<b-input placeholder="E-Mail" class="ml-1" v-model="form.email" type="email" name="email" :class="{ 'is-invalid': form.errors.has('email') }"/>
<has-error :form="form" field="email"></has-error>
</b-form-group>
<b-form-group>
<div slot="label" class="d-flex justify-content-between align-items-end">
<div>Password</div>
Forgot password?
</div>
<b-input v-model="form.password" type="password" name="password" :class="{ 'is-invalid': form.errors.has('password') }" />
<has-error :form="form" field="password"></has-error>
</b-form-group>
<div class="d-flex justify-content-between align-items-center m-0">
<b-check v-model="form.rememberMe" class="m-0">Remember me</b-check>
<b-btn type="submit" variant="primary">Sign In</b-btn>
</div>
</form>
</div>
<template>
<script>
export default ({
name: 'pages-authentication-login-v2',
metaInfo: {
title: 'Login'
},
state: {
token: localStorage.getItem('access_token'),
},
mutations: {
login(state, token) {
state.token = token
},
},
data: () => ({
form: new Form({
email: '',
password: '',
})
}),
methods: {
login(){
this.form.post('/api/login')
.then((response) =>{
const token = response.data.access_token
localStorage.setItem('access_token', token)
// console.log(response);
this.$router.push('/dashboard');
})
.catch((error)=>{
this.$toasted.error('Ooops! Something went wrong', {
icon : "warning",
theme: "bubble",
closeOnSwipe: true,
position: "top-right",
duration : 5000,
singleton: true,
})
});
},
}
})
</script>

Related

Uncaught (in promise) csrf Vue js laravel

i am creating the login form in vuejs.i tested through postman api working well. when i check with vue js validtaion it is not working.login Error,Uncaught (in promise) csrf Vue js laravel.
what i tried so far i attached below.i think the json validation problem can you check it.i attached the full source code below.
Login.vue
<template>
<div class="row">
<div class="col-sm-4" >
<h2 align="center"> Login</h2>
<form #submit.prevent="LoginData">
<input type="hidden" name="_token" :value="csrf">
<div class="form-group" align="left">
<label>Email</label>
<input type="email" v-model="student.email" class="form-control" placeholder="Mobile">
</div>
<div class="form-group" align="left">
<label>Password</label>
<input type="password" v-model="student.password" class="form-control" placeholder="Mobile">
</div>
<button type="submit" class="btn btn-primary">Login</button>
</form>
</div>
</div>
</template>
<script>
import Vue from 'vue';
import axios from 'axios';
Vue.use(axios)
export default {
name: 'Registation',
data () {
return {
csrf: document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
result: {},
student:{
email: '',
password: ''
}
}
},
created() {
},
mounted() {
console.log("mounted() called.......");
},
methods: {
LoginData()
{
axios.post("http://127.0.0.1:8000/api/login", this.student)
.then(
({data})=>{
console.log(data);
try {
if (data === true) {
alert("Login Successfully");
this.$router.push({ name: 'HelloWorld' })
} else {
alert("Login failed")
}
} catch (err) {
alert("Error, please try again");
}
}
)
}
}
}
</script>
LoginController
public function check(Request $request)
{
$credentials = $request->validate([
'email' => ['required', 'email'],
'password' => ['required'],
]);
if (Auth::attempt($credentials))
{
return response()->json(['data' => true ]);
}
return response()->json(['data' => 'Fail']);
}
}
According to Laravel 9 docs you have to send csrf token. Here's the link that talk about it:
https://laravel.com/docs/9.x/sanctum#csrf-protection

The GET method is not supported for this route. Supported methods: POST. when i want to input data

I tried to solve this Laravel - Vue input problem and I can't find the solution. I follow my teacher's tutorial and it's work. But when I tried mine and open the console, I found it show error with message :
`Access to XMLHttpRequest at 'http://localhost/lat_laravel-vue1/public/api/siswa/tambahsiswa' from origin 'http://localhost:8080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.`
and when I click the Laravel's link, it show me an error message
"The GET method is not supported for this route. Supported methods: POST.".
I use Laravel 5.8 version.
https://i.stack.imgur.com/0z6C2.png
Laravel Controller
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\siswaModel;
use Illuminate\Support\Facades\Validator;
header('Access-Control-Allow-Origin: *');
class siswaController extends Controller
{
public function simpan(Request $req)
{
$validator = Validator::make($req->all(), [
'nama_siswa' => 'required',
'tanggal_lahir' => 'required',
'gender' => 'required',
'id_kelas' => 'required'
]);
if ($validator->fails()) {
return Response()->json($validator->errors());
}
$simpan = siswaModel::create([
'nama_siswa' => $req->nama_siswa,
'tanggal_lahir' => $req->tanggal_lahir,
'gender' => $req->gender,
'id_kelas' => $req->id_kelas,
'alamat' => $req->alamat
]);
if ($simpan) {
$data['status'] = true;
$data['message'] = "Sukses Menambahkan Siswa";
} else {
$data['status'] = false;
$data['message'] = "Gagal Menambahkan Siswa";
}
return $data;
}
}
Routes
Route::post('/tambahsiswa', 'siswaController#simpan');
Vue file
<div class="container">
Nama Siswa
<input type="text" name="nama_siswa" v-model="nama_siswa" class="form-control">
<br>
Tanggal Lahir
<input type="date" name="tanggal_lahir" v-model="tanggal_lahir" class="form-control">
<br>
Gender
<select name="gender" v-model="gender" class="form-control">
<option></option>
<option v-for="gender in listgender" :key="gender.key" value="{{gender.key}}">{{gender.val}}</option>
</select>
<br>
Alamat
<textarea rows="4" class="form-control" v-model="alamat" name="alamat"></textarea>
<br>
Kelas
<select name="kelas" v-model="kelas" class="form-control">
<option></option>
<option v-for="kelas in listkelas" :key="kelas.id" value="{{kelas.id}}">{{kelas.nama_kelas}}</option>
</select>
<br>
<button class="btn btn-primary" #click="simpansiswa()">Simpan</button>
</div>
</template>
<script>
export default {
name: "Tambahsiswa",
data() {
return {
'listgender': [
{ key: 'L', val: 'Laki-laki' },
{ key: 'P', val: 'Perempuan' }
],
listkelas: [],
nama_siswa: '',
tanggal_lahir: '',
gender: '',
alamat: '',
kelas: '',
}
},
methods: {
getkelas:function() {
this.axios.get('http://localhost/lat_laravel-vue1/public/api/getkelas').then((result) => {
this.listkelas = result.data
})
},
simpansiswa:function() {
var datasiswa = {
nama_siswa: this.nama_siswa,
tanggal_lahir: this.tanggal_lahir,
gender: this.gender,
alamat: this.alamat,
id_kelas: this.kelas
}
this.axios.post('http://localhost/lat_laravel-vue1/public/api/siswa/tambahsiswa', datasiswa).then((result) => {
console.log(result)
})
}
},
mounted(){
this.getkelas();
}
}
</script>```
Are your Laravel and Vue is in one project ?
No : Laravel 5.8 default has no CORS. Can you check installed any package to config CORS ?
Yes : Try using Axios with CDN instead of javascript package and post data again.
https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js

Call to a member function store() on null on Laravel with Nuxt

I am currently having issues saving in Laravel from my Nuxt Application. I tried to perform the creating data from my postman and it works. I don't know what I missing here.
Controller
$book = Book::create([
'name' => $request->name,
'about' => $request->about,
// dd($request->file('image')),
'image' => $request->file('image')->store('images'),
]);
In my Nuxt template I have this
<form method="POST" enctype="multipart/form-data" #submit.prevent="save">
<div class="form-group">
<label for="name">Book Name</label>
<input
id="name"
v-model="editedItem.name"
type="text"
class="form-control"
placeholder="Book Name"
>
</div>
<div class="form-group">
<label for="image">Upload Book Cover</label>
<input
id="image"
name="image"
type="file"
accept="image/*"
class="form-control-file"
#change="onUpload"
>
</div>
<button type="submit" class="btn btn-primary">
Create Book
</button>
</form>
My nuxt methods
async save () {
try {
const formData = new FormData()
formData.append('name', this.editedItem.name)
formData.append('image', this.editedItem.imageurl.name)
await this.$axios.post('http://127.0.0.1:8000/api/createbookapi',
formData,
{
headers: {
enctype: 'multipart/form-data'
}
}
)
},
onUpload (e) {
this.editedItem.imageurl = e.target.files[0]
},
data: () => ({
editedItem: {
name: '',
imageurl: ''
}),
When I tried to save using postman, it works.
I don't know what I am missing here.
Call to a member function store() on null
becouse your file is null to avoid this add validation or make it optional
example of optional image
make sure database field is nullable
$book = Book::create([
'name' => $request->name,
'about' => $request->about,
'image' => $request->hasFile('image')
? $request->file('image')->store('images')
: null,
]);
for validation example
'image' => 'required|file', // it should check for file because file have class have store method

Foreign key on post request Laravel & Vue

I am using a larvel backend with a vue frontend. They are connected by API. I have been trying to figure out how i can correctly submit a form for a model that has a foreign_key relationship with a parent model.
Here is the relationships
A User has many Tasks
A Task belongs to User
A Client has many Engagements
A Engagement belongs to Client
Engagements and Tasks have many to many
User and Client have no direct relationship
So I know that if i wanted to submit a post request for data that had a relationship with user It would be simple to assign the foreign_key like below
*Example
public function store(Request $request)
{
$data = $request->validate([
'title' => 'required|string',
'completed' => 'required|boolean',
]);
$todo = Todo::create([
'user_id' => auth()->user()->id,
'title' => $request->title,
'completed' => $request->completed,
]);
return response($todo, 201);
}
But when i try to do this same thing for my client I get a 500 internal server error..
So here is the Workflow
On my vue frontend in the AddEngagment.vue component
<template>
<div class="page-wrapper mt-1">
<div class="add-engagement container">
<div class="card-body bg-light border-primary mb-2">
<h4 class="text-left text-primary m-0"><i class="mr-3 far fa-folder-open"></i>New Engagement</h4>
</div>
<form #submit.prevent="addEngagement" class="d-flex-column justify-content-center">
<div class="form-group">
<select class="form-control mb-3" id="type" v-model="engagement.return_type">
<option v-for="type in types" :key="type.id" :value="type">{{ type }}</option>
</select>
<input type="text" class="form-control mb-3" placeholder="Year" v-model="engagement.year">
<input type="text" class="form-control mb-3" placeholder="Assign To" v-model="engagement.assigned_to">
<input type="text" class="form-control mb-3" placeholder="Status" v-model="engagement.status">
<button type="submit" class="btn btn-lg btn-primary d-flex justify-content-start">Create</button>
</div>
</form>
</div>
</div>
</template>
<script>
export default {
name: 'add-engagement',
data() {
return {
engagement: {
return_type: null,
year: '',
assigned_to: '',
status: '',
},
types: [
'Choose Return Type...',
'1040',
'1120',
],
}
},
methods: {
addEngagement(e) {
if(!this.engagement.return_type || !this.engagement.year ){
return
} else {
this.$store.dispatch('addEngagement', {
id: this.idForEngagement,
return_type: this.engagement.return_type,
year: this.engagement.year,
assigned_to: this.engagement.assigned_to,
status: this.engagement.status,
})
e.preventDefault();
}
e.preventDefault();
this.engagement = ""
this.idForEngagement++
this.$router.push('/engagements')
},
},
created: function() {
this.engagement.return_type = this.types[0]
},
}
</script>
I am capturing the data in the input and then dispatching the store for the addEngagement action
Now in the URL for the AddEngagement.vue component I have the client_id shown like below
add-engagement/{client_id}
This is the store.js action for the addEngagement
addEngagement(context, engagement) {
axios.post(('/engagements'), {
return_type: engagement.return_type,
year: engagement.year,
assigned_to: engagement.assigned_to,
status: engagement.status,
done: false
})
.then(response => {
context.commit('getClientEngagement', response.data)
})
.catch(error => {
console.log(error)
})
},
So from here, it sends the request to my /engagement on the laravel api route file like below
Route::post('/engagements', 'EngagementsController#store');
And then goes to the EngagementsController to run the store method below
public function store($client_id, Request $request)
{
$data = $request->validate([
'return_type' => 'required|string',
'year' => 'required|string',
'status' => 'required|string',
'assigned_to' => 'required|string',
'done' => 'required|boolean'
]);
$engagement = Engagement::create([
'return_type' => $request->return_type,
'year' => $request->year,
'assigned_to' => $request->assigned_to,
'status' => $request->status,
'done' => $request->done,
+ [
'client_id' => $client_id
]
]);
return response($engagement, 201);
}
At this point is where I am getting my error and I think it has to do with the $client_id which I have tried many different ways of formatting it with no success. When the URL is storing the client_id on the front end for the post request I do not know how that data is getting shared with laravel for it to know which client the client_id foreign key will be assigned to.
First of all:
$engagement = Engagement::create([
'return_type' => $request->return_type,
'year' => $request->year,
'assigned_to' => $request->assigned_to,
'status' => $request->status,
'done' => $request->done,
+ [
'client_id' => $client_id
]
]);
why is there this +[...] array thing? Doesn't really makes sense to me...
But the 500 Server Error most probably results from your false request (which most of 500's do).
If this is your Route definition:
Route::post('/engagements', 'EngagementsController#store');
This is the method head:
public function store($client_id, Request $request)
And your Post request is the following:
axios.post(('/engagements'), {
return_type: engagement.return_type,
year: engagement.year,
assigned_to: engagement.assigned_to,
status: engagement.status,
done: false
})
You will notice, that the function definition differs from your Route. In the function you expect a parameter 'client_id' which isn't known by the route. So to resolve this issue, put your client_id into the Post request body (underneath your done: false for example) and remove the parameter from the function definition.

see the server error after ajax request with laravel

i receive the 500 (Internal Server Error) after make a ajax request on laravel 5.2.
as I can see what is wrong?
at some point I saw that there is a command that starts with tails, but can not find it.
thanks.
code:
html:
<form role="form" id="Login" >
{{ csrf_field() }}
<label >Correo electronico: </label>
<input id="correo" type="email" class="form-control" name="email" placeholder="Enter email">
<id id="emailError"></id>
<label >ContraseƱa:</label>
<input id="password" type="password" class="form-control" name="password" placeholder="Enter password">
<id id="passwordError"></id>
<button type="button" class="btn btn-default" id="Submit" onclick="LogIn(event)" >Iniciar sesion</button>
</form>
js:
function LogIn(event) {
event.preventDefault();
$.ajax({
type: 'post',
url: Login,
dataType: 'json',
data: {
email: $('#correo').val(),
password: $('#password').val(),
},
beforeSend: function()
{
$("#emailError").fadeOut();
$("#passwordError").fadeOut();
},
success: function (data) {
if (!data.success){
console.log(data);
if(typeof data.error.email !== 'undefined'){
$('#correo').css('border-color', 'red');
$('#emailError').fadeIn(10, function () {
$("#emailError").html(data.error.email);
})
}
if(typeof data.error.password !== 'undefined'){
$('#password').css('border-color', 'red');
$('#passwordError').fadeIn(10, function () {
$("#passwordError").html(data.error.password[0]);
})
}
}else{
console.log(data);
$('#LogIn').modal('hide');
}
}
});
}
Controller:
<?php
namespace App\Http\Controllers;
use App\Modals\Users;
use Illuminate\Http\Request;
use Validator;
use App\Http\Controllers\Controller;
use App\Http\Requests;
use App\Modals\Users as user;
use Auth;
class UserController extends Controller
{
public function index()
{
return view('home');
}
/**
* #param Request $request
* #return \Illuminate\Http\JsonResponse
*/
public function entrar (Request $request){
$validator= Validator::make($request->all(),[
'email' => 'required|email',
'password' => 'required|min:2',
]);
if ($validator->fails()){
return response()->json([
'success' => true,
'error' => $validator->errors()->toArray()
]);
}else{
return response()->json([
'success' =>true
]);
}
if (Auth::attempt(['email' => $request->email, 'password' => $request->password]))
{
return response()->json([
'success' => true
]);
}else
{
return response()->json([
'success' => false,
'error' => 'not login'
]);
}
}
}
log:
POST http://localhost:8000/Entrar 500 (Internal Server Error) jquery.min.js:4
send # jquery.min.js:4
ajax # jquery.min.js:4
LogIn # scripts.js:82
onclick # VM18805:87

Resources