I am naive of Laravel and Vue.js. I'm using JWT authentication for my backend and VueX for the frontend. I want the user able to change their picture, name and email but I got an error when I try to save. and for your information, I try to edit and save name and email first, update the picture will do after this.
My Profile page and this is the error that I received. here is my code:
<template>
<div class="container" style="padding-top:25px">
<div class="main-font">My Profile</div>
<div class="d-flex row">
<div class="col-6">
<ValidationObserver v-slot="{ handleSubmit }">
<form @submit.prevent="handleSubmit(updateProfile)">
<div class="d-flex py-4">
<!-- <img class="profile" src="/img/profile.jpg" alt="" > -->
<div>
<template v-if="!currentUser.profile_image_url" >
<img class="profile" src="/img/default.png" alt="">
</template>
<template v-else>
<div class="profile">{{currentUser.profile_image_url}}</div>
</template>
</div>
<div class="my-auto ml-5">
<button type="submit" class="btn upload text"><i class="fas fa-upload fa-sm pr-2"></i>Upload new picture</button>
</div>
</div>
<div class="form-group col-10 p-0 m-0">
<ValidationProvider name="Name" rules="required|alpha" v-slot="{ errors }">
<label class="text">Name</label>
<input type="text" id="name" class="form-control form-text" placeholder="Enter your username" v-model="userForm.name">
<span class="error-messsage">{{ errors[0] }}</span>
</ValidationProvider>
<!-- <small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small> -->
</div>
<div class="form-group col-10 p-0 m-0 mt-4">
<ValidationProvider name="E-mail" rules="required|email" v-slot="{ errors }">
<label class="text">Email</label>
<input type="email" id="email" class="form-control form-text" placeholder="Enter email" v-model="userForm.email">
<span class="error-messsage">{{ errors[0] }}</span>
</ValidationProvider>
</div>
<button type="submit" class="btn col-10 p-o save-but">SAVE CHANGES</button>
</form>
</ValidationObserver>
</div>
<div class="w-50">
<img class="bg-img" src="/img/profile-bg.png" alt="">
</div>
</div>
</div>
script:
<script>
import { ValidationProvider, ValidationObserver, extend } from 'vee-validate/dist/vee-validate.full';
export default {
components: {
ValidationProvider,
ValidationObserver,
},
data() {
return {
userForm: {
name: '',
email: '',
},
error: null,
}
},
watch: {
created () {
this.userForm = JSON.parse(JSON.stringify(this.$store.getters.currentUser));
},
computed: {
currentUser(){
return this.$store.getters.currentUser;
},
},
methods: {
// updateProfile (){
// this.$store.dispatch('updateUser');
// var _this = this;
// // ajax call to POST this.profile then
// _this.$store.commit('update',
// {
// // name: 'currentUser',
// data: this.userForm
// })
// },
getUser (){
const token = localStorage.getItem('token')
axios.get('/api/auth/userprofile',{
headers: {
Authorization: `Bearer ${token}`
}
})
.then(response => {
this.userForm= response.data.user;
// this.userForm.email = response.data.user.email;
})
},
updateProfile () {
axios.put('/update-profile',
{
name: this.userForm.name,
email: this.userForm.email,
})
.then(response => {
this.userForm.name = response.data.name;
this.userForm.email = response.data.email;
swal({
icon: "success",
text: "Update Succesfully!",
});
})
}
}
}
</script>
controller:
<?php
namespace App\Http\Controllers;
use JWTAuth;
use Illuminate\Support\Facades\Validator;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Exceptions\JWTException;
use Illuminate\Support\Facades\Auth;
use App\Models\User;
use Symfony\Component\HttpFoundation\Response;
use Illuminate\Support\Facades\DB;
use Tymon\JWTAuth\Facades\JWTAuth as FacadesJWTAuth;
use App\Http\Requests\Users\UpdateProfileRequest;
class AuthController extends Controller
{
public $token = true;
public function __construct()
{
$this->middleware('auth:api', ['except' => ['login', 'register']]);
}
public function register(Request $request)
{
$validator = Validator::make($request->all(),
[
'name' => 'required',
'email' => 'required|email',
'password' => 'required',
]);
if ($validator->fails()) {
return response()->json(['error'=>$validator->errors()], 401);
}
$user = new User();
$user->name = $request->name;
$user->email = $request->email;
$user->password = bcrypt($request->password);
$user->save();
if ($this->token) {
return $this->login($request);
}
return response()->json([
'success' => true,
'data' => $user
], Response::HTTP_OK);
}
public function login(Request $request)
{
$input = $request->only('email', 'password');
$jwt_token = null;
if (!$jwt_token = JWTAuth::attempt($input)) {
return response()->json([
'success' => false,
'message' => 'Invalid Email or Password',
], Response::HTTP_UNAUTHORIZED);
}
// return response()->json([
// 'success' => true,
// 'token' => $jwt_token,
// ]);
return $this->respondWithToken($jwt_token);
}
public function logout(Request $request)
{
$this->validate($request, [
'token' => 'required'
]);
try {
JWTAuth::invalidate($request->token);
return response()->json([
'success' => true,
'message' => 'User logged out successfully'
]);
} catch (JWTException $exception) {
return response()->json([
'success' => false,
'message' => 'Sorry, the user cannot be logged out'
], Response::HTTP_INTERNAL_SERVER_ERROR);
}
}
//update user profile
// public function updateProfile(UpdateProfileRequest $request)
// {
// $user = Auth::user();
// $jwt_token = auth('api')->tokenById($user->id);
// $input = $request->all();
// if ($jwt_token) {
// // $user = Auth::user();
// // $users = $user->user;
// $user->name = $request->input('name', '');
// $user->email = $request->input('email', '');
// $user->save();
// }
// // $user->update($request->all());
// // return ['message' => 'Updated the user info'];
// return $this->respondWithToken($jwt_token);
// }
public function updateProfile(UpdateProfileRequest $request)
{
DB::transaction(function() use ($request){
$user = Auth::user();
$user->name = $request->input('name','');
$user->email = $request->input('email','');
$user->save();
});
// $user->update([
// 'name' => $request->name,
// 'email' => $request->email,
// ]);
return ['message' => 'Updated the user info sucessfully!'];
}
public function userProfile()
{
// return response()->json(auth()->user());
$user = auth('api')->user();
$token = auth('api')->tokenById($user->id);
return response([
'user' => $user,
'token' => $token
]);
// return $this->respondWithToken($token);
}
public function getUser(Request $request)
{
$this->validate($request, [
'token' => 'required'
]);
$user = JWTAuth::authenticate($request->token);
return response()->json(['user' => $user]);
}
// Refresh a token.
public function refresh()
{
return $this->respondWithToken(JWTAuth::refresh());
}
// Get the token array structure
protected function respondWithToken($token)
{
return response()->json([
'access_token' => $token,
'user' => $this->guard()->user(),
'token_type' => 'bearer',
'expires_in' => JWTAuth::factory()->getTTL() * 60
]);
}
public function guard() {
return Auth::Guard('api');
}
}
routes:
Route::put('/update-profile', [AuthController::class, 'updateProfile']);
store.js
import {getLoggedinUser} from './auth';
const user = getLoggedinUser();
export default {
state: {
currentUser: user,
isLoggedin: !!user,
loading: false,
auth_error: null,
reg_error:null,
registeredUser: null,
update: null,
},
getters: {
isLoading(state){
return state.loading;
},
isLoggedin(state){
return state.isLoggedin;
},
currentUser(state){
return state.currentUser;
},
authError(state){
return state.auth_error;
},
regError(state){
return state.reg_error;
},
registeredUser(state){
return state.registeredUser;
},
update(state){
return state.update;
}
},
mutations: {
login(state){
state.loading = true;
state.auth_error = null;
},
loginSuccess(state, payload){
state.auth_error = null;
state.isLoggedin = true;
state.loading = false;
state.currentUser = Object.assign({}, payload.user , {token: payload.access_token});
localStorage.setItem("user", JSON.stringify(state.currentUser));
},
loginFailed(state, payload){
state.loading = false;
state.auth_error = payload.error;
},
logout(state){
localStorage.removeItem("user");
state.isLoggedin = false;
state.currentUser = null;
},
registerSuccess(state, payload){
state.reg_error = null;
state.registeredUser = payload.user;
},
registerFailed(state, payload){
state.reg_error = payload.error;
},
// update(state, payload) {
// state.currentUser = payload.data;
// }
},
actions: {
login(context){
context.commit("login");
},
// updateUser(context) {
// const token = localStorage.getItem('token')
// axios.put('/api/auth/update-profile', {
// headers:
// {
// Authorization: `Bearer ${token}`
// }
// })
// .then((response) => {
// context.commit('update', response.data);
// })
// }
}
};
auth.js
import { setAuthorization } from "./general";
export function registerUser(credentials){
return new Promise((res,rej)=>{
axios.post('/api/auth/register', credentials)
.then(response => {
res(response.data);
})
.catch(err => {
rej('An error occured.. try again later.')
})
})
}
export function login(credentials){
return new Promise((res,rej)=>{
axios.post('/api/auth/login', credentials)
.then(response => {
// setAuthorization(response.data.access_token);
res(response.data);
})
.catch(err => {
rej('Wrong Email/Password combination.')
})
})
}
export function getLoggedinUser(){
const userStr = localStorage.getItem('user');
if(!userStr){
return null
}
return JSON.parse(userStr);
}
The login and register function are working well just the profile cannot be updated. Please help me if you have any solution or ideas.
For update profile method, Bearer token need to pass to axios request as well.
updateProfile () {
const token = this.$store.getters.currentUser.token // get the token from state
axios.put('/update-profile',
{
name: this.userForm.name,
email: this.userForm.email,
},
{
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json" // add content-type
}
})
.then(response => {
this.userForm.name = response.data.name;
this.userForm.email = response.data.email;
swal({
icon: "success",
text: "Update Succesfully!",
});
})
}
P.S. If you want axios to include Bearer token in all requests at all time without specify it on each request, you can axios.defaults.headers
but it is another topic