How to use JWT in Yii2 project? - yii2

In my REST API i want to use JWT fro Authorization.
So, I include this extension - https://github.com/sizeg/yii2-jwt
It clear how to create JWT token, but how to validate Token in API side ? I heart, i must use two tokens - auth_token and refresh_token. For what? What different when i whatt to validate and check user ?
I mean - ok, when i receive username and password, I create auth_token (JWT) and update token in users DB, after i return token to frontend.
After frontend will send auth token in each request, and I will validate token and check user in users DB and check access etc. How to realize refresh token and for what?
For example my controller:
class UploadController extends Controller {
public $serializer = [
'class' => 'yii\rest\Serializer',
'collectionEnvelope' => 'items',
];
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => JwtHttpBearerAuth::className()
];
return $behaviors;
}
public function actionIndex() {
//Work with User
}
}
And how to get token from headers ?

Controller
public function actionLogin()
{
$username = Yii::$app->request->post('username');
$password = Yii::$app->request->post('password');
$provider = new ActiveDataProvider([
'query' => User::find()
->where(['user_name' => $username])->asArray()->one(),
]);
$result = $provider->query;
if($result)
{
if (Yii::$app->getSecurity()->validatePassword($password, $result['user_pass']))
{
$tokenId = base64_encode(mcrypt_create_iv(32));
$issuedAt = time();
$notBefore = $issuedAt; //Adding 10 seconds
$expire = $notBefore + 5184000; // Adding 60 Days
$serverName = 'your-site.com';
$data = [
'iat' => $issuedAt, // Issued at: time when the token was generated
'jti' => $tokenId, // Json Token Id: an unique identifier for the token
'iss' => $serverName, // Issuer
'nbf' => $notBefore, // Not before
'exp' => $expire, // Expire
'data' => [ // Data related to the signer user
'id' => $result['user_id'],
'username' => $result['user_name'],
'mobile' => $result['user_mobile'],
'email' => $result['user_email'],
'city' => $result['user_city'],
'state' => $result['user_state'],
'country' => $result['user_country'],
'picture' => $result['user_picture'],
]
];
$jwt = JWT::encode(
$data,
JWT_KEY,
'HS512'
);
$response = [
'status' => true,
'message' => 'Login Success..',
'era_tkn' => $jwt,
];
}
else
{
$response = [
'status' => false,
'message' => 'Wrong username or password.',
];
}
}
else
{
$response = [
'status' => false,
'message' => 'Wrong username or password.',
];
}
return $response;
}
Make global method for check token
public function check_token()
{
$headers = Yii::$app->request->headers;
$token = $headers->get('era_tkn');
if($token)
{
try{
$valid_data = JWT::decode($token, JWT_KEY, array('HS512'));
$valid_data = $valid_data->data;
}catch(Exception $e){
$valid_data = $e->getMessage();
}
}
else
{
$valid_data = 'Required Authentication';
}
return $valid_data;
}
Call check_token mathod
$user_data = $this->check_token();
if (!empty($user_data->id))
{
echo $user_data->id;
}
else
{
echo "Invalid Token.";
}

Related

can't post data to Laravel API from flutter dio pakage Formdata

i had a problem on my RESTAPI. i'm working with backend that makes the API, but i can't post data to the server. due to the error that appears on my debug console. here's the REST-API end-point source code.
`
class PeminjamanController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$data = Peminjaman::all();
return response()->json(['Data User : ', PeminjamanResource::collection($data) ], Response::HTTP_OK);
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create($id)
{
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request, $id)
{
try {
//code...
$data = Request()->all();
if( $id == 1) {
$validator = Validator::make($request->all(),[
'dosen_id' => 'required',
'matkul_id' => 'required',
'spo_id' => 'required'
],[
'dosen_id.required' =>'Dosen Tidak Boleh Kosong',
'matkul_id.required' =>'Mata kuliah Tidak Boleh Kosong',
'spo_id.required' =>'Tindakan Tidak Boleh Kosong',
]);
if($validator->fails()){
return response()->json($validator->errors(),
Response::HTTP_UNPROCESSABLE_ENTITY);
}
$pinjam = new Permintaan();
$pinjam->id = Uuid::uuid4()->getHex();
$pinjam->kd_permintaan = $data['kd_peminjaman'];
$pinjam->user_id = Auth::user()->id;
$pinjam->dosen_id = $data['dosen_id'];
$pinjam->matkul_id = $data['matkul_id'];
$pinjam->spo_id = $data['spo_id'];
$pinjam->tgl_minta = Carbon::now();
$pinjam->diserahkan = NULL;
$pinjam->aprovals = "Belum";
$pinjam->status = "Menunggu Persetujuan";
// $pinjam->keterangan = NULL;
$pinjam->save();
foreach($request->barang_id as $key => $barang){
$stok = Barang::findOrFail($barang);
if ($request->jumlah[$key] > $stok->stok) {
return response('[200] - Maaf Stok Barang Melewati Batas');
}else{
DetailPinjam::create([
'id' => Uuid::uuid4()->getHex(),
'permintaan_id' => $pinjam->id,
'kondisi_id' => 2,
'barang_id' => $barang,
'jumlah' =>$request->jumlah[$key],
'fix_jumlah_kembali' =>$request->jumlah[$key],
]);
$stokpinjam = $stok->stok - $request->jumlah[$key];
$stok->update([
'stok' => $stokpinjam,
]);
$response = [
'success' => true,
'message' => 'Peminjaman Created',
'data' => $pinjam
];
return response()->json($response, Response::HTTP_CREATED);
}
}
}elseif ($id == 2 ){
Request()->validate([
'dosen_id' => 'required',
'matkul_id' => 'required',
'spo_id' => 'required',
'tgl_kembali' => 'required',
],[
'dosen_id.required' =>'Dosen Tidak Boleh Kosong',
'matkul_id.required' =>'Mata kuliah Tidak Boleh Kosong',
'spo_id.required' =>'Tindakan Tidak Boleh Kosong',
'tgl_kembali.required' =>'Tanggal Pengembalian Tidak Boleh Kosong',
]);
$data = Request()->all();
$pinjam = new peminjaman();
$pinjam->id = Uuid::uuid4()->getHex();
$pinjam->kd_peminjaman = $data['kd_peminjaman'];
$pinjam->user_id = Auth::user()->id;
$pinjam->dosen_id = $data['dosen_id'];
$pinjam->matkul_id = $data['matkul_id'];
$pinjam->spo_id = $data['spo_id'];
$pinjam->tgl_pinjam = Carbon::now();
$pinjam->tgl_kembali = $data['tgl_kembali'];
$pinjam->diserahkan = NULL;
$pinjam->aprovals = "Belum";
$pinjam->status = "Menunggu Persetujuan";
$pinjam->keterangan = NULL;
$pinjam->save();
foreach($request->barang_id as $key => $barang){
$stok = Barang::findOrFail($barang);
if ($request->jumlah[$key] > $stok->stok) {
return response('[200] - Maaf Stok Barang Melewati Batas');
}else{
DetailPinjam::create([
'id' => Uuid::uuid4()->getHex(),
'peminjaman_id' => $pinjam->id,
'barang_id' => $barang,
'jumlah' => $request->jumlah[$key]
]);
$stokpinjam = $stok->stok - $request->jumlah[$key];
$stok->update([
'stok' => $stokpinjam,
]);
$response = [
'success' => true,
'message' => 'Peminjaman Created',
'data' => $pinjam
];
return response()->json($response, Response::HTTP_CREATED);
}
}
}
} catch (QueryException $e) {
//throw $th;
return response()->json([
'message' => "Failed" . $e->errorInfo
]);
}
}
`
and here the dart dio push method.
`
Kirim() async {
SharedPreferences localStorage = await SharedPreferences.getInstance();
var token = localStorage.getString('access_token');
try {
var data = FormData.fromMap({
'kd_peminjaman': kodepruduct,
'user_id': id_pengguna,
'dosen_id': dosendrop,
'matkul_id': matakuliahdrop,
'spo_id': spodrop,
//'tgl_minta': '${tanggal.day}.${tanggal.month}.${tanggal.year}',
'tgl_kembali':
'${tanggalkembali.day}.${tanggalkembali.month}.${tanggalkembali.year}',
'[barang_id][]': {
[id]
},
'[jumlah[]]': {
[jumlah]
},
});
var dio = Dio();
dio.options.headers['Authorization'] = 'Bearer $token';
//dio.options.headers['Content-Type'] = 'multipart/form-data';
dio.options.headers['Accept'] = 'application/json';
dio.options.headers['Content-Type'] = 'application/x-www-form-urlencoded';
var response = await dio
.post('http://silk.polindra.ac.id/api/peminjaman/2', data: data);
print(response.statusMessage);
} catch (e) {
print(e);
}
}
`
and i got response from the rest-api method like this.
i have tried to change the atribute on the FormData. on the array
barang[]: [id], jumlah[]: [jumlah]
to jsonEncode method
barang[]: jsonEncode([id]), jumlah[]: jsonEncode([jumlah])
and these too
[barang[]]: [id]], [jumlah[]: [jumlah]]
and the last
barang[]: {[id]}, jumlah[]: {[jumlah]}
all of refactoring atrribut i made, doesn't give any effect, all of method give the same error message
can some one help me.. plz...
sorry for my bad english.. i'm not usually spoken english in my country.
actually, the reason you get this issue is related to your API code on line 164 it suppose to string but it's returning an array. to check which parameter making an issue you can simply diedump by
dd($request->all());
and test it from the postman

CakePHP 3 basic authentication get authenticated user

public function beforeSave(Event $event) //for api
{
$hasher = new DefaultPasswordHasher();
$entity->api_key_plain =
Security::hash(Security::randomBytes(32), 'sha256', false);
$entity->api_key = $hasher->hash($entity->api_key_plain);
return true;
}
$this->loadComponent('Auth', [
'authenticate' => [
'Basic' => [
'fields' => ['username' => 'username', 'password' => 'api_key'],
//'finder'=>'apiauth',
'userModel'=>'Students',
],
],
'userModel'=>'Students',
'storage' => 'Memory',
'unauthorizedRedirect' => false,
]);
public function getuser(){
$user=$this->Auth->getUser(); // Auth getUser not found
$header= $this->request->getHeader('Authorization');
$usr =$this->Auth->user(); // Always return null
return $this->jsonResponse($usr,200);
}
how to get authenticated user information form each request in CakePHP 3 AuthComponent
documentation : the getUser() method should return an array of user information on the success or false on failure.

is it possible to create an email only authentication from existing email-password structure in Laravel

I am trying to create email only authentication. Instead of having a login, I want a situation where I will only have signup and once the email is entered, a bearer token is created.
I have the signup function and login function which worked when I had password initiated but I have removed the password but I tried to move the "create token" to signup. It gives error that token is undefined.
Signup function
public function signup(Request $request)
{
$request->validate([
'email' => 'required|string|email|unique:users'
]);
$user = new User([
'email' => $request->email
]);
$user->save();
return response()->json([
'message' => 'Successfully created user!'
], 201);
}
Login function
public function login(Request $request)
{
$request->validate([
'email' => 'required|string|email'
]);
$credentials = request(['email', '=']);
if(!Auth::attempt($credentials))
return response()->json([
'message' => 'Unauthorized'
], 401);
$user = $request->user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
if ($request->remember_me)
$token->expires_at = Carbon::now()->addWeeks(1);
$token->save();
return response()->json([
'access_token' => $tokenResult->accessToken,
'token_type' => 'Bearer',
'expires_at' => Carbon::parse(
$tokenResult->token->expires_at
)->toDateTimeString()
]);
}
It is really simple, you have already done most of the work needed to be done here. You don't need the login function rather you need to copy the token part of the function as illustrated below
public function signup(Request $request)
{
$request->validate([
'email' => 'required|string|email|unique:users'
]);
$user = new User([
'email' => $request->email
]);
$user->save();
Auth::login($user);
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
if ($request->remember_me)
$token->expires_at = Carbon::now()->addWeeks(1);
$token->save();
return response()->json([
'message' => 'Successfully created user!',
'access_token' => $tokenResult->accessToken,
'token_type' => 'Bearer',
'expires_at' => Carbon::parse(
$tokenResult->token->expires_at
)->toDateTimeString()
], 201);
}

Use JSON in Symfony controller

I'm looking for a way to execute a little bit of JSON from my Symfony (2.6 btw) controller, moreover than an other action (post data into database)
In fact, there is an register page with a controller which put data into database and then, redirect user to another page. But i need that my controller execute too a little bit of JSON to use Mailchimp API.
I've found a lot of docs about how to render JSON response, but, it seems to me that it's not what i want to be.
There is my controller
public function registerAction(Request $request)
{
/** #var $formFactory \FOS\UserBundle\Form\Factory\FactoryInterface */
$formFactory = $this->get('fos_user.registration.form.factory');
/** #var $userManager \FOS\UserBundle\Model\UserManagerInterface */
$userManager = $this->get('fos_user.user_manager');
/** #var $dispatcher \Symfony\Component\EventDispatcher\EventDispatcherInterface */
$dispatcher = $this->get('event_dispatcher');
$user = $userManager->createUser();
$user->setEnabled(true);
$event = new GetResponseUserEvent($user, $request);
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_INITIALIZE, $event);
if (null !== $event->getResponse()) {
return $event->getResponse();
}
$form = $formFactory->createForm();
$form->setData($user);
$form->handleRequest($request);
if ($form->isValid()) {
// Gestion du type d'utilisateur et ajout du role
$user_type = $form->get('user_profile')->get('type')->getData();
$new_role = $this->roles[$user_type];
$event = new FormEvent($form, $request);
$user = $event->getForm()->getData();
$user->addRole($new_role);
$user->getUserProfile()->setEmail($user->getEmail());
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_SUCCESS, $event);
$userManager->updateUser($user);
if (null === $response = $event->getResponse()) {
$url = $this->generateUrl('fos_user_registration_confirmed');
$response = new RedirectResponse($url);
}
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_COMPLETED, new FilterUserResponseEvent($user, $request, $response));
return $response;
}
return $this->render('FOSUserBundle:Registration:register.html.twig', array(
'form' => $form->createView(),
));
}
There is my JSON request
{
"email_address": "$email",
"status": "subscribed",
"merge_fields": {
"FNAME": "$name",
"LNAME": "$lastname",
"DATE": "$date"
}
}
So, how can i do to execute this JSON with this controller ?
Thank you in advance for your help (and sorry for my excellent english)
You probably want to create the JSON from an array rather than try to pass variables. Try:
$data = [
'email_address' => $email,
'status' => 'subscribed',
'merge_fields' => [
'FNAME' => $name,
'LNAME' => $lastname,
'DATE' => $date,
],
];
$json = json_encode($data);
Then I'm assuming this data gets sent to MailChimp in a POST request? If so, you could use Guzzle to send the data to MailChimp:
First add the guzzle dependency in composer by running:
composer require guzzlehttp/guzzle
Then send the data:
$client = new \GuzzleHttp\Client();
$response = $client->request('POST', 'https://MAILCHIMP_URL', ['body' => $data]);
To send JSON instead of raw data, do the following:
$client = new \GuzzleHttp\Client();
$response = $client->request('POST', 'https://MAILCHIMP_URL', ['json' => $data]);
Depending on the response status, you can then handle the logic afterwards.
You can achieve this also using JsonResponse (Symfony\Component\HttpFoundation\JsonResponse)
use Symfony\Component\HttpFoundation\JsonResponse;
...
// if you know the data to send when creating the response
$data = [
'email_address' => $email,
'status' => 'subscribed',
'merge_fields' => [
'FNAME' => $name,
'LNAME' => $lastname,
'DATE' => $date,
]
];
$response = new JsonResponse($data);
return $response;
More details here https://symfony.com/doc/current/components/http_foundation.html

No form errors shown in JsonResponse - Symfony

I have a registration form with fields that are validated in User entity class. The validation works fine, however I can't return JsonResponse with form error messages in it.
My registration form controller method looks like this:
/**
* #Route("/register", name="register")
*/
public function registerAction(Request $request)
{
$user = new User();
$form = $this->createForm(RegistrationType::class, $user);
$form->handleRequest($request);
$errors = "";
if ($form->isSubmitted())
{
if ($form->isValid())
{
$password = $this->get('security.password_encoder')
->encodePassword($user, $user->getPlainPassword());
$user->setPassword($password);
$user->setIsActive(1);
$user->setLastname('none');
$em = $this->getDoctrine()->getManager();
$em->persist($user);
$em->flush();
return new JsonResponse(
array(
'message' => 'Success! User registered!',
), 200);
}
else
{
$errors = ($this->get('validator')->validate($form));
return new JsonResponse(
array(
'message' => 'Not registered',
'errors' => $errors,
), 400);
}
}
return $this->render(
'ImmoBundle::Security/register.html.twig',
array('form' => $form->createView(), 'errors' => $errors)
);
}
I get the following json response when I submit the registration form with invalid data:
{"message":"Not registered","errors":{}}
Actually I'm expecting that "errors":{} will contain some error fields, but it doesn't. Does anyone know what the problem here is?
UPD:
My RegistrationType looks like this:
class RegistrationType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('firstname', TextType::class)
->add('email', EmailType::class)
->add('plainPassword', RepeatedType::class, array(
'type' => PasswordType::class,
'first_options' => array('label' => 'Password'),
'second_options' => array('label' => 'Repeat password'),
'invalid_message' => "Passwords don't match!",
))
->add('register', SubmitType::class, array('label' => 'Register'));
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'ImmoBundle\Entity\User',
'csrf_protection' => true,
'csrf_field_name' => '_token',
'csrf_token_id' => 'authenticate',
));
}
}
UPD2: Found the solution. I needed to do this iteration and then call for getMessage():
$allErrors = ($this->get('validator')->validate($form));
foreach ($allErrors as $error)
{
$errors[] = $error->getMessage();
}
Form validated when you call $form->handleRequest($request);
To get form errors use getErrors method
$errors = $form->getErrors(true); // $errors will be Iterator
to convert errors object to messages array you can use code from this response - Handle form errors in controller and pass it to twig
This is exapmle how i'm process errors in one of my projects
$response = $this->get('http.response_formatter');
if (!$form->isValid()) {
$errors = $form->getErrors(true);
foreach ($errors as $error) {
$response->addError($error->getMessage(), Response::HTTP_BAD_REQUEST);
}
return $response->jsonResponse(Response::HTTP_BAD_REQUEST);
}
It's worked for me.
And also this can help you - Symfony2 : How to get form validation errors after binding the request to the form
You must set error_bubbling to true in your form type by explicitly setting the option for each and every field.