iOS app communicate with Laravel webapp - php

I’m working on a project based on an iOS app (native) who use a webapp (Laravel framework) to communicate.
For exemple, ios user should use Laravel login to use the application.
The laravel part of the project is done and work good on a computer (login,register etc…)
But now i’m thinking how will i communicate with my futur ios App and my webapp using laravel framework. I dont know any ways to do that, maybe i need a special framwork on my ios app ?
I have no idea, can you help me ?
Thanks in advance

This is a loaded question.... My personal preference is to set up a set of API controllers so you can control them independently and version them.
1) Create a sub-set of controllers # /app/controllers/api/v1
2) Give them all a namespace of api/v1
<?php namespace api\v1;
3) Import whatever classes you need into the new namespace
<?php namespace api\v1;
use Illuminate\Support\Facades\Input;
use Illuminate\Support\Facades\Response;
use Usage;
use Auth;
4) Install an oAuth2 package
5) Set up routes that generate and validate tokens and place your protected routes in a route group. (my example below.)
Route::group(['prefix' => 'api/v1', 'before' => 'apiErrors'], function()
{
Route::post('accessToken', function()
{
return AuthorizationServer::performAccessTokenFlow();
});
Route::group(['before' => 'oauth|setUser'], function()
{
Route::resource('usages', 'api\v1\UsagesController');
Route::resource('connections', 'api\v1\ConnectionsController');
Route::resource('users', 'api\v1\UsersController');
});
});
6) Set up your new api controllers to return data in a manner that a mobile app can use (JSON)
public function index()
{
$usages = Usage::with('device.model.manufacturer')
->where('user_id', Auth::user()->id)
->get();
return Response::json($usages, $this->responseCode, $this->accessControl);
}

thanks for your complete answer ! but i have done an simple API controller without oAuth2 package. My controller for the moment just return true or false if login is okay and it works good. here my code for other people...
public function trylogin() {
if (Auth::attempt(array('email'=>Input::get('email'), 'password'=>Input::get('password'))) || Auth::attempt(array('username'=>Input::get('username'), 'password'=>Input::get('password')))) {
return Response::json(array('status' => 'OK'));
} else {
return Response::json(array('status' => 'FAIL'));
}
}
here my api routes
Route::resource('api/v1', 'ApiController');
Route::get('api/v1_hello', 'ApiController#sayhello');
Route::get('api/v1_login', 'ApiController#trylogin')
what do you think about security managment ? i can make my own token system validation on ios ?
EDIT
i finally found a solution, here the function in my ApiController :
you just need to send to your api from iOS the token generate by Facebook or Google connexion. and in my case add a network parameter.
public function registerOrLoginFromSocialNetWorkV1(){
if (Input::get('email') && Input::get('sn_id')) {
//sn = social network
if (User::where('email','=', Input::get('email'))->count() != 0) {
$user = User::where('email','=', Input::get('email'))->first();
$user->fb_id = Input::get('sn_id');
$user->save();
//return 'email already used';
}
else{
if (User::where('fb_id','=', Input::get('sn_id'))->count() == 0) {
$user = new User;
$user->firstname = Input::get('firstname');
$user->lastname = Input::get('lastname');
$user->username = Input::get('username');
$user->email = Input::get('email');
$user->fb_id = Input::get('sn_id');
$user->fk_role = 3;
$user->yearofbirth = Input::get('birthday');
//$user->yearofbirth = substr($me['birthday'],6,9);
if (Input::get('sex') == 'male') {
$user->sex = 1;
}
else{
$user->sex = 0;
}
$user->save();
Userslog::log('api_register_social_network');
}
else{
$user = User::where('fb_id','=', Input::get('sn_id'))->first();
if (!$user->yearofbirth){
$user->yearofbirth = Input::get('birthday');
$user->save();
}
}
}
//dd($user);
Auth::login($user);
$follows = Follow::where('user_id','=',$user->id)->get();
return Response::json(array('user' => $user,'follows' => $follows));
}
else{
return 'error';
}
}

Related

Why do api routes in tenant.php with Laravel VueJs are working with 200 OK status code in network tools but I'm receiving a blade as a response?

First of all, I'd like to comment on this that I'm working on a project based on Laravel VueJs with tenancy for laravel v3 package.
To get into context, I can perfectly log in on my name#example.com account registered at any created tenant on local development but after logging in, I'm struggling mainly with TypeError: Cannot read properties of undefined (reading 'xxxxx') in console with all the api-related and VueJs routes. I have been digging deeper over the problem and got into a conclusion.
TypeError: Cannot read properties of undefined (reading 'xxxxx')
And with that, I figured out my GET route with GetUserAuth as uri at 'api' middleware on tenant.php is recognized but isn't calling the method associated to it but throwing as a status code 200 OK. Instead, the response is a blade as in the following picture.
Where Respuesta is Response
It's also important to mention I've set up Laravel Passport according to the stancl/tenancy v3 documentation, specifically using Passport in the tenant application only with shared passport encryption keys.
The following code refers to my tenant.php
<?php
declare(strict_types=1);
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use Stancl\Tenancy\Middleware\InitializeTenancyByDomain;
use Stancl\Tenancy\Middleware\PreventAccessFromCentralDomains;
use App\Http\Controllers\UserController;
/*
|--------------------------------------------------------------------------
| Tenant Routes
|--------------------------------------------------------------------------
|
| Here you can register the tenant routes for your application.
| These routes are loaded by the TenantRouteServiceProvider.
|
| Feel free to customize them however you want. Good luck!
|
*/
Route::middleware(['api', InitializeTenancyByDomain::class, PreventAccessFromCentralDomains::class])->group(
function ()
{
/*auth middleware api passport token*/
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
// Other routes
Route::middleware(['auth:api', 'Is_Active'])->group(function ()
{
//Other routes
//------------------------------- Users --------------------------\\
Route::get('GetUserRole', [UserController::class, "GetUserRole"]);
Route::get('GetUserAuth', [UserController::class, "GetUserAuth"]);
Route::get("/GetPermissions", [UserController::class, "GetPermissions"]);
Route::resource('users', UserController::class);
Route::put('users/Activated/{id}', [UserController::class, "IsActivated"]);
Route::get('users/export/Excel', [UserController::class, "exportExcel"]);
Route::get('users/Get_Info/Profile', [UserController::class, "GetInfoProfile"]);
Route::put('updateProfile/{id}', [UserController::class, "updateProfile"]);
});
});
Route::middleware(['web', InitializeTenancyByDomain::class, PreventAccessFromCentralDomains::class])->group(
function ()
{
// Web routes
});
The following one is referring to the code located at C:/project-root/resources/src/store/modules/auth.js
import Vue from 'vue'
import Vuex from 'vuex'
// import VueCookie from 'vue-cookie'
import axios from 'axios'
import router from "./../../router";
Vue.use(Vuex)
// Vue.use(VueCookie)
const state = {
// token: Vue.cookie.get('Stocky_token'),
isAuthenticated:false,
Permissions: null,
user: {},
loading: false,
error: null,
notifs:0,
};
const getters = {
isAuthenticated: state => state.isAuthenticated,
currentUser: state => state.user,
currentUserPermissions: state => state.Permissions,
loading: state => state.loading,
notifs_alert: state => state.notifs,
error: state => state.error
};
const mutations = {
setLoading(state, data) {
state.loading = data;
state.error = null;
},
setError(state, data) {
state.error = data;
state.loggedInUser = null;
state.loading = false;
},
clearError(state) {
state.error = null;
},
// setLoginCred(state, payload) {
// state.token = payload.token;
// // state.isAuthenticated = true;
// },
setPermissions(state, Permissions) {
state.Permissions = Permissions;
// state.user = user;
},
setUser(state, user) {
state.user = user;
},
// SET_AUTHENTICATED(state, isAuthenticated) {
// state.isAuthenticated = isAuthenticated;
// },
Notifs_alert(state, notifs) {
state.notifs = notifs;
},
logout(state) {
// state.token = null;
state.user = null;
state.Permissions = null;
// state.isAuthenticated = false;
// Vue.cookie.delete('Stocky_token');
state.loggedInUser = null;
state.loading = false;
state.error = null;
},
};
const actions = {
// setLoginCred(context, payload) {
// context.commit('setLoading', true)
// context.commit('setLoginCred', payload)
// },
async refreshUserPermissions(context) {
await axios.get("GetUserAuth").then((userAuth) => {
let Permissions = userAuth.data.permissions
let user = userAuth.data.user
let notifs = userAuth.data.notifs
// context.commit('SET_AUTHENTICATED', true)
context.commit('setPermissions', Permissions)
context.commit('setUser', user)
context.commit('Notifs_alert', notifs)
}).catch(() => {
// context.commit('SET_AUTHENTICATED', false)
context.commit('setPermissions', null)
context.commit('setUser', null)
context.commit('Notifs_alert', null)
});
},
logout({ commit }) {
axios({method:'post', url: '/logout', baseURL: '' })
.then((userData) => {
window.location.href='/login';
})
},
};
export default {
state,
getters,
actions,
mutations
};
And the following one refers to the mentioned before method on UserCon related with the GET route throwing status code 200 OK with a blade as a response
//------------- GET USER Auth ---------\\
public function GetUserAuth(Request $request)
{
$helpers = new helpers();
$user['avatar'] = Auth::user()->avatar;
$user['username'] = Auth::user()->username;
$user['currency'] = $helpers->Get_Currency();
$user['logo'] = Setting::first()->logo;
$user['footer'] = Setting::first()->footer;
$user['developed_by'] = Setting::first()->developed_by;
$user['initCCF'] = Auth::user()->initCCF;
$user['currentCCF'] = Auth::user()->currentCCF;
$user['finalCCF'] = Auth::user()->finalCCF;
$user['initCF'] = Auth::user()->initCF;
$user['currentCF'] = Auth::user()->currentCF;
$user['finalCF'] = Auth::user()->finalCF;
$user['warehouse_id'] = Auth::user()->warehouse_id;
$permissions = Auth::user()->roles()->first()->permissions->pluck('name');
$products_alerts = product_warehouse::join('products', 'product_warehouse.product_id', '=', 'products.id')
->whereRaw('qte <= stock_alert')
->where('product_warehouse.deleted_at', null)
->count();
return response()->json([
'success' => true,
'user' => $user,
'notifs' => $products_alerts,
'permissions' => $permissions,
]);
}
Finally, I'd like to mention that my application with central domain only and a single database was working perfectly but I don't know what could be the problem even debugging, checking all the documentation related and other answered questions but none of those fixed my issue and I need help as soon as possible. Any suggestions or help are welcomed and if you need extra information, please let me know. Thanks in advance for taking your time.
A common thing I faced when using tenancy for laravel is the default Authenticate middleware included with the SaaS boilderplate you can purchase. It extends the default laravel Authenticate and adds this code:
if (! $request->expectsJson()) {
// return a blade view
return route('tenant.login');
}
This redirects all requests to the tenant.login view if the Accept: application/json header is missing.
I can't really see the headers of the request you're seding to GetUserAuth, but this could be the reason.

Laravel validating socialite token in every request

I am creating laravel API based application where I used passport for authentication. I have also used the laravel socialite for social media login. The things are working fine with laravel passport but I am unable to verify the social medea token, Like we pass the google token in the header of every request but not getting the way to check the token validity in every request.
Is there anyone who can help me with this problem?
Thanks in advance.
You can check on middleware:
Middleware File:
class ApiAuthenticate {
public function handle($request, Closure $next)
{
$status = false;
$accessToken = $request->header('AccessToken');
if($accessToken) {
$user_check = User::where("api_token", $accessToken)->first();
if(count($user_check) > 0)
{
$status = true;
}
}
if($status == false) {
return response()->json([
'code' => 401,
'msg' => trans('web_service.unathenticated')
]);
} else {
return $next($request);
}
}
}
Route File:
Route::group(array('prefix' => 'api', 'middleware' => 'api'), function()
{
Route::get('/users', 'Api\UsersController#getUser');
Route::post('/users/save', 'Api\UsersController#saveUser');
})

CakePHP and REST Api for ionic (angular) app

Hello I try to setup cakephp for rest client (with login auth) for ionic (angular) app.
Ok, I configure CakePhp like this setup tutorial and for example I get data that:
public function projects()
{
$projects = $this->Projects->find('all');
$this->set([
'projects' => $projects,
'_serialize' => ['projects']
]);
}
and get data via $.http in Ionic
This work perfectly but I try to configure cake auth for mobile client.
I don't know how I do this. In my Resttest Controller i wrote code where set session Id for ionic app, but ionic not cache this session and I think is my cakePhp code is wrong.
CakePHP controller:
<?php
namespace App\Controller;
use App\Controller\AppController;
use Cake\Controller\Component\RequestHandlerComponent;
// use Cake\View\Helper\SessionHelper;
class ResttestController extends AppController
{
public function initialize()
{
parent::initialize();
$this->loadComponent('RequestHandler');
$this->loadModel('Projects');
$this->loadModel('Task');
$this->loadModel('User');
$this->viewBuilder()->layout(false);
$this->response->header('Access-Control-Allow-Origin', '*');
$this->loadComponent('Auth', [
'loginAction' => [
'controller' => $this->name,
'action' => 'login',
// '_ext'=>'json'
],
'authorize'=>['Controller'],
]);
// Basic setup
$this->Auth->config('authorize', ['Controller']);
}
public function login(){
header('Access-Control-Allow-Headers: Content-Type, x-xsrf-token');
$this->response->header('Access-Control-Allow-Methods', '*');
if($this->request->is('post')){
$postdata = file_get_contents("php://input");
$d = json_decode($postdata);
if($this->Auth->user()){
$response =array("success"=>2,'msg'=>'logged After');
}
// $d = $this->request->data;
if(!$d->password || !$d->login){
$response = array("success"=>0,'msg'=>'n');
}
$u = $this->User->find()
->where(['email'=>$d->login])
->first();
if($u){
$salt = $u->salt;
$input_password = crypt($d->password, '$2y$12$' . $salt);
$password = $u->password;
if($password == $input_password){
$tok = self::getToken();
$u->token = $tok;
$out = $this->Auth->setUser($u);
$response = array("success"=>1,'msg'=>'logged', 'token'=>$tok, 'out'=>$out,'sadga'=>$this->Auth->identify,'asf'=>$this->Auth,'adsafsfq'=>$d,'$this->request'=>$this->request,'$this->response'=>$this->response,'apache_request_headers '=>apache_request_headers());
}else{
$response = array("success"=>0,'msg'=>'n');
}
}else{
$response = array("success"=>0,'msg'=>'n');
}
}else{
$response =array("success"=>0,'msg'=>'n');
}
$this->set([
'response' => $response,
'_serialize' => ['response']
]);
}
private function getToken(){
return crypt(sha1(md5(uniqid(rand(), true))));
}
public function testAuth(){
}
}
This code return session and user data but not work and I think is not good method for mobile auth. Do you have any idea for auth for cakephp ?
How I make my code more security ?
When we split application to backend api and frontend, we should consider backend as stateless application. This mean you can't use session for auth.
Instead you should implements auth/login and auth/register rest endpoints that will return some token for example JWT.
For cakephp2 you can easely find such library: https://github.com/t73biz/cakephp2-jwt-auth
Use this authenticator instead of Form when you configure Auth component.
From front end side pass token like it is described in the plugin.

Using Laravel Socialite with an API?

I'm trying to use Laravel Socialite package over an api. I try to pass the code into my api to fetch the user but it keeps giving me an error:
Fatal error: Call to a member function pull() on null
Since I'm doing the request over an API, I take the following steps.
Send a request to api for the url to fetch the code:
Socialite::with('facebook')->stateless()->redirect()->getTargetUrl()
Then make a request with the above fetched url, which redirects with the code parameter.
Send the code to the api and fetch the user:
$fb_user = Socialite::with('facebook')->user();
This is where it crashes. I'm not sure why.
I've used the package before and it works fine when I just have an app that reloads the page. But when I send it to an api (on a different domain) it crashes. I'm thinking there is some issue with how the code is generated. Is there anyway to fix this?
Just found my answer. Need to use stateless in both calls:
Socialite::with('facebook')->stateless()->redirect()->getTargetUrl()
$fb_user = Socialite::with('facebook')->stateless()->user();
Hope this helps someone.
I made SocialController.php and url (POST request) /api/social-login which accepts provider and access_token.
SocialAccount here is a laravel model where you'll provider and provider_user_id and local database user id. Below is the example of social_accounts table
And in SocialController :
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Hash;
use Illuminate\Http\Request;
use App\User;
use App\SocialAccount;
use Socialite;
class SocialController extends Controller
{
public function social(Request $request) {
$provider = $request->input('provider');
switch($provider){
case SocialAccount::SERVICE_FACEBOOK:
$social_user = Socialite::driver(SocialAccount::SERVICE_FACEBOOK)->fields([
'name',
'first_name',
'last_name',
'email'
]);
break;
case SocialAccount::SERVICE_GOOGLE:
$social_user = Socialite::driver(SocialAccount::SERVICE_GOOGLE)
->scopes(['profile','email']);
break;
default :
$social_user = null;
}
abort_if($social_user == null , 422,'Provider missing');
$social_user_details = $social_user->userFromToken($request->input('access_token'));
abort_if($social_user_details == null , 400,'Invalid credentials'); //|| $fb_user->id != $request->input('userID')
$account = SocialAccount::where("provider_user_id",$social_user_details->id)
->where("provider",$provider)
->with('user')->first();
if($account){
return $this->issueToken($account->user);
}
else {
// create new user and social login if user with social id not found.
$user = User::where("email",$social_user_details->getEmail())->first();
if(!$user){
// create new social login if user already exist.
$user = new User;
switch($provider){
case SocialAccount::SERVICE_FACEBOOK:
$user->first_name = $social_user_details->user['first_name'];
$user->last_name = $social_user_details->user['last_name'];
break;
case SocialAccount::SERVICE_GOOGLE:
$user->first_name = $social_user_details->user['name']['givenName'];
$user->last_name = $social_user_details->user['name']['familyName'];
break;
default :
}
$user->email = $social_user_details->getEmail();
$user->username = $social_user_details->getEmail();
$user->password = Hash::make('social');
$user->save();
}
$social_account = new SocialAccount;
$social_account->provider = $provider;
$social_account->provider_user_id = $social_user_details->id;
$user->social_accounts()->save($social_account);
return $this->issueToken($user);
}
}
private function issueToken(User $user) {
$userToken = $user->token() ?? $user->createToken('socialLogin');
return [
"token_type" => "Bearer",
"access_token" => $userToken->accessToken
];
}
}
EDIT:
I have created package for the same https://packagist.org/packages/pimplesushant/laravelsocialiteapi

FosUserBundle integration with FosRestBundle

Does anyone have an example or any idea how one would implement the FOSRestBundle together along with the FOSUserBundle. I have a Web app already developed with Symfony 2 and the FOSUserBundle, but I would like to add the FOSRestBundle for an api layer. I want to be able to pass it a username and password and receive some type of token from the FOSUserBundle that represents the logged in user that I can then pass and forth between other api calls. Does anyone know of a good way to do this?
FOSUserBundle should be natively "restful" meaning that it may follow the REST recommandations.
However, it is not designed to work natively with FOSRestBundle, the simplest way to do that is to override the UsersController in your Bundle and adapt your actions.
For example, to allow RESTFul registration, you may write the following action:
public function postUsersAction()
{
$form = $this->container->get('fos_user.registration.form');
$formHandler = $this->container->get('fos_user.registration.form.handler');
$confirmationEnabled = $this->container->getParameter('fos_user.registration.confirmation.enabled');
$process = $formHandler->process($confirmationEnabled);
if ($process) {
$user = $form->getData();
$authUser = false;
if ($confirmationEnabled) {
} else {
$authUser = true;
}
$response = new Response();
if ($authUser) {
/* #todo Implement authentication */
//$this->authenticateUser($user, $response);
}
$response->setStatusCode(Codes::HTTP_CREATED);
$response->headers->set(
'Location',
$this->generateUrl(
'api_users_get_user',
array('user' => $user->getId()),
true
)
);
return $response;
}
return RestView::create($form, Codes::HTTP_BAD_REQUEST);
}

Categories