laravel 5.2 redirect after registration by id - redirect

I've found here some examples, but they are not answering how to redirect registered user to his own profile by id.
protected $redirectPath = '/profile/view/'.$user->id; Did not help.
I have a project where users are being authorized without email confirmation and they are sent to /home after registration.
Route to user profile is: /profile/view/id (id is unique of course).
I managed to send them there after login (in AuthController :
public function authenticated($request,$user)
{
return redirect('/profile/view/'.$user->id);
}
but redirect to profile after registration I can't handle.

Approach 1.
Let users view their own profile without ID.
route (make ID optional):
Route::get('profile/view/{id?}', ...);
controller:
public function view($id = null) {
if (is_null($id) { //set id of currently signed in user if id == null
$id = Auth::user()->id;
}
//continue as before
}
Approach 2.
Modify routes so redirect happens to correct url.
Note: order of routes is important
Route::get('profile/view', function() {
return redirect()->route('profile.view', ['id' => Auth::user()->id]);
});
Route::get('profile/view/{id}', ...)->name('profile.view');
Note: in both approaches auth middleware is a must, else you going to get error if user is not logged in (PHP error: Trying to get property of non-object on line X)
With both approaches you just redirect user to profile/view:
is shown profile (without ID in URL)
is redirected to proper url profile/view/ID.

Related

Laravel Socialite with Facebook not logging in

I'm following the documentation exactly.
https://github.com/laravel/socialite and https://laravel.com/docs/5.1/authentication#social-authentication
I've created my app on Facebook and got everything working. When I click my log in with Facebook button, it authorizes the app and takes me back to my site.
However, it doesn't show me as logged in. If I dd() instead of the redirect below, I get all of the data from my Facebook account. But the pages that are only visible to logged in users, aren't visible.
Here is my controller:
public function redirectToProvider()
{
return Socialite::driver('facebook')->redirect();
}
public function handleProviderCallback()
{
$user = Socialite::driver('facebook')->user();
return redirect('my-profile')
->with('message', 'You have signed in with Facebook.');
}
Here are my routes:
Route::get('login/facebook', 'Auth\AuthController#redirectToProvider');
Route::get('login/facebook/callback', 'Auth\AuthController#handleProviderCallback');
Socialite is installed properly in composer.json. The classes are in config/app.php and the IDs for my FB app are in config/services.php.
Any ideas as to why it's not working?
In the handleProviderCallback method you need to create and authenticate the user returned by the driver.
Create the user if doesn't exist:
$userModel = User::firstOrNew(['email' => $user->getEmail()]);
if (!$userModel->id) {
$userModel->fill([.....]);
$userModel->save();
}
Then authenticate the user:
Auth::login($userModel);
Your method will look like this:
public function handleProviderCallback() {
$user = Socialite::driver('facebook')->user();
$userModel = User::firstOrNew(['email' => $user->getEmail()]);
if (!$userModel->id) {
$userModel->fill([.....]);//Fill the user model with your data
$userModel->save();
}
Auth::login($userModel);
return redirect('my-profile')
->with('message', 'You have signed in with Facebook.');
}

What's the proper way to handle insufficient permissions with the Facebook Authentication for Spring Security plugin?

I'm using the Spring Security 2.0-RC4 and the Facebook Authentication for Spring Security 0.15.2-CORE2 to allow users to authenticate with a Facebook login. I request the extra FB permission "email" since I use email as the primary key for my User class, so if the email permission is unselected by the user I need to abort login. Currently I check for null email in my FacebookAuthService.create() and return null if email was not set.
In the normal case everything works fine. Login succeeds, I get new User and FacebookUser records created and my User object's email property is updated with the Facebook user's email address. However, if the user elects to remove email permission during login then I run into problems.
In my FacebookAuthService.create() I check if email was returned (similar to in this question), and if not return null to abort the authentication process:
FacebookUser create(FacebookAuthToken token) {
Facebook facebook
FacebookProfile fbProfile
try {
facebook = new FacebookTemplate(token.accessToken.accessToken)
fbProfile = facebook.userOperations().userProfile
} catch (org.springframework.social.ApiException apiex) {
return null
}
String email = fbProfile.email
if (!email) {
return null
}
...
When email is null and I return null my security state seems to be messed up. I have a beforeInterceptor on my controller which gets called after I return null from create():
def beforeInterceptor = {
def user = springSecurityService.currentUser
log.trace("${user?.email} - End action ${controllerName}Controller.${actionName}() : returns $model, view ${modelAndView?.viewName}")
}
getCurrentUser() should be returning null but instead it throws an exception:
org.codehaus.groovy.grails.web.errors.GrailsExceptionResolver - NullPointerException occurred when processing request: [GET] /rar/user/home
Cannot get property 'username' on null object. Stacktrace follows:
java.lang.NullPointerException: Cannot get property 'username' on null object
at org.codehaus.groovy.runtime.NullObject.getProperty(NullObject.java:56)
at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:169)
at org.codehaus.groovy.runtime.callsite.NullCallSite.getProperty(NullCallSite.java:44)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:227)
at grails.plugin.springsecurity.SpringSecurityService.getCurrentUser(SpringSecurityService.groovy:87)
at grails.plugin.springsecurity.SpringSecurityService$$FastClassBySpringCGLIB$$6e53ab8e.invoke(<generated>)
...
It seems that SpringSecurityService thinks that someone is logged in because getCurrentUser()'s call to isLoggedIn() returns true, which causes an exception later when principal is null and a property is accessed on the null principal object.
Should I be aborting the Facebook login process in a different way instead of returning null from FacebookAuthService.create()?
Solved by throwing an exception from FacebookAuthService.create() rather than returning null when email permission has been removed.
My create() now includes this code segment:
if (!email) {
def grailsWebRequest = WebUtils.retrieveGrailsWebRequest()
def flash = grailsWebRequest.flashScope
flash.message = 'Login to Facebook failed. We must have access to your email address in order to proceed with login.'
throw new InsufficientAuthenticationException()
}

Exchanging Facebook Auth Code for Access Token using the PHP SDK

I am trying to build a server-to-server auth flow using the Facebook PHP SDK and no Javascript, as outlined here. So far, I have successfully created a LoginUrl that lets the User sign in with Facebook, then redirect back to my App and check the state parameter for CSFR protection.
My Problem is, that I can't seem to get the API-call working that should swap my Auth Code for an access token. I pillaged every similar problem anyone else that Google was able to find had encountered for possible solutions.
Yet the end result was always the same: no access token, no error message that I could evaluate.
Researching the topic yielded the following advice, which I tested:
The URL specified in the App Settings must be a parent folder of $appUrl.
use curl to make the request instead of the SDK function api()
I've been at this for 2 days straight now and really could use some help.
<?php
require '../inc/php-sdk/src/facebook.php';
// Setting some config vars
$appId = 'MY_APP_ID';
$secret = 'MY_APP_SECRET';
$appUrl = 'https://MY_DOMAIN/appFolder';
$fbconfig = array('appId'=>$appId, 'secret'=>$secret);
$facebook = new Facebook($fbconfig);
// Log User in with Facebook and come back with Auth Code if not yet done
if(!(isset($_SESSION['login']))){
$_SESSION['login']=1;
header('Location: '.$facebook->getLoginUrl());
}
// process Callback from Facebook User Login
if($_SESSION['login']===1) {
/* CSFR Protection: getLoginUrl() generates a state string and stores it
in "$_SESSION['fb_'.$fbconfig['appId'].'_state']". This checks if it matches the state
obtained via $_GET['state']*/
if (isset($_SESSION['fb_'.$fbconfig['appId'].'_state'])&&isset($_GET['state'])){
// Good Case
if ($_SESSION['fb_'.$fbconfig['appId'].'_state']===$_GET['state']) {
$_SESSION['login']=2;
}
else {
unset($_SESSION['login']);
echo 'You may be a victim of CSFR Attacks. Try logging in again.';
}
}
}
// State check O.K., swap Code for Token now
if($_SESSION['login']===2) {
$path = '/oauth/access_token';
$api_params = array (
'client_id'=>$appId,
'redirect_uri'=>$appUrl,
'client_secret'=>$secret,
'code'=>$_GET['code']
);
$access_token = $facebook->api($path, 'GET', $api_params);
var_dump($access_token);
}
The easiest way I found to do this is to extend the Facebook class and expose the protected getAccessTokenFromCode() method:
<?php
class MyFacebook extends Facebook {
/** If you simply want to get the token, use this method */
public function getAccessTokenFromCode($code, $redirectUri = null)
{
return parent::getAccessTokenFromCode($code, $redirectUri);
}
/** If you would like to get and set (and extend), use this method instead */
public function setAccessTokenFromCode($code)
{
$token = parent::getAccessTokenFromCode($code);
if (empty($token)) {
return false;
}
$this->setAccessToken($token);
if (!$this->setExtendedAccessToken()) {
return false;
}
return $this->getAccessToken();
}
}
I also included a variation on the convenience method I use to set the access token, since I don't actually need a public "get" method in my own code.

CakePHP 2.3.1 Facebook authentication

I'm using CakePHP 2.3.1 and this plugin: https://github.com/webtechnick/CakePHP-Facebook-Plugin to implement a facebook authentication. I followed this screen cast http://tv.cakephp.org/video/webtechnick/2011/01/12/nick_baker_--_facebook_integration_with_cakephp but it doesn't work, I can't receive the Facebook user information. I mean $this->Connect->user() always return null.
First make sure your user as granted access to your app. Then make a call to retrieve personal details through the api(/me) => $this->Connect->user()
Personally, I use this
public function beforeFilter(){
if($this->Connect->FB->getUser() != 0){
$this->set('facebookUser', $this->Connect->user());
}
Initiating ConnectComponent will populate (or not) the Auth Session. If no id is to be found, redirect user to a login dialog.
Call this method from beforefilter..and save the post data received in some variable like fb_data here.
protected function _valdiateFbRequest() {
if (!isset($this->request->data['signed_request'])) {
// not a valid request from fb
// throw exception or handle however you want
return;
}
$this->signedRequest = $this->request->data['signed_request'];
$this->fb_data=$this->Connect->registrationData(); //save fb data
unset($this->request->data['signed_request']);
if (empty($this->request->data)) {
$this->Security->csrfCheck = false;
}
// validate the request
}

ServiceStack OAuth - registration instead login

In servicestack OAuth implementation I only saw possibility to automatically login with eg. facebook account.
But is there abbility to support registration process with facebook login. What I wanted is to let users login to facebook app, and then load their Name, Surname and email and prefill needed text boxes for real registration on my site (since I also have to have mobile phone verification etc.) I don't want user to be authorized and authenticated when he logs in with facebook. Only credentials login should be valid one for full site access.
Edit: I found a solution.
In FacebookProvider.cs
public override bool IsAuthorized(IAuthSession session, IOAuthTokens tokens, Auth request = null)
{
if (request != null)
{
if (!LoginMatchesSession(session, request.UserName)) return false;
}
return tokens != null && session.UserName!=null && !string.IsNullOrEmpty(tokens.AccessTokenSecret);
}
The catch was the && session.UserName!=null part. So we can check if user is logged in using credentials, this will be !=null and user can use all services. If not, this will be ==null and he can only get facebook info from session.
The SocialBootstrap API project shows an example of handling the callback after a successful Authentication by overriding the OnAuthenticated() hook of its custom user session:
I've pulled out, rewrote some and highlighted some of the important bits:
public class CustomUserSession : AuthUserSession
{
public override void OnAuthenticated(IServiceBase authService,
IAuthSession session,
IOAuthTokens tokens,
Dictionary<string, string> authInfo)
{
base.OnAuthenticated(authService, session, tokens, authInfo);
//Populate matching fields from this session into your own MyUserTable
var user = session.TranslateTo<MyUserTable>();
user.Id = int.Parse(session.UserAuthId);
user.GravatarImageUrl64 = CreateGravatarUrl(session.Email, 64);
foreach (var authToken in session.ProviderOAuthAccess)
{
if (authToken.Provider == FacebookAuthProvider.Name)
{
user.FacebookName = authToken.DisplayName;
user.FacebookFirstName = authToken.FirstName;
user.FacebookLastName = authToken.LastName;
user.FacebookEmail = authToken.Email;
}
else if (authToken.Provider == TwitterAuthProvider.Name)
{
user.TwitterName = authToken.DisplayName;
}
}
//Resolve the DbFactory from the IOC and persist the user info
using (var db = authService.TryResolve<IDbConnectionFactory>().Open())
{
//Update (if exists) or insert populated data into 'MyUserTable'
db.Save(user);
}
}
//Change `IsAuthorized` to only verify users authenticated with Credentials
public override bool IsAuthorized(string provider)
{
if (provider != AuthService.CredentialsProvider) return false;
return base.IsAuthorized(provider);
}
}
Basically this user-defined custom logic (which gets fired after every successful authentication) extracts data from the UserSession and stores it in a custom 'MyUserTable'.
We've also overridden the meaning of IsAuthorized to only accept users that have authenticated with CredentialsAuth.
You can use this data to complete the rest of the registration.
Other possible customizations
ServiceStack's built-in Auth persists the AuthData and populates the Session automatically for you. If you want to add extra validation assertions you can simply use your own custom [Authentication] attribute instead containing additional custom logic. Look at the implementation of the built-in AuthenticateAttribute as a guide.