Yii REST POST is not working in POSTMAN but in Framework - rest

how could i post the form to the rest api action. Or how can i test the rest api for creating a record in the db with all the field values. Should we add create aq queryStringUrl. if its comming from a POST form action its fine. But this yii rest api should also work when called on a android device. I have used $_Request on post of the form , will the same work else where. if i wanna test the same in POSTMAN how can i do it. http://localhost/basic/web/site/create?fname=deepika&uname=deeps&email=deep#gmail.com&pwd=deepika&pwd_confirm=deepika&gender=female says 404 in postman. But works in the yii controller url This is the action i have created.
public function actionCreate()
{
$params=$_REQUEST;
//echo $params;
$model= new UsersForm();
if(isset($params['fname']))
$fname=$params['fname'];
if(isset($params['uname']))
$uname=$params['uname'];
if(isset($params['email']))
$email=$params['email'];
if(isset($params['pwd']))
$pwd=$params['pwd'];
if(isset($params['gender']))
$gender=$params['gender'];
if($fname == "" || $uname == "" || $email == "" || $pwd == "" || $gender == ""){
$this->setHeader(400);
echo "<pre>".json_encode(array('status'=>0,'error_code'=>400,'errors'=>"Something went wrong"),JSON_PRETTY_PRINT)."</pre>";
}else{
$model->fname = $fname;
$model->uname = $uname;
$model->email = $email;
$model->pwd = $pwd;
$model->pwd_confirm = $pwd;
$model->gender = $gender;
if($model->save()){
if($model->status == 0){
$mailSent = Yii::$app->mailer->compose()
->setFrom("noreply#gmail.com")
->setTo($model->email)
->setSubject("Proceed by Verification")
->setTextBody('Plain text content')
->setHtmlBody('<b>HTML content</b>')
->send();
// VarDumper::dump($mailSent, 10, true);die();
}
$this->setHeader(200);
echo "<pre>".json_encode(array('status'=>1,'success_code' => 200,'verification_mail'=>$mailSent,'message'=>'Registered Successfully'),JSON_PRETTY_PRINT)."</pre>";
}else{
$this->setHeader(400);
echo "<pre>".json_encode(array('status'=>0,'error_code'=>400,'errors'=>$model->errors),JSON_PRETTY_PRINT)."</pre>";
}
}
// VarDumper::dump($params, 10, true);die();
}

Without code examples its hard to say what goes wrong in your app. I think first of all if you creat new item by GET method, its not REST. In REST API cretion of new item goes by POST method (I say nothing about URL appearance). When I was realized REST in some project, I create simple methods at the backend application and then on frontend (JavaScript app) create simple method for send request to API URLs, and when I preparing headers to send, and then depending of url I set method to headers GET, POST, or PUT (no DELETE because we not deletin items throgh API). So it may be little bit confusing... But I believe when you will get things about REST you will resolve your problem.

Related

Disable redirect in fetch request using React native

I'm trying to crawl a web using React Native which has no API. It's written in PHP.
To log an user, a POST request must be sent. The response returns a cookie with a PHPSessid cookie which I must capture to use in subsequent requests.
I would like to capture the cookie value, buy the POST response is a 302 and the redirection is followed automatically, so I can't see the cookie. In node I was able to do it with redirect:manual, but it does not work in react native.
The cookie is sent automatically in subsequent requests, buy I'm trying to manage cookies by hand with react-native-cookie and I'd like to know if it's possible.
Do you know a way to stop the redirection?
I've been checking the code and what I did was the following:
Clear all cookies
Launch an empty login request
Capture the PHPSessID coookie
Launch a login request with that PHPSessID
After that, the subsequent fetch requests would have automatically a PHPSessID cookie with a valid logged in user, so we can use the site with simple fetchs
Here is some code, but the important thing is that you do a first empty login request, capture the PHPSessid and launch the real login request with that PHPSessid.
This would be the main function:
import Cookie from 'react-native-cookie';
// I think this is used only to clear the cookies
function login(user, pass){
// clear all cookies for all domains
// We need to start withouth authorization token
Cookie.clear();
const makeLoginRequest = (sessid) =>
makeLoginRequestForUserAndPass(user,pass,sessid);
return makeInitialRequest()
.then(getSessionIDFromResponse)
.then(makeLoginRequest)
.then(checkIfLoggedAndGetSessionID);
}
The initial request is a request to the login script. Note that I used GET because it worked with my site, perhaps an empty post would be necessary:
function makeInitialRequest() {
const INIT_PATH = '/index.php?r=site/login';
const INIT_URL = site + INIT_PATH;
const request = new Request(INIT_URL, options....);
return fetch(request);
}
We have the session ID in the response. I used a simple regex to extract it. Note that we are not logged in; PHP has created a session and that's what we have here:
function getSessionIDFromResponse(response) {
return getPHPSessIdFromCookie(response.headers.get('set-cookie'));
}
function getPHPSessIdFromCookie(header) {
const regex = /PHPSESSID=(\w*)/;
const match = regex.exec(header);
return match ? match[1] : '';
}
Now the login request. Note that I can't stop redirection here, but I't have to do it because we can have PHPSessid later. Redirection must be set to manual in POST request:
function makeLoginRequestForUserAndPass(user, pass, sessid) {
const request = buildLoginRequest(user, pass, sessid);
return fetch(request);
}
// This is where we build the real login request
function buildLoginRequest(user, pass, sessid) {
const LOGIN_PATH = '/index.php?r=site/login';
const LOGIN_URL = site + LOGIN_PATH;
const fields = [
{name: 'LoginForm[username]', value: user},
{name: 'LoginForm[password]', value: pass},
etc...
];
const data = translateFieldsToURLEncodedData(fields);
const headers = {
'Content-type': 'application/x-www-form-urlencoded',
Cookie: `PHPSESSID=${sessid}`, // HERE is where you put the data
};
const options = { method: 'POST',
headers: headers,
mode: 'cors',
cache: 'default',
agent: proxy,
body: data,
redirect: 'manual' // VERY IMPORTANT: if you don't do it, the cookie is lost
};
return new Request(LOGIN_URL, options);
}
// Simple utility function
function translateFieldsToURLEncodedData(fields){
let pairs = fields.map( (field) => {
return encodeURIComponent(field.name) + '=' + encodeURIComponent(field.value);
});
return pairs.join('&');
}
This is the last part. To see if I was logged in I checked if the response had text belonging to login error's page. I also got the PHPSessid (I think it changed after login, not sure, it was a year ago) but I don't know if I used it, I believe it was included automatically in subsequent requests. I think this part could be simplified an improved:
function checkIfLoggedAndGetSessionID(response) {
return (
checkIfLoggedOK(response)
.then(() => getSessionIDFromResponse(response))
);
}
function checkIfLoggedOK(response){
return getTextFromResponse(response)
.then(throwErrorIfNotLogedOk);
}
function getTextFromResponse(response) {
return response.text();
}
function throwErrorIfNotLogedOk(page) {
if(isErrorPage(page)) throw new Error("Login failed");
}
function isErrorPage(text) {
const ERROR_MESSAGE = 'Something that appears in login failed page of your site';
let n = text.search(ERROR_MESSAGE);
return n !== -1;
}
Hope this can be useful.

Laravel Passport and Ionic2 Facebook-Login

I am developing a mobile app which should do API calls to an own laravel backend.
Frontend: Ionic 2 + Angular2
Backend: Laravel 5.3 + Laraval Passport + MySQL
At the user can log in with password grant (username + password).
Now I want to offer a login via Facebook.
I've implemented a Login with Facebook-button in the app. This works fine. I get the profile information from the Facebook API: id, email, name
Now this user (has no email + password combination from our server) should be able to make API calls to our Laravel server and should be linked to user in the users-table of the MySQL-database behind the laravel backend. Users which login with Facebook shouldn't need any username or password to login. Just Facebook.
I want to generate a new user in the database for each facebook user (simply with a column facebook_id). But how to give such users an access_token?
Accepting just the Facebook ID, match this (or create new) user in the database and create an access_token would be very unsecure because Facebook ID is public...
I must say I have same problem couple of weeks ago. Only difference I got was that I have both, ionic2 app and website. Both must support username/password login as social login (google, facebook).
So how did I did that (I will write for facebook, google is slightly different - better):
Prepare your facebook app to accept logins from mobile AND webpage. You will need facebook client_id and client_secret.
Install socialite package for laravel. And set it up to work with facebook ( in app/services.php set facebook ).
Now when you got this you can start coding. You said you already have it working on Ionic2 part. So that means you get token and other data from facebook for user.
What I did is I make request to my api and send this token and user_id. Then on my API side I check if token is valid, login user and issue passport token.
Ionic2 code:
Facebook.login(["public_profile"])
.then(response => {
// login success send response to api and get token (I have auth service class to do that)
this.auth.facebookLogin(response.authResponse).then(
...
);
}, error => {
this.showAlert( this.loginFailedTitle, this.loginFailedText );
});
Now Laravel part. I made SocialController.php and url (POST request) /api/social-login/facebook:
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Model\SocialLogin;
use App\User;
use Illuminate\Http\Request;
use Socialite;
class SocialController extends Controller
{
public function facebook(Request $request) {
$user = Socialite::driver('facebook')->userFromToken( $request->input('accessToken'));
abort_if($user == null || $user->id != $request->input('userID'),400,'Invalid credentials');
// get existing user or create new (find by facebook_id or create new record)
$user = ....
return $this->issueToken($user);
}
private function issueToken(User $user) {
$userToken = $user->token() ?? $user->createToken('socialLogin');
return [
"token_type" => "Bearer",
"access_token" => $userToken->accessToken
];
}
}
Now this will return you passport token and you can make api request to protected routes.
About passport, email, username, ..... you will have to change database and make it nullable. And add facebook_id field.
And be sure to make requests over https, because your are sending token.
Hope it helps.
in addition to #Bostjan's answer adding my generalised implementation :
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
];
}
}

Google Analytics OAuth2: How to solve error: "redirect_uri_mismatch"?

I'm trying to get this example to work: https://developers.google.com/analytics/devguides/config/mgmt/v3/quickstart/web-php#enable
The error I'm getting is "Error: redirect_uri_mismatch" .
In order to install the google api resources, I used composer with this command:
php composer.phar require google/apiclient:^2.0.0#RC
This installed the "vendor" folder in my root site folder. My index.php and oauth2callback.php files are located in the "public_html" folder.
Here's a screenshot of my error when going to my site:
The weird thing is that if I navigate to the link above that's included in the error message "Visit ...... to update the authorized..", I get this error message: " The OAuth Client Does Not Exist "
If I click on my only available Client ID, I can navigate to see the URI's which I'll screenshot below as well:
As you can see, under Authorized Javascript origins, I have http://localhost listed, and under authorized redirect URIs, I have my live site followed by the "oauthc2callback.php" file extension.
I don't understand how to get rid of the error I'm getting. I've tried replacing the URI's and putting in different JavaScript origins.
Also, for some reason on that last screenshot, it says that I don't have permission to edit this OAuth client, but I can make edits.
The code I have for index.php:
<?php
// Load the Google API PHP Client Library.
require_once '../vendor/autoload.php';
// Start a session to persist credentials.
session_start();
// Create the client object and set the authorization configuration
// from the client_secretes.json you downloaded from the developer console.
$client = new Google_Client();
$client->setAuthConfigFile('../config/client_secrets.json');
$client->addScope('https://www.googleapis.com/auth/analytics.readonly');
// If the user has already authorized this app then get an access token
// else redirect to ask the user to authorize access to Google Analytics.
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
// Set the access token on the client.
$client->setAccessToken($_SESSION['access_token']);
// Create an authorized analytics service object.
$analytics = new Google_Service_Analytics($client);
// Get the first view (profile) id for the authorized user.
$profile = getFirstProfileId($analytics);
// Get the results from the Core Reporting API and print the results.
$results = getResults($analytics, $profile);
printResults($results);
} else {
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
function getFirstprofileId(&$analytics) {
// Get the user's first view (profile) ID.
// Get the list of accounts for the authorized user.
$accounts = $analytics->management_accounts->listManagementAccounts();
if (count($accounts->getItems()) > 0) {
$items = $accounts->getItems();
$firstAccountId = $items[0]->getId();
// Get the list of properties for the authorized user.
$properties = $analytics->management_webproperties
->listManagementWebproperties($firstAccountId);
if (count($properties->getItems()) > 0) {
$items = $properties->getItems();
$firstPropertyId = $items[0]->getId();
// Get the list of views (profiles) for the authorized user.
$profiles = $analytics->management_profiles
->listManagementProfiles($firstAccountId, $firstPropertyId);
if (count($profiles->getItems()) > 0) {
$items = $profiles->getItems();
// Return the first view (profile) ID.
return $items[0]->getId();
} else {
throw new Exception('No views (profiles) found for this user.');
}
} else {
throw new Exception('No properties found for this user.');
}
} else {
throw new Exception('No accounts found for this user.');
}
}
function getResults(&$analytics, $profileId) {
// Calls the Core Reporting API and queries for the number of sessions
// for the last seven days.
return $analytics->data_ga->get(
'ga:' . $profileId,
'7daysAgo',
'today',
'ga:sessions');
}
function printResults(&$results) {
// Parses the response from the Core Reporting API and prints
// the profile name and total sessions.
if (count($results->getRows()) > 0) {
// Get the profile name.
$profileName = $results->getProfileInfo()->getProfileName();
// Get the entry for the first entry in the first row.
$rows = $results->getRows();
$sessions = $rows[0][0];
// Print the results.
print "<p>First view (profile) found: $profileName</p>";
print "<p>Total sessions: $sessions</p>";
} else {
print "<p>No results found.</p>";
}
}
The code I have for "oauth2callback.php":
<?php
require_once '../vendor/autoload.php';
// Start a session to persist credentials.
session_start();
// Create the client object and set the authorization configuration
// from the client_secrets.json you downloaded from the Developers Console.
$client = new Google_Client();
$client->setAuthConfigFile('../config/client_secrets.json');
$client->setRedirectUri('http://' . $_SERVER['HTTP_HOST'] . '/oauth2callback.php');
$client->addScope('https://www.googleapis.com/auth/analytics.readonly');
// Handle authorization flow from the server.
if (! isset($_GET['code'])) {
$auth_url = $client->createAuthUrl();
header('Location: ' . filter_var($auth_url, FILTER_SANITIZE_URL));
} else {
$client->authenticate($_GET['code']);
$_SESSION['access_token'] = $client->getAccessToken();
$redirect_uri = 'http://' . $_SERVER['HTTP_HOST'] . '/';
header('Location: ' . filter_var($redirect_uri, FILTER_SANITIZE_URL));
}
All of this code was taken from the first website example, except with a few minor additions to make it match my system.
Anyone know how I can get rid of this error? What am I doing wrong?
Remember, as far as Google is concerned, "your" server is hostile until you name it "friendly", you must explicitly whitelist every possible source of an OAuth call TO Google.
Google is a clubbouncer, a big, ugly, unmovable bouncer with a a guest list saying to your application: "I will only deal with your request if your exact name OR id is on the list"
Have you tried including, not only localhost, but all other possible origins?
You must list every possible variation of url "root", including explicit IPs.
http://www.example.com
http://example.com
https://example.com
https://www.example.com
http://222.111.0.111
...
dont forget to include
https://accounts.google.com:443
The redirect Uri in the request MUST be exactly the same as one Uri you stored.
I see a / at the end of the stored one you missed in your request.
just copy the request URI on which error is occurring from error screen and paste it to OAuth credentials "Authorised redirect URIs"
now run the app.
this works for me. Hope I answered your query.

How to intercept and redirect each request on owncloud

I' struggling with a simple problem on owncloud 7.0
I'm creation an app that have to check a condition and redirect to a page to validate something. My target is to disable service usage until a condition is ok.
In the nominal scenario, user log in, system redirect user to the validation page if condition is not verified. So I use postLogin hook.
But if user try to change page without validating, I have to catch him and redirect it back to the validation page.
I have tried Middleware (owncloud interceptor), but they are not global, so second scenario fails.
Now I'm working with app loading and do something like
$app = new MyApp();
$c = $app->getContainer();
if ( $c->isLoggedIn() ) {
$requestedPath = path($_SERVER['REQUEST_URI']);
$redirectPath = $c->getServer()->getURLGenerator()->linkToRoute('myapp.page.validate');
$refererPath = path($_SERVER['HTTP_REFERER']);
if ( $requestedPath !== $redirectPath && $redirectPath !== $refererPath ) {
$location = $c->getServer()->getRouter()->generate('myapp.page.validate');
header('Location: ' . $location);
exit();
}
}
function path($url) {
$urlArray = parse_url($url);
return $urlArray['path'];
}
It works fine for the first case, but I go into several redirections in the second case.
I think it must exist a better solution. Somebody has an idea ?
PS: I have exposed my case on IRC channel without success to interest someone :)
You might be able to do this using appinfo/app.php if you've registered your app as type authentication in appinfo/info.xml. This should basically look like the following code, however this obviously needs further tuning for your use-case.
info.xml:
<?xml version="1.0"?>
<info>
<id>appname</id>
<name>Appname</name>
<description>Lorem Ipsum.</description>
<licence>AGPL</licence>
<author>Your Name</author>
<require>6.0.3</require>
<types>
<authentication/>
</types>
</info>
app.php:
<?php
namespace OCA\appname\AppInfo;
use \OCP\User;
/**
* Implement your code here
* #return bool
*/
function conditionMatch() {
return true;
}
// Intercept all requests which have not already been matched
if ($_SESSION['alreadyMatched'] !== true) {
if(conditionMatch()) {
$_SESSION['alreadyMatched'] = true;
} else {
// The session has not met the condition - enter your code here
exit();
}
}

facebook.login() is not working in Corona SDK

I have went threw all the steps, creating a key hash for android for my game build in corona. I have create a Button for user login Facebook account. But don't have any error message and response when user touch the Button. Only have print output.
What am I missing? Please help.
I have create the Key Hashes using OPENSSL
Enter App ID from Facebook Developers
Enter Key Hashes to Facebook Developers
Enable "Single Sign On" and "Deep Linking"
Enter Class Name "com.ansca.corona.CoronaActivity" on Facebook Developers
include "android.permission.INTERNET" in build.settings
local facebook = require ("facebook")
local fbAppID = "49911xxxxxx"
local function onClick( event )
if ( "ended" == event.phase ) then
print( "Button was pressed and released" )
facebook.login( fbAppID, facebookListener, { "publish_actions, email" } )
end
end
-- Facebook Button
FacebookButton = widget.newButton
{
defaultFile = "images/fb.png" ,
width = 240,
height = 120,
onEvent = onClick,
}
FacebookButton.x = display.contentWidth / 2
FacebookButton.y = display.contentHeight / 2
I am unsure if you have fixed this problem but I too have been having problems with this. When you go to log in through Facebook and it gives you an error saying:
"invalid key hash code, it does not match xxxxxxxxxxxxx configure it in (your website here)" I copied the hash code and checked it over and over again...
Only to FINALLY realize that the lowercase "L" was actually an uppercase "i" o.0 it fixed it! Good luck to ya!
Also, here is a little code snippit that helped me a little
local function facebookListener(event)
if (event.type == "session") then
if (event.phase == "login") then
sessionToken = event.token
local response = event.response
native.showAlert("My Response", response)
--facebook.request("me", "GET", {fields = "email"})
elseif (event.type == "request") then
local response = event.response
native.showAlert("My Response", response)
end
end
end
facebook.login( appId, facebookListener, {"publish_actions, email, public_profile"})