Magento 2 REST API - php

I' m trying to create a node.js client for the Magento REST API.
I use the community edition running on my own centOS server.
The steps I follow to use the api:
Create user with Administrator role in Magento admin panel
Create new Integration
Activate Integration (after this, I receive ConsumerKey, ConsumerSecret, AccessToken, SecretToken)
The problem is: when I try a get request to any endpoint I get:
{
Client is not authorized to access this resource: ResourceName
}
the request is:
request({
url: this.url+endpoint,
method: 'GET',
headers:{
'Authorization': 'Bearer '+bearer,
'User-Agent': '...',
'Accept' : 'application/json',
'Content-Type': 'application/json'
}
}, (error, response, body) => {
callback(error,response,body)
})
})
I correctly get the bearer ( I checked it ) token by this request:
request({
url: this.url+'integration/admin/token',
method: 'POST',
json:{
username: this.username,
password: this.password
}
}, (error, response, body) => {
callback(body)
})
Navigating through the magento installation, I ran into the authorization request:
public function isAllowed($resource, $privilege = null)
{
return $this->_aclPolicy->isAllowed($this->_aclRoleLocator->getAclRoleId(), $resource, $privilege);
}
If I change into
return true
I get access to all the resources without authentication, but it' s not what I want
I checked the function
getAclRoleId()
and I found this DefaultRoleLocator.php
namespace Magento\Framework\Authorization\RoleLocator;
class DefaultRoleLocator implements
\Magento\Framework\Authorization\RoleLocatorInterface
{
/**
* Retrieve current role
*
* #return string
*/
public function getAclRoleId()
{
return '';
}
}
I am not very good in PHP, and I' m a newbie on magento.
Even the oauth authentication fails.
I have to change this function ?
I have to create another RoleLocator class ?
Any help would be really appreciated !

Are you sure you added permissions to access the requested resource?

Related

WooCommerce Session returns blank

I am developing mobile application from my existing WooCommerce store. I have added custom APIs to maintain everything through user session. I don't know how session is being managed on WooCommerce. But when I call wp_get_session_token() method from mobile app, it returns blank string and from postman when I call the same API, it returns proper string of session.
My main object is to add product to cart and retrieve from cart for particular session of user. By using custom APIs, I am able to do everything as per user session. Product is being added to current logged in user's cart via logged in session. But from mobile app, I am not able to add product to cart for particular user via its session. I am getting proper response for custom add to cart API from mobile app but it can't define for which user's cart that product is added. Also after adding product to cart, I call get cart items API which also return 0 items which means product is not being added there. All these APIs working fine from Postman.
To figure out this issue, I tried calling wp_get_session_token() method in login API. This method returns proper session id when it is called from Postman. But when I call this from mobile app, it returns only blank string.
It seems to me that problem is with session from mobile app but I don't know how to manage it from Mobile App to WooCommerce store.
Here is my login API where I return session id for now to debug:
function register_api_hooks() {
register_rest_route(
'custom-plugin', '/login/',
array(
'methods' => ['GET'],
'callback' => 'login',
)
);
function login($request) {
$creds = array();
$creds['user_login'] = $request["username"];
$creds['user_password'] = $request["password"];
$creds['remember'] = true;
$user = wp_signon( $creds, false );
$session = (object) wp_get_session_token();
write_log($user);
write_log($session);
return $session;
// return $user;
}
}
write_log also have blank entry for session when it is called from Mobile App.
Code for add to cart:
add_action( 'rest_api_init', 'register_cart_hooks' );
// API custom endpoints for WP-REST API
function register_cart_hooks() {
register_rest_route(
'custom-plugin', '/addToCart/',
array(
'methods' => ['GET'],
'callback' => 'addToCart',
)
);
function addToCart($request) {
global $woocommerce;
$woocommerce>cart>add_to_cart($request["product_id"],$request["quantity"]);
return "Success...";
}
}
Please let me know where I am going wrong or what other implementation I have to make.
EDIT
Here is the code I am using from React Native Mobile App:
fetch(url1, {
method: methodName,
async: true,
crossDomain: true,
headers: new Headers({
"Content-Type": "application/json",
"cache-control": "no-cache",
}),
body:data1
}).then((response) => {
const statusCode = response.status;
console.log("fetchData StatusCode : "+statusCode);
console.log("fetchData response1 : " + JSON.stringify(response));
console.log("fetchData response2 : " + response);
return response.json();
}).then((responseJson) => {
// var firstResponse = responseJson.split(',');
// console.log("fetchData responseJson 111 : "+firstResponse);
console.log("fetchData responseJson : "+responseJson);
var response = JSON.stringify(responseJson);
console.log("fetchData responseJson stringify : " + response);
response = JSON.parse(response);
console.log("fetchData responseJson stringify 1 : " + response);
console.log("fetchData responseJson stringify 2 : " + JSON.stringify(response));
if (callBack != null) {
callBack("", response);
}
}).catch((error) => {
console.log("fetchData Api error : "+error);
if (callBack != null) {
console.log("fetchData Api error callBack != null 2");
callBack("Error", "");
}
});

How to get additional scope information from Google PHP API payload?

I'm struggling with getting additional scope information from the Google PHP API. I'm using it in conjunction with JavaScript to get an access token (not sure if this is the correct way, but it works for me)
I have a Google sign up button on my page that's connected to the following function. Basically, it gets a response token to send to my PHP server trough AJAX.
gapi.load('auth2', function() {
// Retrieve the singleton for the GoogleAuth library and set up the client.
auth2 = gapi.auth2.init({
client_id: 'XXXX',
cookie_policy: 'single_host_origin',
// Requesting additional scopes
scope: 'https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/plus.login'
});
auth2.attachClickHandler(document.getElementById('google-login-signup'), {},
function(googleUser) {
if ( auth2.isSignedIn.get() ) {
var data = {
'action': 'social_google_login',
'_nonce': $('#google-login-signup').attr('data-nonce'),
'redirect_to': $('#google-login-signup').attr('data-redirect-to'),
'token': googleUser.getAuthResponse().id_token
}
$.ajax({
url: ajax_url,
type: 'POST',
data: data,
success: function(response) {
console.log(response);
if ( response.success === true ) {
window.location.href = response.data.redirect;
}
}
});
}
}, function(error) {
console.log(error);
}
);
});
Then on my server, the token is retrieved and fed through the following function, which checks if the token is valid and returns the info:
public function connect() {
$client = new Google_Client();
$credentials = json_decode('XXXX', true);
$client->setAuthConfig($credentials);
$payload = $client->verifyIdToken($_POST['token']);
if ( !$payload ) {
return new WP_Error('invalid_payload', 'The payload was invalid.');
}
return $payload;
}
This all works fine, except that it doesn't include the information from the additional scopes I requested in the JavaScript function. How can I get this additional scope information such as the birthday and sex?
Just for reference, this is what the $payload variable returns:
at_hash: "XXXX"
aud: "XXXX.apps.googleusercontent.com"
azp: "XXXX.apps.googleusercontent.com"
email: "XXXX#gmail.com"
email_verified: true
exp: 1520189629
family_name: "XXXX"
given_name: "XXXX"
iat: XXXX
iss: "accounts.google.com"
jti: "XXXX"
locale: "en"
name: "XXXX XXXX"
picture: "XXXX"
sub: "XXXX"
I managed to figure it out. The main problem was I was trying to access data through the id_token, but what I needed to do was use an access_token and pass it through other Google APIs.
In case anyone stumbles upon this, here is my new and improved code, which also fixes some issues I had unrelated to this question.
JavaScript
$('#google-login-signup').on('click', function(e) {
e.preventDefault();
gapi.load('auth2', function() {
var scopes = [
'https://www.googleapis.com/auth/userinfo.email',
'https://www.googleapis.com/auth/userinfo.profile',
'https://www.googleapis.com/auth/plus.login'
];
// Use gapi.auth2.authorize instead of gapi.auth2.init.
// This is because I only need the data from Google once.
gapi.auth2.authorize({
'client_id': 'XXXX.apps.googleusercontent.com',
'cookie_policy': 'single_host_origin',
'fetch_basic_profile': false,
'ux_mode': 'popup',
'scope': scopes.join(' '),
'prompt': 'select_account'
},
function(googleResponse) {
if ( googleResponse.error ) {
return;
}
var data = {
'action': 'social_google_login',
'_nonce': $('#google-login-signup').attr('data-nonce'),
'redirect_to': $('#google-login-signup').attr('data-redirect-to'),
// Instead of id_token, send the access_token.
// This is needed for accessing the scope info from other APIs.
'access_token': googleResponse.access_token
}
$.ajax({
url: ajax_url,
type: 'POST',
data: data,
success: function(response) {
if ( response.success === true ) {
window.location.href = response.data.redirect;
}
}
});
});
});
});
PHP
public function connect() {
$client = new Google_Client();
$credentials = json_decode('XXXX', true);
$client->setAuthConfig($credentials);
// Set Access Token
$client->setAccessToken($_POST['access_token']);
// Connect to Oauth2 API after providing access_token to client
$oauth2 = new Google_Service_Oauth2($client);
if ( !$oauth2 ) {
return new WP_Error('invalid_access_token', 'The access_token was invalid.');
}
// Contains basic user info
$google_user = $this->get_user($oauth2->userinfo->get());
// To get the plus.login scope we need to setup a Google_Service_Plus
$google_plus_service = new Google_Service_Plus($client);
// Contains Google+ profile info
$profile = $google_plus_service->people->get('me');
}
That's it! it was basically an issue of not knowing that I needed to access a different Google_Service to get the additional scope information.
In Google Developers API Console search for Google People API, Enable it and use these scopes as well:
https://www.googleapis.com/auth/contacts | Manage your contacts
https://www.googleapis.com/auth/contacts.readonly | View your contacts
https://www.googleapis.com/auth/plus.login | Know the list of people in your circles, your age range, and language
https://www.googleapis.com/auth/user.addresses.read | View your street addresses
https://www.googleapis.com/auth/user.birthday.read | View your complete date of birth
https://www.googleapis.com/auth/user.emails.read | View your email addresses
https://www.googleapis.com/auth/user.phonenumbers.read | View your phone numbers
https://www.googleapis.com/auth/userinfo.email | View your email address
https://www.googleapis.com/auth/userinfo.profile | View your basic profile info
Lists of all available scopes documented in here

Laravel with AngularJS Login

Im using Laravel 5 as an API and i have AngularJS running my frontend.
I have built the login portion of the backend that accepts the form data and responds with a json object.
My question is when i recieve the success object from the api to say that the login details are sucessfull. How do i use AngularJS to then login the user from the frontend.
AuthenticateUser.php
http://pastebin.com/PZqGCpz5
app.js
var app = angular.module('app', []);
app.controller('AppCtrl', function($scope, $http) {
$scope.login = {};
$scope.submitLoginForm = function () {
var email = $scope.login.email;
var password = $scope.login.password;
$http({
method : 'POST',
url : '/api/1.0/auth/login',
data : { email, password },
headers : { 'Content-Type': 'application/json' }
})
.success(function(data) {
console.log(data);
});
}
}
JSON Response
success: Object
message : authentication_successfull
code : 200
user_id : 1
What steps should i take from here to log the user into the frontend.
Thanks in advance
You can do this with the help of api_token approach.
First when you call a login api then create a unique token specific to user and save it database and send it in response as:
success: Object
message : authentication_successfull
code : 200
data : {api_token: some_random_key}
Then for subsequent request send that api_token in the request headers.
And server will automatically logins the user if you are using the auth:api middleware as:
Route::group(['middleware' => ['auth:api']], function()
{
// API routes here
});
For reference

How to post data using AWS API Gateway Http?

I am using AWS API Gateway. I want to post data to my controller which resides on my server directory.
I've created one API which has a development resource and POST method.
I've also added OPTIONS method to add headers.
I am using ajax to send the request data to controller.
Data is always empty.
Controller is in CakePHP
function which I am calling is
function webservice() {
if(empty($this->data['username'])){
echo json_encode("Data is Empty");
}
else{
$username = $this->data['username'];
$password = $this->data['password'];
$deviceType = $this->data['deviceType'];
$token = $this->data['token'];
$conditions= array('username' => $username,
'password' => $password,
'token' => $token,
'deviceType' => $deviceType
);
echo json_encode($conditions);
}
exit();
}
Ajax Call is :
var username = "dummydata";
var password = "dummydata";
var deviceType = "dummydata"
var token = "dummydata";
alert(username + password + token);
$.ajax(
{
type : "POST",
url : "https://xxxxxxxxxx.execute-api.ap-southeast-1.amazonaws.com/dev/webserv",
data: "{username : username, password: password, token: token, deviceType: deviceType}",
success : function(result){
alert((result));
}
});
How to receive posted data from AJAX in controller using AWS API Gateway?
First you need to provide a mapping template to API Gateway to allow it to map request data to your Lambda function call. Second, pay attention to "Content Type" you set on the mapping template, and set that same content type in your AJAX call in order to trigger the use of that template.
For example if you set the content type in API Gateway to "application/json" then you would set this property on your jQuery AJAX call: contentType: "application/json"
As for the mapping template, I find it easiest to just use a template that always maps everything from the incoming request. I use this template, taken from this answer:
{
"method": "$context.httpMethod",
"body" : $input.json('$'),
"headers": {
#foreach($param in $input.params().header.keySet())
"$param": "$util.escapeJavaScript($input.params().header.get($param))" #if($foreach.hasNext),#end
#end
},
"queryParams": {
#foreach($param in $input.params().querystring.keySet())
"$param": "$util.escapeJavaScript($input.params().querystring.get($param))" #if($foreach.hasNext),#end
#end
},
"pathParams": {
#foreach($param in $input.params().path.keySet())
"$param": "$util.escapeJavaScript($input.params().path.get($param))" #if($foreach.hasNext),#end
#end
}
}

How to send a request from angular front end to laravel API?

I'm building a RESTful API with Laravel 5.2 and I have an AngularJS 1.5 front end. I am successfully writing services to get information but I am having troubble putting or posting anything to the database when I pass it to the API. I've tried doing some searching and but I just don't understand how to actually save data I would send the API. Here is my attempt so far:
-Service from the Factory-
addReceipt: function(request) {
return $http.post(api_url + "/rewards/receipts/add", request).then(function(results) {
console.log(results);
return results.data;
});
}
-From the Controller
$scope.submitReceipt = function() {
rewardsFactory.addReceipt($scope.model).then(function() {
console.log($scope.model);
toaster.pop({ type: 'success', title: 'Claim Submitted!', body: "Thanks! We'll take a look at your claim shortly.", showCloseButton: true });
});
};
-From Laravel API routes
Route::post('rewards/receipts/add', 'Rewards\RewardsController#addReceipt');
-From Laravel Controller
public function addReceipt(Request $request)
{
//Add the Receipt
DB::table('receipts')->insert(
['transaction_id' => $request->input('transactionID'),
'client_id' => $request->input('client_id'),
'location_id' => $request->input('location_id') ]
);
}
My Current Cors setup seems to be working out well enough for at least some traffic so I don't think that is the problem but I'm just still not sure what I'm doing wrong.
Note that $http does not send form encoded data by default, it sends application/json in request body.
I don't do any work with laravel but if you check $_POST you will see it is empty so $request->input is probably empty also.
In php you can access the response body using :
json_decode(file_get_contents('php://input')[,true/*optional to convert to array*/])
I believe that json_decode($request->getContent()) will do the same in laravel
The alternative is to use the following $http set up taken from the docs to send form encoded data
.controller(function($http, $httpParamSerializerJQLike) {
//...
$http({
url: myUrl,
method: 'POST',
data: $httpParamSerializerJQLike(myData),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
});
});
You can also set $http.defaults in a run block so all post or put are sent as x-www-form-urlencoded and not have to add the config to each use

Categories