some progress in login forms

This commit is contained in:
Hesabix 2023-11-04 04:39:35 -04:00
parent 3a43694864
commit e7569b0fe9
14 changed files with 187 additions and 34 deletions

View file

@ -14,6 +14,7 @@ security:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
stateless: true
lazy: true
provider: app_user_provider
json_login:
@ -31,7 +32,6 @@ security:
# switch_user: true
logout:
path: front_user_logout
# where to redirect after logout
target: general_home
form_login:
@ -39,6 +39,11 @@ security:
login_path: front_user_login
check_path: front_user_login
enable_csrf: true
custom_authenticator: App\Security\BackAuthAuthenticator
remember_me:
secret: '%kernel.secret%' # required
lifetime: 116121600 # 4 years in seconds
always_remember_me: true
# Easy way to control access for large sections of your site
# Note: Only the *first* access control that matches will be used

View file

@ -5,7 +5,9 @@ use App\Controller\CustomUserMessageAuthenticationException;
use App\Entity\Business;
use App\Entity\Permission;
use App\Form\UserRegisterType;
use App\Security\BackAuthAuthenticator;
use App\Service\Provider;
use App\Service\twigFunctions;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\UserToken;
use Exception;
@ -23,6 +25,7 @@ use Symfony\Component\Form\FormError;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Mime\Address;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Symfony\Component\Security\Http\Authentication\UserAuthenticatorInterface;
use Symfony\Contracts\Translation\TranslatorInterface;
use SymfonyCasts\Bundle\VerifyEmail\Exception\VerifyEmailExceptionInterface;
use Symfony\Component\EventDispatcher\EventDispatcher,
@ -75,10 +78,10 @@ class UserController extends AbstractController
}
#[Route('/register', name: 'front_user_register')]
public function front_user_register(Request $request,TranslatorInterface $translator, UserPasswordHasherInterface $userPasswordHasher, EntityManagerInterface $entityManager): Response
public function front_user_register(twigFunctions $functions,Request $request,TranslatorInterface $translator, UserPasswordHasherInterface $userPasswordHasher, EntityManagerInterface $entityManager): Response
{
//redirect to hesabix app register page
return $this->redirect('https://app.hesabix.ir/user/register');
return $this->redirect($functions->systemSettings()->getAppSite() . '/user/register');
$user = new User();
$form = $this->createForm(UserRegisterType::class, $user);
$form->handleRequest($request);
@ -148,27 +151,33 @@ class UserController extends AbstractController
return $this->redirectToRoute('app_register');
}
#[Route('/login/by/token', name: 'app_login_by_token')]
public function app_login_by_token(Request $request): Response
#[Route('/login/by/token{route}', name: 'app_login_by_token' , requirements: ['route' => '.+'])]
public function app_login_by_token(string $route,AuthenticationUtils $authenticationUtils,twigFunctions $functions,Request $request, UserPasswordHasherInterface $userPasswordHasher, UserAuthenticatorInterface $userAuthenticator, BackAuthAuthenticator $authenticator, EntityManagerInterface $entityManager): Response
{
$token = $entityManager->getRepository(UserToken::class)->findOneBy(['tokenID'=>$request->get('tokenID')]);
if(!$token){
$token = $entityManager->getRepository(UserToken::class)->findOneBy(['token'=>$request->get('tokenID')]);
if(!$token)
throw $this->createNotFoundException('توکن معتبر نیست');
}
// log the user in on the current firewall
$security->login($user);
$userAuthenticator->authenticateUser(
$token->getUser(),
$authenticator,
$request
);
return $this->redirect($functions->systemSettings()->getAppSite() . $route);
}
// if the firewall has more than one authenticator, you must pass it explicitly
// by using the name of built-in authenticators...
$security->login($user, 'form_login');
// ...or the service id of custom authenticators
$security->login($user, ExampleAuthenticator::class);
// you can also log in on a different firewall
$security->login($user, 'form_login', 'other_firewall');
// use the redirection logic applied to regular login
$redirectResponse = $security->login($user);
return $redirectResponse;
// or use a custom redirection logic (e.g. redirect users to their account page)
// return new RedirectResponse('...');
/**
* @throws Exception
*/
#[Route('/logout/by/token{route}', name: 'app_logout_by_token' , requirements: ['route' => '.+'])]
public function app_logout_by_token(string $route,twigFunctions $functions,Request $request,Security $security, EntityManagerInterface $entityManager): Response
{
try {
$security->logout(false);
} catch (Exception $e){}
return $this->redirect($functions->systemSettings()->getAppSite() . $route);
}
}

View file

@ -56,16 +56,16 @@ class UserController extends AbstractController
'message' => 'missing credentials',
], Response::HTTP_UNAUTHORIZED);
}
$tokenString = $this->RandomString(254); // somehow create an API token for $user
$token = new UserToken();
$token->setUser($user);
$token->setToken($tokenString);
$token->setToken($this->RandomString(254));
$token->setTokenID($this->RandomString(254));
$entityManager->persist($token);
$entityManager->flush();
return $this->json([
'user' => $user->getUserIdentifier(),
'token' => $tokenString,
'token' => $token->getToken(),
'tokenID'=> $token->getTokenID()
]);
}

View file

@ -25,6 +25,9 @@ class Settings
#[ORM\Column(length: 255, nullable: true)]
private ?string $zarinpalMerchant = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $appSite = null;
public function getId(): ?int
{
return $this->id;
@ -77,4 +80,16 @@ class Settings
return $this;
}
public function getAppSite(): ?string
{
return $this->appSite;
}
public function setAppSite(?string $appSite): static
{
$this->appSite = $appSite;
return $this;
}
}

View file

@ -20,6 +20,9 @@ class UserToken
#[ORM\JoinColumn(nullable: false)]
private ?User $user = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $tokenID = null;
public function getId(): ?int
{
return $this->id;
@ -48,4 +51,16 @@ class UserToken
return $this;
}
public function getTokenID(): ?string
{
return $this->tokenID;
}
public function setTokenID(?string $tokenID): static
{
$this->tokenID = $tokenID;
return $this;
}
}

View file

@ -4,6 +4,7 @@ namespace App\Repository;
use App\Entity\UserToken;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\NonUniqueResultException;
use Doctrine\Persistence\ManagerRegistry;
/**
@ -40,7 +41,7 @@ class UserTokenRepository extends ServiceEntityRepository
}
/**
* @throws \Doctrine\ORM\NonUniqueResultException
* @throws NonUniqueResultException
*/
public function findByApiToken($value): UserToken | null
{
@ -54,6 +55,18 @@ class UserTokenRepository extends ServiceEntityRepository
;
}
/**
* @throws NonUniqueResultException
*/
public function findByApiTokenID($value): UserToken | null
{
return $this->createQueryBuilder('u')
->andWhere('u.tokenID = :val')
->setParameter('val', $value)
->orderBy('u.id', 'ASC')
->getQuery()
->getOneOrNullResult();
}
// public function findOneBySomeField($value): ?UserToken
// {
// return $this->createQueryBuilder('u')

View file

@ -0,0 +1,92 @@
<?php
namespace App\Security;
use App\Entity\User;
use App\Repository\UserTokenRepository;
use Doctrine\ORM\NonUniqueResultException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\CustomUserMessageAuthenticationException;
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\RememberMeBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
class BackAuthAuthenticator extends AbstractAuthenticator
{
/**
* @var UserTokenRepository
*/
private UserTokenRepository $userTokenRepository;
public function __construct(UserTokenRepository $userRepository)
{
$this->userTokenRepository = $userRepository;
}
public function supports(Request $request): ?bool
{
// TODO: Implement supports() method.
}
/**
* @throws NonUniqueResultException
*/
public function authenticate(Request $request): Passport
{
$apiToken = $request->get('tokenID');
if (null == $apiToken) {
// The token header was empty, authentication fails with HTTP Status
// Code 401 "Unauthorized"
throw new CustomUserMessageAuthenticationException('No API token provided');
}
$tk = $this->userTokenRepository->findByApiTokenID($apiToken);
if (! $tk) {
throw new UserNotFoundException();
}
// TODO: Implement authenticate() method.
return new Passport(
new UserBadge($apiToken, function() use ($apiToken) {
$tk = $this->userTokenRepository->findByApiTokenID($apiToken);
if (! $tk) {
throw new UserNotFoundException();
}
return $tk->getUser();
}),
new PasswordCredentials($tk->getUser()->getPassword()),
[
new RememberMeBadge(),
]
);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
// TODO: Implement onAuthenticationSuccess() method.
return new Response('1');
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{
// TODO: Implement onAuthenticationFailure() method.
return new Response('0');
}
// public function start(Request $request, AuthenticationException $authException = null): Response
// {
// /*
// * If you would like this class to control what happens when an anonymous user accesses a
// * protected page (e.g. redirect to /login), uncomment this method and make this class
// * implement Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface.
// *
// * For more details, see https://symfony.com/doc/current/security/experimental_authenticators.html#configuring-the-authentication-entry-point
// */
// }
}

View file

@ -5,6 +5,7 @@ namespace App\Service;
use App\Entity\ChangeReport;
use App\Entity\Settings;
use Doctrine\ORM\EntityManagerInterface;
class twigFunctions
@ -84,5 +85,8 @@ class twigFunctions
return '0.0.1';
}
public function systemSettings(){
return $this->em->getRepository(Settings::class)->findAll()[0];
}
}

View file

@ -48,8 +48,8 @@
<!-- Right Section -->
<div>
<a href="https://app.hesabix.ir/user/login" class="btn btn-sm btn-primary me-1">ورود</a>
<a href="https://app.hesabix.ir/user/register" class="btn btn-sm btn-success">عضویت</a>
<a href="{{ twigFunctions.systemSettings().appSite }}/user/login" class="btn btn-sm btn-primary me-1">ورود</a>
<a href="{{ twigFunctions.systemSettings().appSite }}/user/register" class="btn btn-sm btn-success">عضویت</a>
</div>
<!-- END Right Section -->

View file

@ -52,7 +52,7 @@
<div class="alert alert-info">
برای ارسال دیدگاه به حساب خود وارد شوید.
<br>
<a href="/login">ورود</a> | <a href="https://app.hesabix.ir/register">عضویت</a>
<a href="/login">ورود</a> | <a href="{{ twigFunctions.systemSettings().appSite }}/register">عضویت</a>
</div>
{% else %}
<div class="rounded bg-light px-2 pt-2 pb-1">

View file

@ -35,7 +35,7 @@
<!-- Footer -->
<ul class="list-inline flex-gow-1 p-5 fs-sm fw-medium mb-0">
<li class="list-inline-item">
<a class="text-muted" href="https://app.hesabix.ir/"> ورود به حسابیکس </a>
<a class="text-muted" href="{{ twigFunctions.systemSettings().appSite }}/"> ورود به حسابیکس </a>
</li>
</ul>
<!-- END Footer -->

View file

@ -10,7 +10,7 @@
<h3 class="mx-5">
متاسفانه پرداخت ناموفق بود!
</h3>
<a class="btn btn-lg btn-success mt-4" href="https://app.hesabix.ir/profile/dashboard">
<a class="btn btn-lg btn-success mt-4" href="{{ twigFunctions.systemSettings().appSite }}/profile/dashboard">
<i class="bi bi-buy"></i>
بازگشت به پروفایل کاربری
</a>

View file

@ -10,7 +10,7 @@
<h3 class="mx-5">
با تشکر از پرداخت شما. سفارش شما اعمال شد.
</h3>
<a class="btn btn-lg btn-success mt-4" href="https://app.hesabix.ir/profile/dashboard">
<a class="btn btn-lg btn-success mt-4" href="{{ twigFunctions.systemSettings().appSite }}/profile/dashboard">
<i class="bi bi-buy"></i>
بازگشت به پروفایل کاربری
</a>

View file

@ -12,7 +12,7 @@
نیاز نیست که هیچگونه نرم افزاری را نصب کنید. کافیست در سایت ثبت نام کرده و بلافاصله کسب و کار خود را مدیریت کنید.
</p>
<div class="d-grid gap-2 d-sm-flex justify-content-sm-center">
<a href="https://app.hesabix.ir/user/login" class="btn btn-primary btn-lg px-4 gap-3">
<a href="{{ twigFunctions.systemSettings().appSite }}/user/login" class="btn btn-primary btn-lg px-4 gap-3">
<i class="fa fa-door-open"></i>
ورود | عضویت رایگان
</a>