i try to make API authentication with my WP app
i have write the add the below code to add new fields and upon login it send data to External API if it user exist in API return login or create new WP user if not just don't do anything or gives an error, but i have the issue with Cookie now and get the "Error: Cookies are blocked due to unexpected output."
here is my code:
add_action('login_form', 'businessId', 10, 1);
function businessId()
{
?>
<div class="businessid_wrap">
<label for="businessId">business ID</label>
<input type="text" id="businessId" name="businessId" value=""/>
</div>
<?php
}
function au_auth($user, $username, $password)
{
$endpoint = 'will be my API endpoint url';
// Makes sure there is an endpoint set as well as username and password
if (!$endpoint || $user !== null || (empty($username) && empty($password))) {
return false;
}
$auth_args = [
'method' => 'POST',
'headers' => [
'Content-type: application/json',
],
'sslverify' => false,
'body' => [
'businessId' => $_POST['businessId'],
'userLogin' => $username,
'userPassword' => $password,
],
];
$response = wp_remote_post($endpoint, $auth_args);
$body = json_decode($response['body'], true);
var_dump ($response);
if (!$response) {
// User does not exist, send back an error message
$user = new WP_Error('denied', __('<strong>Error</strong>: Your username or password are incorrect.'));
} elseif ($response) {
/for now i just dumping the return data to check
var_dump ($response);
}
remove_action('authenticate', 'wp_authenticate_username_password', 20);
return $user;
}
add_filter('authenticate', 'au_auth', 10, 3);
Related
I made a plugin to allow wordpress login with external api.
Everything works, now what I have to do is that when a user logs in for the first time, the plugin checks to see if it is already present on wp, and where it was not already present, it creates a new user by taking behind username, email and password.
The new user is created but I would like it to bring with it also the id field from the external api saving it in an ACF field.
This is the code created so far:
function au_auth($user, $username, $password)
{
$options = get_option('au_options');
$endpoint = $options['au_apiurl'];
$user_email_key = 'email';
$password_key = 'password';
// Makes sure there is an endpoint set as well as username and password
if (!$endpoint || $user !== null || (empty($username) && empty($password))) {
return false;
}
// Check user exists locally
$user_exists = wp_authenticate_username_password(null, $username, $password);
if ($user_exists && $user_exists instanceof WP_User) {
$user = new WP_User($user_exists);
return $user;
}
// Build the POST request
$login_data = array(
$user_email_key => $username,
$password_key => $password
);
$auth_args = array(
'method' => 'POST',
'headers' => array(
'Content-type: application/x-www-form-urlencoded'
),
'sslverify' => false,
'body' => $login_data
);
$response = wp_remote_post($endpoint, $auth_args);
// Token if success; Not used right now
$response_token = json_decode($response['response']['token'], true);
$response_code = $response['response']['code'];
if ($response_code == 400) {
// User does not exist, send back an error message
$user = new WP_Error('denied', __("<strong>Error</strong>: Your username or password are incorrect."));
} else if ($response_code == 200) {
// External user exists, try to load the user info from the WordPress user table
$userobj = new WP_User();
// Does not return a WP_User object but a raw user object
$user = $userobj->get_data_by('email', $username);
if ($user && $user->ID) {
// Attempt to load the user with that ID
$user = new WP_User($user->ID);
}
} else {
// The user does not currently exist in the WordPress user table.
// Setup the minimum required user information
$userdata = array(
'user_email' => $username,
'user_login' => $username,
'user_pass' => $password
);
// A new user has been created
$new_user_id = wp_insert_user($userdata);
// Assign editor role to the new user (so he can access protected articles)
wp_update_user(
array(
'ID' => $new_user_id,
'role' => 'editor'
)
);
// Load the new user info
$user = new WP_User ($new_user_id);
}
}
// Useful for times when the external service is offline
remove_action('authenticate', 'wp_authenticate_username_password', 20);
return $user;
}
Anyone have any way how to help me?
Resolved! I hope this will help those who have found themselves in the same situation as me:
add_filter('authenticate', 'au_auth', 10, 3);
add_filter('register_new_user', 'au_registration', 10, 3);
// add_filter('profile_update', 'au_profile_update', 10, 3);
// add_filter('edit_user_profile_update', 'au_profile_edit', 10, 3);
function au_auth($user, $username, $password)
{
$options = get_option('au_options');
$endpoint = $options['au_apiurl'];
// Makes sure there is an endpoint set as well as username and password
if (!$endpoint || $user !== null || (empty($username) && empty($password))) {
return false;
}
$auth_args = [
'method' => 'POST',
'headers' => [
'Content-type: application/x-www-form-urlencoded',
],
'sslverify' => false,
'body' => [
'email' => $username,
'password' => $password,
],
];
$response = wp_remote_post($endpoint, $auth_args);
// Token if success; Not used right now
$response_token = json_decode($response['response']['token'], true);
$body = json_decode($response['body'], true);
$response_status_code = $response['response']['code'];
$success = $body !== 'KO';
if (!$success) {
// User does not exist, send back an error message
$user = new WP_Error('denied', __('<strong>Error</strong>: Your username
or password are incorrect.'));
} elseif ($success) {
$idExternal = $body['Id'];
$nome = $body['Name'];
$cognome = $body['Surname'];
$email = $body['Email'];
$userobj = new WP_User();
$user = $userobj->get_data_by('email', $email);
if ($user && $user->ID) {
$user = new WP_User($user->ID);
} else {
$userdata = [
'user_email' => $email,
'user_login' => join(' ', [$name, $surname]),
'user_pass' => '----',
];
$new_user_id = wp_insert_user($userdata);
$new_user_composite_id = 'user_' . $new_user_id;
update_field('field_60084ad3970a8', $idExternal, $new_user_composite_id);
update_field('field_5f22ca201c7b0', $name, $new_user_composite_id);
update_field('field_5f22ccd498f40', $surname, $new_user_composite_id);
update_field('field_5f22ce7b7c1db', $email, $new_user_composite_id);
$user = new WP_User($new_user_id);
}
}
remove_action('authenticate', 'wp_authenticate_username_password', 20);
return $user;
}
I have a few API endpoints on my WordPress page. The problem is, that the response-time takes about (6 – 30 seconds – depends on what is to do).
When a client sends a request to my API he has to wait for 6 – 30 seconds for a response and that is the problem.
I read about background dispatch – how does this work with WordPress? The only thing the API does is insert, delete or update posts.
At the moment the API does the following:
Validate data
Check if the client_id exists and the client_secret matches
Check if the post already exists -> if yes update -> if no create
Update / Create post
(optional) Upload images with media_sideload_image()
5/6. Update custom fields -> update_field()
if (have_rows("api_users", "options")) {
while (have_rows("api_users", "options")) {
the_row();
if (get_sub_field("api_user_client_id") == $client_id) {
$flag = true;
}
}
}
if (!$flag) {
wp_send_json_error(array("message" => "Wrong ClientID"));
}
return false;
}
public function rest_create_xxx($request) {
// check if clientID is correct
$this->checkIfClientIsAllowed($request->get_param("client_id"));
// validate params
$params = $request->get_params();
$validator = $this->validation->make($params, array(
// my validation rules
));
if ($validator->fails()) {
wp_send_json_error(array("message" => "validation failed");
}
// check if parent post exist
$result = self::findPostByInternId("yyy", $request->get_param("client_id"), $request->get_param("parent"));
$parent_post = 0;
if ($result->have_posts() && $result->post_count == 1) {
$parent_post = $result->posts[0];
} else {
wp_send_json_error(array("message" => "parent post not found"));
}
// check if xxx with that id already exists (if yes update, if no insert)
$result = self::findPostByInternId("xxx", $request->get_param("client_id"), $request->get_param("intern_id"));
$post = null;
if ($result->have_posts() && $result->post_count == 1) {
// post already exist - so update it
$post = wp_update_post(array(
"ID" => $result->posts[0]->ID,
"post_title" => $request->get_param("title"),
"post_type" => "xxx",
"post_parent" => $parent_post->ID,
"post_status" => "publish"
));
} else {
// post not found - so insert it
$post = wp_insert_post(array(
"post_title" => $request->get_param("title"),
"post_type" => "xxx",
"post_parent" => $parent_post->ID,
"post_status" => "publish"
));
}
// update some acf fields
update_field("a", $request->get_param("a"), $post);
update_field("b", $request->get_param("b"), $post);
update_field("c", $request->get_param("c"), $post);
wp_send_json_success();
}
?>
I have a registeration form with some custom fields and need to register users with Wordpress REST api,
$('#user_register_form').submit(function(e){
e.preventDefault();
var form = $(this),
rest = new DwREST();
rest.registerUser({
first_name: '',
last_name: '',
username: 'amin',
name : 'amin',
email : 'aaaa#amin.ev',
password: '11111',
// passwrod2: '11111' -confirm password field
// custom_field1: ''
// ....
}, function( res ){
console.log( res );
});
});
The user registeration works fine but the problem is i can't confirm wether password repeat matches or not, i searched a lot and didn't find an action to modify to /users/ validation
the second question is is it possible to automatically login user created with REST api after registeration?
i appreciate any help.
I searched in rest-api source codes, sadly i didn't find any proper hook to do what i needed, there's just a rest_pre_insert_user hook which getting it to do what i intend to do is a bit tricky, but here's the work around, in case some one has the same problem:
add_filter('rest_pre_insert_user', function( $user, $request ){
$params = $request->get_params();
if( $params['password'] !== $params['password2'] ) {
$error = new WP_Error( 'rest_no_matching_passwords', __( 'Passwords don\'t match' ), array( 'status' => 400 ) );
foreach( $error->error_data as $data ) {
http_response_code( $data['status'] );
}
header('Content-Type: application/json; charset=utf-8;');
foreach( $error->errors as $key => $val ){
$json = json_encode([
'code' => $key,
'type' => 'error',
'message' => $val[0]
]);
}
die( $json );
}
return $user;
}, 10, 2 );
Reference
Anyone why i got this error? I am trying to log-in via Facebook.
It give me this error:
Cross-site request forgery validation failed. The "state" param from
the URL and session do not match.
This is my code!
$helper = $fb->getRedirectLoginHelper();
$this->facebook['callback_url'] = Yii::$app->urlManager->createAbsoluteUrl('users/user/set-info') . '&social_code=21g36fsdfe135e5';
$this->facebook['login_url'] = $helper->getLoginUrl('https://example.com/index.php?r=users/user/set-info&social_code=21g36fsdfe135e5', $this->facebook['permissions']);
try {
// Get the Facebook\GraphNodes\GraphUser object for the current user.
// If you provided a 'default_access_token', the '{access-token}' is optional.
$accessToken = $helper->getAccessToken();
} catch(Facebook\Exceptions\FacebookResponseException $e) {
// When Graph returns an error
echo 'Graph returned an error: ' . $e->getMessage();
exit;
} catch(Facebook\Exceptions\FacebookSDKException $e) {
// When validation fails or other local issues
echo 'Facebook SDK returned an error: ' . $e->getMessage();
exit;
}
if (isset($accessToken)) {
$this->setUserData([
'facebook' => [
'access_token' => (string) $accessToken
]
]);
// OAuth 2.0 client handler
$oAuth2Client = $fb->getOAuth2Client();
// Exchanges a short-lived access token for a long-lived one
$longLivedAccessToken = $oAuth2Client->getLongLivedAccessToken($_SESSION['facebook_access_token']);
$_SESSION['facebook_access_token'] = (string) $longLivedAccessToken;
// setting default access token to be used in script
$fb->setDefaultAccessToken($_SESSION['facebook_access_token']);
$response = $fb->get('/me?fields=email,id,name,first_name,last_name,link,gender,locale,timezone,updated_time,verified,location,friends', $accessToken);
$tmp = $response->getGraphObject();
echo 'Logged in as ' . $tmp->getName();
$this->user_information = [
'social_id' => $tmp['id'],
'social_name' => 'facebook',
'email' => $tmp['email'],
'public_profile' => $tmp['link'],
'first_name' => $tmp['first_name'],
'last_name' => $tmp['last_name'],
'gender' => $tmp['gender'],
'home_address' => $tmp['location']['name'],
'user_friends' => $tmp['friends'],
];
$friends_response = $fb->get('/me/taggable_friends?fields=id,name,picture,email&limit=5000', $accessToken);
$temp = $friends_response->getGraphEdge();
$friends = array();
for ($i = 0; $i < count($temp); ++$i) {
$friends[] = $temp[$i];
}
$_SESSION['friends'] = $friends;
$this->social_loggedIn = true;
}
else {
$this->social_loggedIn = false;
}
Please Go to the file
src/Facebook/PersistentData/PersistentDataFactory.php
In Your Facebook SDK
find this Code
if ('session' === $handler) {
new FacebookSessionPersistentDataHandler();
}
And Replace with
if ('session' === $handler) {
return new FacebookSessionPersistentDataHandler();
}
I am trying to execute and then display a cookie in my nav header template.
Currently my controller checks if a user is logged in. If not logged in then checks for a cookie. If no cookie exists a generic cookie is created. And then finally the template is loaded.
Currently the cookie is being created and template is loaded just fine, but the value passed when rendering the template does not show up after the page loads. I can see the cookie is created, and if I reload the page a 2nd time everything works as intended.
So I know this means the headers are not being sent as expected correct? But I cannot figure out the proper way to do this in Symfony2.
Here is my controller code:
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Cookie;
class navController extends Controller {
public function displayNavAction() {
$userState = '';
$userZipcode = '';
if ($this->container->get('security.context')->getToken() != null) {
// To check if user is authenticated or anonymous
if ($this->container->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY') === true) {
$user = $this->getUser();
$userCity = $user->getCity();
$userState = $user->getState();
$userZipcode = $user->getZipcode();
} else {
//User is not logged in, so check for cookie.
$request = $this->get('request');
$cookies = $request->cookies;
if ($cookies->has('city'))
{
//User not logged in, but cookie exists. So use cookie.
$userCity = $cookies->get('city');
} else {
//User not logged in, and no existing cookie. So create cookie.
$cookieGuest = array(
'name' => 'city',
'value' => 'seattle',
'path' => '/',
'time' => time() + 3600 * 24 * 7,
false,
false
);
$cookie = new Cookie($cookieGuest['name'], $cookieGuest['value'], $cookieGuest['time'], $cookieGuest['path']);
$response = new Response();
$response->headers->setCookie($cookie);
$response->sendHeaders();
$userCity = $cookies->get('city');
}
}
}
return $this->render(
'trrsywxBundle:Default:nav.html.twig', array('city' => $userCity, 'state' => $userState, 'zipcode' => $userZipcode, 'tempjunk' => $userCity));
}
}
You are not using the response you created that's the problem try this :
$userCity = $cookies->get('city');
$response = new Response($this->render(
'trrsywxBundle:Default:nav.html.twig',array(
'city' => $userCity,
'state' => $userState,
'zipcode' => $userZipcode,
'tempjunk' => $userCity
)));
$cookie = new Cookie($cookieGuest['name'], $cookieGuest['value'],$cookieGuest['time'], $cookieGuest['path']);
$response->headers->setCookie($cookie);
$response->sendHeaders();
return $response;
then you can get cookie value in your twig using the request global {% app.request.cookies %}