I am trying to verify a new user using an email.
app/Http/Controllers/Auth/RegisterController.php
public function register(Request $request)
{
$validator = $this->validator($request->all());
if ($validator->fails())
{
$this->throwValidationException($request, $validator);
}
DB::beginTransaction();
try
{
$user = $this->create($request->all());
$email = new EmailVerification(new User(['email_token' => $user->email_token]));
Mail::to($user->email)->send($email);
DB::commit();
$this->guard()->login($user);
return redirect($this->redirectPath());
}
catch(Exception $e)
{
DB::rollback();
return back();
}
}
public function verify($token)
{
User::where('email_token',$token)->firstOrFail()->verified();
return redirect('/login');
}
routes/web.php
Route::get('register/verify/{token}', 'Auth\RegisterController#verify');
The issue I am having is that the path never gets triggered, even though the email has the correct link. If I remove $this->guard()->login($user); it does activate it, but it doesn't log in and I need it, so the user redirects to a specific page and stays there until the account is being verified.
Any idea what might be the issue?
Related
I'm having a problem that came out of nowhere. I created a login function using JWTAuth and it was working pretty well, the JWTAuth::attempt returns the token that I needed. But after I added the Auto-Hash password function in the User Model, the JWTAuth::attempt always returns false.
I also added softDeletes in the user migration. What causes the JWTAuth::attempt keeps returning false? Because I didn't modify anything except the User Model and the User Migration. How can I fix this problem?
Here is my codes:
Auto-Hash Password Function (User.php Model)
public function setPasswordAttribute($password)
{
$this->attributes['password'] = Hash::make($password);
}
Login Function (AuthController.php Controller)
public function login(Request $request)
{
$credentials = $request->only('email', 'password');
try {
$token = JWTAuth::attempt($credentials);
return response()->json(['status' => 'success','token' => $token], 200);
} catch(Exception $e){
return response()->json(['error' => $e], 401);
}
}
You may use for checking credentials.
$credentials = $request->only('email', 'password');
if (false === ($token = JWTAuth::attempt($credentials))) {
return response()->json(['status' => 'error'], 400);
}
return response()->json(['status' => 'success', 'token' => $token], 200);
Also, just use auto-hash inside your controller or in your service. Maybe your setPasswordAttribute function has some side effects.
In my unit test, I have a user for whom I generate a token:
$tokenString = $this->user->createToken('PHPunit', ['example'])->accessToken;
How can I afterward delete this user's token?
This is what I do when a user logged out.
public function logout() {
Auth::user()->tokens->each(function($token, $key) {
$token->delete();
});
return response()->json('Successfully logged out');
}
This code will remove each token the user generated.
I think something like this can revoke the token:
$this->user->token()->revoke()
Based on this link.
Laravel Sanctum documentation stated 3 different ways to revoke tokens. you can find it here.
but for most cases we just revoke all user's tokens via:
// Revoke all tokens...
auth()->user()->tokens()->delete();
note: for some reason intelephense gives an error saying tokens() method not defined but the code works fine. Hirotaka Miyata found a workaround here.
so the over all logout method can be something like this:
public function logout()
{
//the comment below just to ignore intelephense(1013) annoying error.
/** #var \App\Models\User $user **/
$user = Auth::user();
$user->tokens()->delete();
return [
'message' => 'logged out'
];
}
the best working solution is this
public function logout(LogoutRequest $request): \Illuminate\Http\JsonResponse
{
if(!$user = User::where('uuid',$request->uuid)->first())
return $this->failResponse("User not found!", 401);
try {
$this->revokeTokens($user->tokens);
return $this->successResponse([
], HTTP_OK, 'Successfully Logout');
}catch (\Exception $exception) {
ExceptionLog::exception($exception);
return $this->failResponse($exception->getMessage());
}
}
public function revokeTokens($userTokens)
{
foreach($userTokens as $token) {
$token->revoke();
}
}
public function __invoke(Request $request)
{
$request->user()
->tokens
->each(function ($token, $key) {
$this->revokeAccessAndRefreshTokens($token->id);
});
return response()->json('Logged out successfully', 200);
}
protected function revokeAccessAndRefreshTokens($tokenId) {
$tokenRepository = app('Laravel\Passport\TokenRepository');
$refreshTokenRepository = app('Laravel\Passport\RefreshTokenRepository');
$tokenRepository->revokeAccessToken($tokenId);
$refreshTokenRepository->revokeRefreshTokensByAccessTokenId($tokenId);
}
I am working with Laravel, Vue.js and I am currently using JWT auth for user authentication. I have implemented function for my buttons where I click the up button the vote increases and when I click the down it decreases but the problem is that if I switch user and login with another user I am still able do decrement another user's vote. The user_id in database is still the same and is not updated with new request. I am unable to find the problem please help as I am new to these technologies.
I have tried passing the id manually and then it works sometimes. I guess it is some problem with the authentication or my passing of user_id
this is my vote code:
public function vote(Request $request, $id) {
$issue = Issue::findOrFail($id);
$issueVotes = new \App\IssueVotes();
$issueVotes->user_id = auth()->id();
$issueVotes->issue_id = $request->issue_id;
if($request->vote_type =='up') {
$already_voted = \App\IssueVotes::where('user_id', auth()->id())->where('issue_id', $request->issue_id)->where('vote_type', $request->vote_type)->first();
if(!$already_voted) {
$issue->increment('votes');
$issueVotes->vote_type = $request->vote_type;
$issueVotes->save();
}
} elseif ($request->vote_type =='down') {
$voted_up = \App\IssueVotes::where('user_id', auth()->id())->where('issue_id', $request->issue_id)->where('vote_type', 'up')->first();
if($voted_up) {
#$delete_down = \App\IssueVotes::where('user_id', auth()->id())->where('issue_id', $request->issue_id)->where('vote_type', 'up')->delete();
$issue->decrement('votes');
$issueVotes->vote_type = 'down';
// $issueVotes->save();
}
}
return response()->json($request->post_id, 200);
}
And my JWT auth login code is:
public function login(Request $request)
{
$credentials = $request->json()->all();
try{
if (!$token = JWTAuth::attempt($credentials)){
return response()->json(['error'=>'invalid_credentials'], 400);
}
}catch(JWTException $e) {
return response()->json(['error' => 'could_not_create_token'], 500); // something went wrong whilst attempting to encode the token
}
return response()->json(compact('token'));
}
public function getAuthenticatedUser()
{
try{
if(!$user = JWTAuth::parseToken()->authenticate()){
return response()->json(['user_not_found'], 404);
}
}catch(Tymon\JWTAuth\Exceptions\TokenExpiredException $e){
return response()->json(['token_expired'], $e->getStatusCode());
}catch(Tymon\JWTAuth\Exceptions\TokenInvalidException $e){
return response()->json(['token_invalid'], $e->getStatusCode());
}catch(Tymon\JWTAuth\Exceptions\JWTException $e){
return response()->json(['token_absent'], $e->getStatusCode());
}
return $user;
}
What I am trying to achieve is that only the user who is logged in can change the vote value but of the posts on which he has given votes not on every post.
Here is the screenshot of my database where I switched the user but the user_id remains the same
I have a problem that I wanted to create a reactivate option for users, but after trying several times, it is not working and I am confused.
here is the middleware (original version):
public function handle($request, Closure $next)
{
if (!Auth::check()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('/');
}
}
else
{
$user = Auth::user();
if (!$user->activated) {
$activation = action('Auth\AuthController#getActivationMail', ['username' => $user->username]);
Auth::logout();
return redirect()->guest('auth')
->withErrors(array('message' => 'Please activate your account. Re-send your activation by clicking <a href=' . $activation . '>here</a>.'));
}
else if (!$user->enabled) {
Auth::logout();
return redirect('/auth')->withErrors(array('message' => 'Your account has been deactivated. Please email ... for any inquiries.'))->withInput();
// I tried to add the same method as the above if statement but not working here
}
$user->runDailyNotifications();
}
return $next($request);
}
I wanted to update my database using this way:
$user = Auth::user();
$user->enabled = 1;
$user->save();
which should be working fine.
I am new to Laravel. At first, I added these code in the middleware (which is a mistake).
After trying a bit I know it is impossible for it to work (when users click login twice they will log in after deactivating their account). Now I'm just wondering how could I achieve that since I kept getting error messages from everywhere. Thank you for the help!
I have done email confirmation and resend confirmation in one of my older projects. I've done the email confirmation validation in the post login check in the LoginController. Let me post you some snippets which might help you.
// Overwrite the authenticated method in LoginController
protected function authenticated(Request $request, $user)
{
if ($user->isBanned()) {
$this->logout($request);
flashError('Your account has been banned.');
return back();
}
if (!$user->isEmailConfirmed()) {
$this->logout($request);
flashWarning('Email confirmation pending. Click here to resend confirmation email.');
return back();
}
return redirect()->route($this->redirectRoute);
}
public function resendConfirmationEmail(Request $request, User $user)
{
//resend confirmation email
}
public function confirmEmail(Request $request, $token)
{
// Validate the token and update the user email confirmation status
}
Model
public function isBanned()
{
return (bool) $this->banned;
}
public function isEmailConfirmed()
{
return (bool) $this->confirmed;
}
Route
Route::get('confirm/resend/{user}', 'Auth\RegisterController#resendConfirmationEmail')->name('confirm.resend');
Route::get('confirm/email/{token}', 'Auth\RegisterController#confirmEmail')->name('confirm.email');
I wanted to find out how I would do as requested in the subject line, as the code below works fine but the user is logged in before checking the $user->Activated status. Here is some code to illustrate:
AuthController
public function authenticated(Request $request, User $user)
{
if ($user->Activated) {
return redirect()->intended($this->redirectPath());
} else {
Auth::logout();
return redirect($this->loginPath())
->withInput($request->only('email', 'remember'))
->withErrors([
'activated' => 'You need to activate your account to login'
]);
}
}
Preferably I would like to do the following:
AuthController
public function getCredentials(Request $request)
{
$credentials = $request->only($this->loginUsername(), 'password');
return array_add($credentials, 'Activated', '1');
}
But then the only message that gets returned is "These credentials do not match our records.", instead of "You need to activate your account to login". Also how would I update a LoginStatusId once the user is logged in, currently I do it like this:
AuthController
public function authenticated(Request $request, User $user)
{
if ($user->Activated) {
$user->LoginStatusId = 1;
$user->save();
return redirect()->intended($this->redirectPath());
} else {
Auth::logout();
return redirect($this->loginPath())
->withInput($request->only('email', 'remember'))
->withErrors([
'activated' => 'You need to activate your account to login'
]);
}
}
Is there a better place to set the $user->LoginStatusId once they login, or is this the best place to put it?
Open this file vendor\laravel\framework\src\Illuminate\Foundation\Auth\AuthenticatesUsers.php
Add this block of code inside postLogin
// If activated is equal to 1, user allowed to login or throw an credential mismatch error
$userData = User::select('activated')->where('email', $request['email'])->first();
if ($userData->activated == 1) {
$request['activated'] = $activated;
}
$credentials = $this->getCredentials($request); //add these code before this line
And add 'activated' to getCredentials method. It will look like this:
protected function getCredentials(Request $request)
{
return $request->only($this->loginUsername(), 'password', 'activated');
}
You can check user login status anywhere just using this Auth::user(). No need to store login status by yourself. As example in any controller you can write this:
if(Auth::user()){
// do this;
}else{
// do that;
}