Announcement Announcement Module
Collapse
No announcement yet.
Quickstart JavaConfig with Spring Web Flow Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Quickstart JavaConfig with Spring Web Flow

    Hi all,

    I am integrating spring social into an existing spring web app that uses spring web flow.
    I am having trouble just getting anything to work right.

    A bit about my app:
    *Uses Spring/ Spring Web Flow
    * "Backend" web app for admin purposes

    What my goal is:
    * I need to integrate the social component for only a handful of users.
    * Only AFTER the user logs into our system, THEN the user can login to Twitter / Facebook/ Instagram .
    * The user can perform action specific to the SaaS provider. (can post new posts on Facebook).
    * I do NOT need the log in through provider feature (ProviderSignInController).
    * Save the accessToken (connection info) in a DB (postgres) for future connections.

    I am using the "quickstart" sample app from github.

    I have integrated the xml settings (to the best of my ability) and installed the needed jars. This appears to be configured ok, i have no errors upon deployment and the web app runs.

    I have the "login" page being displayed via SWF. Its lives in folder directory "/flows/social/signin"
    Attachment

    This page displays the "log into facebook" button. Same as from the quickstart sample app.

    Code:
    		
    		<form action="<c:url value="/app/social/signin/facebook" />" method="POST">
    		    <button type="submit">Sign in with Facebook</button>
    		    <input type="hidden" name="scope" value="email,publish_stream,offline_access" />		    
    		</form>
    FIRST ISSUE: When I click "login to facebook" I get a 404. Page not found error when I click this button.

    Where am I messing up? And also, how is the ConnectController receiving the request parameter "facebook" in this case?
    According to the reference doc, this controller automatically reads the request and takes the provider id from that, is that correct????

    I am basically trying to kickoff the OAuth dance for facebook with no luck.

    I have been reading the manual/ reference docs on all things Spring Social vigorously, and attacking StackOverflow and here in springsource community.... but I am stumped.

    SECOND: Do I remove ProviderSignInController completely? I have commented it out.

    THIRD: I have way more questions lol, first things first.

    Any help would be awesome!

    Thanks!

    Here are my modified HomeController, WebMVC and SocialConfig classes:



    HomeController.java
    Code:
    @Controller
    public class HomeController {
    
    	private final Facebook facebook;
    	
    	@Inject
    	public HomeController(Facebook facebook) {
    		this.facebook = facebook;
    	}
    
    	@RequestMapping(value = "/", method = RequestMethod.GET)
    	public String home(Model model) {
    		List<Reference> friends = facebook.friendOperations().getFriends();
    		model.addAttribute("friends", friends);
    		return "social/home";
    	}
    
    }



    WebMVC:
    Code:
    @Configuration
    @EnableWebMvc
    public class WebMvcConfig extends WebMvcConfigurerAdapter {
    
    	public void addInterceptors(InterceptorRegistry registry) {
    		registry.addInterceptor(new UserInterceptor(usersConnectionRepository));
    	}
    
    	public void addViewControllers(ViewControllerRegistry registry) {
    		registry.addViewController("/signin");
    		registry.addViewController("/signout");
    	}
    
    	@Bean
    	public ViewResolver viewResolver() {
    		InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
    		viewResolver.setPrefix("/social");
    		//viewResolver.setSuffix(".jsp");
                    //commented out setSuffix()...dont think i need that for SWF???
    		return viewResolver;
    	}
    
    	private @Inject UsersConnectionRepository usersConnectionRepository;
    
    }



    SocialConfig.java

    Code:
    @Configuration
    public class SocialConfig {
    
    	@Inject
    	private Environment environment;
    
    	@Inject
    	private DataSource dataSource;
    
    	/**
    	 * When a new provider is added to the app, register its {@link ConnectionFactory} here.
    	 * @see FacebookConnectionFactory
    	 */
    	@Bean
    	public ConnectionFactoryLocator connectionFactoryLocator() {
    		ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();
    		//registry.addConnectionFactory(new FacebookConnectionFactory(environment.getProperty("facebook.clientId"),
    				//environment.getProperty("facebook.clientSecret")));
    // hardcoded the clientId and clientSecret for dev purps
    		registry.addConnectionFactory(new FacebookConnectionFactory( "3210996879#####", "88092872e86eb928a36771a8c6b#####" ) );
    		return registry;
    	}
    
    
    	/**
    	 * Singleton data access object providing access to connections across all users.
    	 */
    	@Bean
    	public UsersConnectionRepository usersConnectionRepository() {
    		JdbcUsersConnectionRepository repository = new JdbcUsersConnectionRepository(dataSource,
    				connectionFactoryLocator(), Encryptors.noOpText());
    		repository.setConnectionSignUp(new SimpleConnectionSignUp());
    		return repository;
    	}
    
    	/**
    	 * Request-scoped data access object providing access to the current user's connections.
    	 */
    	@Bean
    	@Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)
    	public ConnectionRepository connectionRepository() {
    	    User user = SecurityContext.getCurrentUser();
    	    return usersConnectionRepository().createConnectionRepository(user.getId());
    	}
    
    	/**
    	 * A proxy to a request-scoped object representing the current user's primary Facebook account.
    	 * @throws NotConnectedException if the user is not connected to facebook.
    	 */
    	@Bean
    	@Scope(value="request", proxyMode=ScopedProxyMode.INTERFACES)	
    	public Facebook facebook() {
    	    return connectionRepository().getPrimaryConnection(Facebook.class).getApi();
    	}
    	
    	/**
    	 * The Spring MVC Controller that allows users to sign-in with their provider accounts.
    	 */
    // i do not need this service so i commented it out and put the ConnectController in its place. IS THAT RIGHT?
    //	@Bean
    //	public ProviderSignInController providerSignInController() {
    //		return new ProviderSignInController(connectionFactoryLocator(), usersConnectionRepository(),
    //				new SimpleSignInAdapter());
    //	}
    
    
           /* according to the reference doc, this controller automatically reads the request and takes the provider id from that???? */
    	@Bean 
    	public ConnectController connectController(){
    		ConnectController controller = new ConnectController( connectionFactoryLocator(), connectionRepository() );
    		controller.setApplicationUrl("mygreatwebsite.com/home");
    		return controller;
    	}
    }
    Attached Files
    Last edited by Dvs8r; Mar 28th, 2013, 01:41 PM.

  • #2
    Hi

    I'm not sure exactly how the controllers are configured in your application, but the Connect controller expects POST requests to "/connect/facebook" to instigate "connect with Facebook" flow.

    It looks from your code as if you are posting to "/signin/facebook" - I'm thinking this may be why you are getting 404.

    Hope this helps,

    Michael

    Comment


    • #3
      What Michael said. :-)

      You say you want your users to connect with Facebook/Twitter/etc *AFTER* they are signed into your application. That's the job for ConnectController, which responds to requests for /connect/{provider ID} (e.g., /connect/facebook).

      ProviderSignInController (which you say you have commented out) responds to requests for /signin/{provider ID}. ProviderSignInController's job is to authenticate your user via FB/Twitter/etc, which is what you indicated you do not want. If it's commented out, then that's why you're getting 404s.

      The quickstart sample is perhaps poorly named. It certainly shows a simple configuration for *one way* of using Spring Social, but it's not necessarily the only way or even the most common way. It primarily shows how to do pseudo-authentication of a user via FB. But it sounds like you want to create connections for users who are already authenticated to your app. In that case, you'll want to look at how ConnectController is used in the showcase samples.

      Comment


      • #4
        Hi michael,
        thanks for the response!

        yea i noticed that too from the manual, i tried that just now and I get a 404. Its looks like it's going through the Web Flow looking for that page 'mysite.com/app/social/connect/facebook'

        and getting the 404, becuase nothing is there.

        Should I be using the @RequestMapping on the ConnectController?

        Comment


        • #5
          habuma,

          Woah I got a response from the main man himself! nice!

          Basically getting the same thing when I make the change to the submit button.Heres the out from the logs below....I wonder are my JavaConfig classes correct?

          Code:
          2013-03-28 15:05:18,555 DEBUG ["http-bio-8944"-exec-192] (DispatcherServlet.java:819) DispatcherServlet with name 'app' processing POST request for [/rabeanco_yazFront/app/social/connect/facebook]
          2013-03-28 15:05:18,555 DEBUG ["http-bio-8944"-exec-192] (FlowHandlerMapping.java:114) No flow mapping found for request with URI '/rabeanco_yazFront/app/social/connect/facebook'
          2013-03-28 15:05:18,555 WARN  ["http-bio-8944"-exec-192] (DispatcherServlet.java:1080) No mapping found for HTTP request with URI [/rabeanco_yazFront/app/social/connect/facebook] in DispatcherServlet with name 'app'

          Comment


          • #6
            I also wonder why you're using "/app/social/connect/facebook". ConnectController listens at "/connect/{provider ID}". As you've used in in <c:url>, you shouldn't need to prefix it with "/app/social" (unless you're using an altered version of ConnectController with a different @RequestMapping)

            Comment


            • #7
              Perhaps my web.xml is off?

              I commented out the contextClass given in the sample app. I did this because my web app is mainly xml configured and I thought that this might conflict.(and it doesn't deploy)

              Code:
              		<!-- Java-based Spring container definition -->
               <!-- 	<context-param>
                  	<param-name>contextClass</param-name>
                  	<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
              	</context-param> -->
              If you can and care to, please have a look at my web.xml and let me know if there are any blaring mistakes.

              I can provide any other files needed to get to the heart of the issue.

              Thanks in advance!

              All the quickstart app configs are at the bottom:

              Code:
              <?xml version="1.0" encoding="ISO-8859-1"?>
              <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
              	version="3.0" metadata-complete="true">
              	<display-name>front</display-name>
              
              	<description>front</description>
              
              	<!-- INIT -->
              
              	<session-config>
              		<session-timeout>30</session-timeout>
              	</session-config>
              
              	<error-page>
              		<error-code>500</error-code>
              		<location>/WEB-INF/jsp/error/error500.jsp</location>
              	</error-page>
              
              	<error-page>
              		<error-code>404</error-code>
              		<location>/WEB-INF/jsp/error/error404.jsp</location>
              	</error-page>
              
              	<error-page>
              		<error-code>403</error-code>
              		<location>/WEB-INF/jsp/error/error403.jsp</location>
              	</error-page>
              
              	<error-page>
              		<error-code>400</error-code>
              		<location>/WEB-INF/jsp/error/error400.jsp</location>
              	</error-page>
              
              	<!-- FILTERS -->
              
              	<!-- set character encoding to UTF-8 -->
              	<filter>
              		<filter-name>SetCharacterEncodingFilter</filter-name>
              		<filter-class>org.apache.catalina.filters.AddDefaultCharsetFilter</filter-class>
              		<init-param>
              			<param-name>encoding</param-name>
              			<param-value>UTF-8</param-value>
              		</init-param>
              	</filter>
              
              	<filter-mapping>
              		<filter-name>SetCharacterEncodingFilter</filter-name>
              		<url-pattern>/*</url-pattern>
              	</filter-mapping>
              
              	<!-- sets the hostname of the app server into the response header with name 
              		"acdc_app" -->
              	<filter>
              		<filter-name>HostnameFilter</filter-name>
              		<filter-class>com.acadaca.util.servlet.filter.HostnameFilter</filter-class>
              	</filter>
              
              	<filter-mapping>
              		<filter-name>HostnameFilter</filter-name>
              		<url-pattern>/*</url-pattern>
              	</filter-mapping>
              
              	<filter>
              		<filter-name>SiteFromHostFilter</filter-name>
              		<filter-class>com.acadaca.yaz.application.servlet.filter.SiteFromHostFilter</filter-class>
              	</filter>
              
              	<filter-mapping>
              		<filter-name>SiteFromHostFilter</filter-name>
              		<url-pattern>/*</url-pattern>
              	</filter-mapping>
              
              	<!-- sets a request attribute called "generateStaticLinks" according to a request 
              		parameter or property. this way, you don't have to keep looking in two different 
              		places. -->
              	<filter>
              		<filter-name>StaticLinkingFilter</filter-name>
              		<filter-class>com.acadaca.yaz.application.servlet.filter.StaticLinkingFilter</filter-class>
              	</filter>
              
              	<filter-mapping>
              		<filter-name>StaticLinkingFilter</filter-name>
              		<url-pattern>/*</url-pattern>
              	</filter-mapping>
              
              	<!-- URL rewriting filter -->
              	<filter>
              		<filter-name>UrlRewriteFilter</filter-name>
              		<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
              		<init-param>
              			<param-name>confPath</param-name>
              			<param-value>/WEB-INF/classes/urlrewrite.xml</param-value>
              		</init-param>
              		<init-param>
              			<param-name>logLevel</param-name>
              			<param-value>INFO</param-value>
              		</init-param>
              	</filter>
              
              	<filter-mapping>
              		<filter-name>UrlRewriteFilter</filter-name>
              		<url-pattern>/*</url-pattern>
              	</filter-mapping>
              
              	<!-- logs if any page takes more than 1 second to respond -->
              	<filter>
              		<filter-name>ResponseTimeFilter</filter-name>
              		<filter-class>com.acadaca.util.servlet.filter.ResponseTimeFilter</filter-class>
              		<init-param>
              			<param-name>maximumThreshold</param-name>
              			<param-value>1000</param-value>
              		</init-param>
              	</filter>
              
              	<filter-mapping>
              		<filter-name>ResponseTimeFilter</filter-name>
              		<url-pattern>/*</url-pattern>
              	</filter-mapping>
              
              	<!-- for Spring Security - looks for a bean named "springSecurityFilterChain" 
              		which references all the Spring Security "filters" -->
              	<filter>
              		<filter-name>springSecurityFilterChain</filter-name>
              		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
              	</filter>
              
              	<filter-mapping>
              		<filter-name>springSecurityFilterChain</filter-name>
              		<url-pattern>/*</url-pattern>
              	</filter-mapping>
              
              	<!-- LISTENERS -->
              
              	<!-- some stuff to take care of when the context (web app) is shutdown -->
              	<listener>
              		<listener-class>com.acadaca.util.application.listener.ShutdownListener</listener-class>
              	</listener>
              
              	<!-- creates a root WebApplicationContext based off the "contextConfigLocation" 
              		context-param -->
              	<listener>
              		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
              	</listener>
              
              	<!-- CONTEXT PARAMS -->
              
              	<context-param>
              		<param-name>javax.servlet.jsp.jstl.fmt.fallbackLocale</param-name>
              		<param-value>en</param-value>
              	</context-param>
              
              	<context-param>
              		<param-name>contextConfigLocation</param-name>
              		<param-value>/WEB-INF/spring/app-root.xml /WEB-INF/spring/security-app-context.xml</param-value>
              	</context-param>
              
              	<!-- SERVLETS -->
              
              	<!-- registers a DispatcherServlet with its own WebApplicationContext whose 
              		parent is the root WebApplicationContext -->
              	<servlet>
              		<servlet-name>app</servlet-name>
              		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
              		<init-param>
              			<param-name>detectAllViewResolvers</param-name>
              			<param-value>false</param-value>
              		</init-param>
              		<init-param>
              			<param-name>contextConfigLocation</param-name>
              			<param-value>/WEB-INF/spring/app-servlet.xml /WEB-INF/spring/app-webflow.xml</param-value>
              		</init-param>
              		<load-on-startup>1</load-on-startup>
              	</servlet>
              
              	<servlet-mapping>
              		<servlet-name>app</servlet-name>
              		<url-pattern>/app/*</url-pattern>
              	</servlet-mapping>
              
              	<servlet>
              		<servlet-name>AdminServlet</servlet-name>
              		<servlet-class>com.acadaca.yaz.application.servlet.AdminServlet</servlet-class>
              	</servlet>
              
              	<servlet-mapping>
              		<servlet-name>AdminServlet</servlet-name>
              		<url-pattern>/servlet/AdminServlet</url-pattern>
              	</servlet-mapping>
              	
              	<!-- ##### TEST TEST TEST QUICKSTART APP ############ -->
              	
              	<!-- Enables support for DELETE and PUT request methods with web browser clients -->
              	<filter>
              		<filter-name>hiddenHttpMethodFilter</filter-name>
              		<filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
              	</filter>
              
              	<filter-mapping>
              		<filter-name>hiddenHttpMethodFilter</filter-name>
              		<url-pattern>/*</url-pattern>
              	</filter-mapping>
              
              	<!-- H2 Database Console for managing the app's database -->
              	<servlet>
              		<servlet-name>H2Console</servlet-name>
              		<servlet-class>org.h2.server.web.WebServlet</servlet-class>
              		<init-param>
              			<param-name>-webAllowOthers</param-name>
              			<param-value>true</param-value>
              		</init-param>
              		<load-on-startup>2</load-on-startup>
              	</servlet>
              
              	<servlet-mapping>
              		<servlet-name>H2Console</servlet-name>
              		<url-pattern>/admin/h2/*</url-pattern>
              	</servlet-mapping>
              	
              		<!-- Java-based Spring container definition -->
               <!-- 	<context-param>
                  	<param-name>contextClass</param-name>
                  	<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
              	</context-param> -->
              		
              		<!-- Location of Java @Configuration classes that configure the components that makeup the quickstart social application -->
              	<context-param>
                  	<param-name>contextConfigLocationSocial</param-name>
                  	<param-value>com.acadaca.yaz.app.social.config</param-value>
              	</context-param>
              	
              
              </web-app>

              Comment


              • #8
                Is the Spring Social configuration (which I'm guessing is still in Java-based configuration) even being read?

                If you're using primarily XML config, then you'll need to either make sure that the @Configuration classes are discovered by component-scanning or explicitly declare them as <bean>s. Otherwise, they won't be loaded and that would explain why you get 404.

                Comment


                • #9
                  Originally posted by habuma View Post
                  I also wonder why you're using "/app/social/connect/facebook". ConnectController listens at "/connect/{provider ID}". As you've used in in <c:url>, you shouldn't need to prefix it with "/app/social" (unless you're using an altered version of ConnectController with a different @RequestMapping)
                  Craig,

                  Even when I use "/connect/{provider ID}" on the c:url, it comes out like that.

                  POST request for [/rabeanco_yazFront/connect/facebook]

                  It looks like a SWF thing (or the way we have it configured?).

                  How can I tell if my java configurations are being loaded into the spring context for sure?

                  And also can you tell me if my WebMVCConfig file is correct?(its in the first post)

                  When I am on the sign in page the url looks like this:
                  http://www.website.com/rabeanco_yazF.../social/signin


                  Also...
                  I know this is probably not the answer but, i get different results with and without the leading slash on the c:url

                  Without the leading slash...
                  <c:url value="connect/facebook" />
                  I click the button and it goes to...
                  http://www.website.com/rabeanco_yazF...nnect/facebook

                  WITH the leading slash..
                  <c:url value="/connect/facebook" />
                  I click the button and it goes to...
                  http://www.website.com/rabeanco_yazF...nnect/facebook

                  Comment


                  • #10
                    Im gonna switch over to the new XML namespace config. I have showcase xml sample up and running on tcServer via Eclipse...so that shuld help alot (as did you)
                    Thanks again.

                    Ill post back here when I get it running.

                    Comment


                    • #11
                      Originally posted by Dvs8r
                      Troll spam.
                      Yes, and I've now deleted it. I'm also going to delete your reply because your reply contained the original spam link in it. No need in the spammers getting any additional attention just because you quoted their link.

                      Comment

                      Working...
                      X