Announcement Announcement Module
Collapse
No announcement yet.
After signin being redirected to main domain and not canvas url? Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • After signin being redirected to main domain and not canvas url?

    I'm brand new to using Spring Social (and only moderately skilled in Spring as a whole.) I'm trying to get things working correctly for a Facebook app.

    I currently have a dummy app for testing that I set up on facebook (using foobar.com for sake of discussion.)

    The canvas page url is set to:
    https://apps.facebook.com/myappname/

    and the Canvas url:
    http://www.foobar.com/fb/app


    I took the spring-social-quickstart-3.0.x app as a guide and basically took all those classes/files and moved them into my facebook application (basically hello world - just trying to get 'hello world' to show up in the fb iframe - the canvas url.) (We're not on spring3.1)

    Now, if you go to the application https://apps.facebook.com/myappname/ without having first signed into facebook, you see the signin button and you can sign in and accept permissions etc (although even that flow seems a bit odd which I can explain more about in another post.) The problem is, after signing in and accepting fb permissions, you end up being redirected to http://www.foobar.com and not to the app at https://apps.facebook.com/myappname/ (I'd expect to see the site mapped to the canvas url.)

    If you then go and put https://apps.facebook.com/myappname/ in the url bar you WILL end up with the canvas url page coming up (http://www.foobar.com/fb/app), so spring social is seeing you as logged in.

    Did I set something up wrong? Maybe within the facebook app setup?

    Thanks for any help

  • #2
    I think this is the first time I've heard of anyone running a Spring Social-based app as a canvas app. (Admittedly, I've not tried it, but I'll be trying it soon.) But it should work. You probably just need to configure ProviderSignInController's postSignInUrl property to point to "https://apps.facebook.com/myappname/". Since you're using stuff from spring-social-quickstart-3.0.x, find the ProviderSignInController bean in controllers.xml and change it to:

    Code:
    	<bean class="org.springframework.social.connect.web.ProviderSignInController">
    		<constructor-arg ref="connectionFactoryLocator" />
    		<constructor-arg ref="usersConnectionRepository" />		
    		<constructor-arg>
    			<bean class="org.springframework.social.quickstart.user.SimpleSignInAdapter" />
    		</constructor-arg>
    		<property name="postSignInUrl" value="https://apps.facebook.com/myappname/" />
    	</bean>
    I imagine that would work. Let me know if it doesn't and we'll try to sort it out.

    Comment


    • #3
      Originally posted by habuma View Post
      Code:
      	<bean class="org.springframework.social.connect.web.ProviderSignInController">
      		 ....
      		<property name="postSignInUrl" value="http://apps.facebook.com/myappname/" />
      	</bean>
      Thanks! That certainly did do the trick. (Wouldn't have even known to look there so appreciated the quick response.)

      Side bar question: that has me wondering if I'm thinking about things in the wrong way since you mentioned "I think this is the first time I've heard of anyone running a Spring Social-based app as a canvas app. "

      Since this is the first time you heard of it, maybe I'm not doing things in a typical fashion? In our case we'll be wanting to run a facebook application (really just a website) within a facebook canvas so that it looks more seamless while a user is in facebook rather than breaking them out into a new window.

      We will obviously be using the spring social stuff to do things like post to their wall etc, but our first plan is to use spring social to 'grab their facebook userid (email)'

      With this facebook e-mail, I'll go to the backend to see if that facebook id (email) is associated with a valid user in our db. If it is, we sign the user in and they'll see the application within the facebook canvas.

      If that facebook email is NOT in our db, they'll be viewing a 'join page' within the canvas, in which they can signup (we can't just use facebook's sign in alone since we need more demographic information before we can have them join.) (Note, we'll also be able to leverage spring social to pull in facebook demographic information that they might have already completed within fb - such as sex and age and we could thus leave those fields off of the join form.)

      Does this sound like a decent approach to take?

      You have me a bit worried since you mentioned this is the first time you heard of someone using a spring social app within a facebook canvas.

      Thanks for any more of you thoughts.

      Comment


      • #4
        I didn't mean to worry you. Really there should be minimal differences between canvas apps and non-canvas apps.

        Think of the world of FB apps as falling into two categories: Those that run in the FB canvas for the seamless look-n-feel you mention and those that interact with FB, but aren't presented inside of the canvas. Foursquare, for example, is an application that does not run inside of the FB canvas, but does interact with FB. There's really not much difference in the programming model between canvas apps and non-canvas apps. In both cases the app runs "elsewhere" (where "elsewhere" is on some server that doesn't belong to FB). It's really just a presentation detail of whether it will be presented in the canvas iframe or in the browser as a standalone app. Of course, as you've discovered, running inside of the canvas iframe presents some special circumstances, especially with regard to redirect URLs.

        Whether it runs in the canvas or not, the app can still connect to FB on behalf of a user and interact with FB (perhaps fetching the user's email address). That really has little to do with the canvas and everything to do with authorizing the app via OAuth and using the REST API to interact with FB.

        In any event, the flow you're describing sounds very much like what Spring Social's ProviderSignInController does. ProviderSignInController lets the user sign in via FB (or whatever provider), fetches the user's ID on that provider, compares that ID with a known set of connected users and if a match is found it signs them in. If no match is found, it goes to a user-defined signup page.

        Is that something similar to what you're trying to do?

        Comment


        • #5
          Originally posted by habuma View Post
          In any event, the flow you're describing sounds very much like what Spring Social's ProviderSignInController does. ProviderSignInController lets the user sign in via FB (or whatever provider), fetches the user's ID on that provider, compares that ID with a known set of connected users and if a match is found it signs them in. If no match is found, it goes to a user-defined signup page.

          Is that something similar to what you're trying to do?
          I 'think so' yes. So looking now in more detail at the code (from the spring-social-quickstart-3.0.x), it looks like I would:

          1) Keep the connectionFactoryLocator tied to the FacebookConnectionFactory (as provided in SocialConfig.) That's what is getting me the "facebook user" (and will have them signin to facebook if they haven't already.)

          2) Provide a different usersConnectionRepository returned from the SocialConfig.. instead of relying on the JdbcUsersConnectionRepository provided in the example, I'd have my own UsersConnectionRepository (eg "MyAppUsersConnectionRepository.") ?

          I'll have to explore (look at the source code) to see how those three UsersConnectionRepository interface methods are implemented in some other concrete implementations though. At this stage since I'm new to the framework they look a little confusing. Maybe there is a simpler approach? All I'll basically be doing (in pseudo code):

          "If a user's email (user signed into facebook) exists in our table of valid users, let them in."

          Actually maybe I just need to create my own SimpleConnectionSignUp and then just use the JdbcUsersConnectionRepository? (but I'm a bit lost there.) I definitely need to read a bit more since I'm jumping the gun a bit I know on some of these questions.

          Comment


          • #6
            Ok, I stepped back a bit and read more of the base Spring Social docs. I see now my idea of what the UserConnectionsRepository was for was off... that factory stores the user connections from the connectionsFactoryLocator (eg. FacebookConnectionFactory.) (Do most people just rely on that JDBC provided one or do they roll their own?)

            With the above in mind, I think my flow couldn't all be handled in one provider could it?

            For example, after my facebook authentication comes back, I still have to then check to see if they are in "our internal db tied to that facebook email." At this point the FacebookProvider I'm assuming already added them to the userConnectionRepository since they successfully signed in to Facebook.

            So after I do a manual check (in my initial controller - calling my own injected service class) with the email of the facebook user I'd either redirect to them the join page, or let them in.

            Do I have things correct? Or is there some provider I could use to that "other check against my company db to check the fb email?"

            Comment


            • #7
              Regarding UsersConnectionsRepository: Yes, its job is to store/retrieve user connections. Right now Spring Social only provides a JDBC implementation. But you could always implement your own if that one doesn't meet your needs (I'd be curious to know how you'd prefer to implement it). In fact, the Spring Andoid project comes with an SQLite implementation and there's work being done in the community on a JPA implementation.

              So you're saying that instead of comparing the user's FB ID with the FB ID of a previously established connection (which is what ProviderSignInController does), your app won't have any previously established connections and you'd want to compare the email you get from FB with the email you already have on record for the user in your app's DB? Sounds very do-able and quite similar to what ProviderSignInController does.

              But in your case, I wouldn't try to work it in alongside ProviderSignInController--I'd probably look at the source for ProviderSignInController, understand what it does and write a new (but similar) sign-in controller that handles the sign-in by comparing emails against your user DB instead of comparing FB IDs against the connection table.

              FWIW, the reason ProviderSignInController uses the user's provider ID and not email or some other field is because the ID is constant. Emails can change (and many providers don't even give out their user's emails), so we can't reliably do login via a provider based on email. But FB does give out email addresses (with the right permissions) and if you can trust that your user's FB email will match their email in your DB, then you could do it that way. But you'll need to roll your own sign-in controller to deal with emails instead of IDs. If you do that, I'd be interested in seeing what you come up with.

              Comment


              • #8
                Originally posted by habuma View Post
                Regarding UsersConnectionsRepository: Yes, its job is to store/retrieve user connections. Right now Spring Social only provides a JDBC implementation. But you could always implement your own if that one doesn't meet your needs (I'd be curious to know how you'd prefer to implement it). In fact, the Spring Andoid project comes with an SQLite implementation and there's work being done in the community on a JPA implementation.
                I think maybe to avoid too many changing pieces at one time, I'll be fine just sticking to that JDBC one.

                Originally posted by habuma View Post
                So you're saying that instead of comparing the user's FB ID with the FB ID of a previously established connection (which is what ProviderSignInController does), your app won't have any previously established connections and you'd want to compare the email you get from FB with the email you already have on record for the user in your app's DB?
                That is exactly correct.

                Originally posted by habuma View Post
                Sounds very do-able and quite similar to what ProviderSignInController does.
                But in your case, I wouldn't try to work it in alongside ProviderSignInController--I'd probably look at the source for ProviderSignInController, understand what it does and write a new (but similar) sign-in controller that handles the sign-in by comparing emails against your user DB instead of comparing FB IDs against the connection table.
                Hmm, ok then would I even really need the UsersConnectionsRepository? Looks like I'd probably always skip checking there? I definitely want the fb provider acting like it does now - handling all the oath2 stuff etc. I think you're saying that I'd tweak my own version so that at the end rather than saying "ok this guy is good, let him through" - I'd first compare in that provider ID to our DB to see if the ID matches and if doesn't redirect them to the appropriate join page.

                Originally posted by habuma View Post
                FWIW, the reason ProviderSignInController uses the user's provider ID and not email or some other field is because the ID is constant. Emails can change (and many providers don't even give out their user's emails), so we can't reliably do login via a provider based on email.
                Agreed, the provider ID will be much better to use.

                PS (nice job on spring in action 3rd edition. Reading the ebook now.)

                Comment


                • #9
                  If all you want to do is handle the signin case you describe, then I suppose there's no need to store the connection once you've found your user. But if you intend to use any part of the FB API after sign-in you should store it so that you won't have to get at the Facebook API binding on your own.

                  Note in SocialConfig.java how the repository isn't just used to store connections, but also to ultimately get the primary connection to create the Facebook bean (which is the API binding). In this way your code never directly deals with the access token...you just inject a Facebook and use it however you like. HomeController uses it to fetch the user's list of friends.

                  If you don't do this, then creating a usable Facebook object later will be much more difficult because you will have lost the connection details (including the access token needed to construct a FacebookTemplate).

                  Comment


                  • #10
                    Originally posted by habuma View Post
                    If all you want to do is handle the signin case you describe, then I suppose there's no need to store the connection once you've found your user. But if you intend to use any part of the FB API after sign-in you should store it so that you won't have to get at the Facebook API binding on your own.
                    Good point. I forgot about that. We will want to access the FB API for sure after they connect so I definitely want to save the connection.

                    So, if I'm understanding correctly, once I understand "where" I need to do things (looking at source code now), my plan would be to not put the user into the userConnectionsRepository until AFTER I made that quick check to our own backend to make sure that fb provider id existed in our tables. Looking at the ProviderSigninController now and looks like I'd make my own based off of it with a few tweaks here and there... although I'm wondering if a cleaner approach would be to somehow keep that ProviderSigninController 'as is,' since it works for the FB part (fb signin), but now have a chain where it goes to the next step which is another provider (my custom provider.) Basically the postSignInUrl provided for ProviderSigninController would be a mapping to hit my next SigninProvider? This way I keep things clean where the FB one deals with FB and this other SigninProvider deals with the next step. Maybe that's making things too complicated though?

                    I have the source code of Spring Social and SpringSocialFacebook opened in IDEA so I'll look at things more closely. I'm curious where the actual placing of the user into the usersConnectionRepository takes place. Looks like that task is independent of a successful signin within the ProviderSigninController which I thought would be taking place in the signinAdapter - but looking at the SimpleSignInAdapter used in the example code it adds a cookie but I don't see anything related to a user being added to the usersConnectionRepository. I "think" it's happening the first time a call is made to get the facebook api (looking at SocialConfig.) But that is confusing as well since it would created after a call to SocialConfig facebook() - yet I've searched all three projects (spring social, spring social fb, and the demo app) and don't see where the call is being made (my guess is an xml file I missed somewhere?)

                    Comment


                    • #11
                      See the ref docs, Sign in chapter and spring-social-showcase sample for illustration. In short, it's the application developer's responsibility to "handlePostSignUp" in the context of a ProviderSignInAttempt that results in a new user signing up. This involves associating the Connection with the new local user account by adding it to the repository.

                      Keith

                      Comment


                      • #12
                        Hi,

                        I was wondering if this is working? I have a canvas application and when I point it to the canvas url, it doesn't seem to work.
                        I am getting the following error i

                        type Status report

                        message Request method 'POST' not supported

                        description The specified HTTP method is not allowed for the requested resource (Request method 'POST' not supported).

                        here is how I set up the configuration:

                        <?xml version="1.0" encoding="UTF-8"?>
                        <beans xmlns="http://www.springframework.org/schema/beans"
                        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                        xmlns:mvc="http://www.springframework.org/schema/mvc"
                        xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schem...ng-mvc-3.0.xsd
                        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

                        <!-- Controls rendering of the home page once a user has signed in -->
                        <bean class="org.springframework.social.quickstart.HomeC ontroller">
                        <constructor-arg ref="facebook" />
                        </bean>

                        <!-- Allows users to sign-in with their provider accounts. -->
                        <bean class="org.springframework.social.connect.web.Prov iderSignInController">
                        <constructor-arg ref="connectionFactoryLocator" />
                        <constructor-arg ref="usersConnectionRepository" />
                        <constructor-arg>
                        <bean class="org.springframework.social.quickstart.user. SimpleSignInAdapter" />
                        </constructor-arg>
                        <property name="postSignInUrl" value="http://apps.facebook.com/myApps/" />
                        </bean>
                        <mvc:view-controller path="/signin" />

                        <mvc:view-controller path="/signout" />

                        </beans>

                        Any help/
                        Last edited by vossgeraldo; Aug 5th, 2011, 02:38 PM.

                        Comment


                        • #13
                          Originally posted by vossgeraldo View Post
                          Hi,

                          I was wondering if this is working? I have a canvas application and when I point it to the canvas url, it doesn't seem to work.
                          I am getting the following error i

                          type Status report

                          message Request method 'POST' not supported

                          description The specified HTTP method is not allowed for the requested resource (Request method 'POST' not supported).
                          "connectjob" is mapped to a canvas url which maps to one of your controllers. Let's assume the connectjob maps to mydomain.com/myapp In that controller you probably have the method mapped as:

                          @RequestMapping(value="/myapp", method = RequestMethod.POST)

                          This is actually correct though and should be a POST. Are you sure that ProviderSignInController is actually being called? And also, are you sure the controller method for your canvas url isn't being called? - maybe you're doing something funky in that controller like redirecting to a method that you have set for a POST when it needs to be a GET.

                          Comment


                          • #14
                            Thank you very much for the quick reply. I change my RequestMapping method to post and it is working.

                            Best Regards,

                            Comment

                            Working...
                            X