Separating jhipster back-end and front-end into two projects?

12,277

Solution 1

When requests fail due to CORS, there is no visible error on the backend. The HTTP request actually succeeds, but is blocked on the front-end side by javascript. A message like this one will appear in the JS console.

XMLHttpRequest cannot load http://localhost:8080/api/authenticate. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:9000' is therefore not allowed access.

The error message you're seeing is actually related to authentication. When you enable CORS, your JS will send ''pre-flight'' requests using the HTTP OPTIONS method. JHipster isn't configured to allow the OPTIONS method globally. I ran into this exact same problem myself while doing the same thing you did. The fix is very simple: just add this line to your com.mycompany.config.SecurityConfiguration immediately preceding (before) the first antMatchers entry.

.antMatchers(org.springframework.http.HttpMethod.OPTIONS, "/api/**").permitAll()

This will explicitly allow all requests with the OPTIONS method. The OPTIONS method is used in CORS as a way to read all of the headers and see what HTTP methods are allowed in the CORS request.

Finally, in your SimpleCORSFilter class, you should also add these headers:

response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "86400"); // 24 Hours
response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, x-auth-token");

Solution 2

Separating frontend and backend in JHipster application is quite simple. Please follow the steps mentioned below if you want to setup frontend and backend applications separately and individually using JHipster:

  1. Create two directories for frontend and backend applications

    • mkdir frontend
    • mkdir backend
  2. change your directory to frontend and run the JHipster command to create just frontend module

    • cd frontend
    • jhipster --skip-server --db=sql --auth=jwt
    • if all works fine, run npm start command to run your frontend application.

    I'm using mysql for db and JWT for auth and if you want to use websockets you add: "--websocket=spring-websocket"

  3. Now, change your directory to the backend and run JHipster command to create just backend module

    • cd .. //as we are ing backend directory currently
    • cd backend
    • jhipster --skip-client
    • Run your backend application as you run your spring boot application

Now, your frontend and backend application are running separately and individually and frontend is coordinating with the backend application via REST API calls.

Solution 3

You can use CORS filter from Tomcat. Put Tomcat dependency in the pom.xml:

   <dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-catalina</artifactId>
        <version>8.0.15</version>
        <scope>provided</scope>
    </dependency>

Use whatever version of Tomcat you use.

Add CORS filter initialization in WebConfigurer:

private void initCorsFilter(ServletContext servletContext, EnumSet<DispatcherType> disps) {
        log.debug("Registering CORS Filter");
        FilterRegistration.Dynamic corsFilter = servletContext.addFilter("corsFilter", new CorsFilter());
        Map<String, String> parameters = new HashMap<>();
        parameters.put("cors.allowed.headers", "Content-Type,X-Requested-With,accept,Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Authorization");
        parameters.put("cors.allowed.methods", "GET,POST,HEAD,OPTIONS,PUT,DELETE");
        corsFilter.setInitParameters(parameters);
        corsFilter.addMappingForUrlPatterns(disps, false, "/*");
        corsFilter.setAsyncSupported(true);
    }

put this line in WebConfigurer.onStartup(...), put it as close to the top as possible.

...
initCorsFilter(servletContext, disps);
...

Solution 4

In addition to xeorem's answer above, I also had to modify the parse-links-service.js to handle the preflight OPTIONS responses, which don't have the "link" response header:

var links = {};
if (!angular.isObject()) {
    // CORS OPTIONS responses
    return links;
}

if (header.length == 0) {
    throw new Error("input must not be of zero length");
}

// Split parts by comma
var parts = header.split(','); 

...

Instead of adding API_URL to app.js, modify Gruntfile.js and add the API_URL to the ngConstants block for both DEV and PROD environments.

Share:
12,277

Related videos on Youtube

musa
Author by

musa

Updated on March 16, 2021

Comments

  • musa
    musa about 3 years

    I'm trying jhipster with token-based authentication. It works perfectly.

    Now, I want to run back-end and front-end code on different domains. How can I do this?


    This is what I tried:

    1. Run yo jhipster and select token-based authentication option:

      Welcome to the JHipster Generator
      
      ? (1/13) What is the base name of your application? jhipster
      ? (2/13) What is your default Java package name? com.mycompany.myapp
      ? (3/13) Do you want to use Java 8? Yes (use Java 8)
      ? (4/13) Which *type* of authentication would you like to use? Token-based authentication (stateless, with a token)
      ? (5/13) Which *type* of database would you like to use? SQL (H2, MySQL, PostgreSQL)
      ? (6/13) Which *production* database would you like to use? MySQL
      ? (7/13) Which *development* database would you like to use? H2 in-memory with Web console
      ? (8/13) Do you want to use Hibernate 2nd level cache? Yes, with ehcache (local cache, for a single node)
      ? (9/13) Do you want to use clustered HTTP sessions? No
      ? (10/13) Do you want to use WebSockets? No
      ? (11/13) Would you like to use Maven or Gradle for building the backend? Maven (recommended)
      ? (12/13) Would you like to use Grunt or Gulp.js for building the frontend? Grunt (recommended)
      ? (13/13) Would you like to use the Compass CSS Authoring Framework? No
      
      ...
      
      I'm all done. Running bower install & npm install for you
      ^C
      
    2. Make two copies of the project as jhipster/backend and jhipster/frontend

    3. Delete unnecessary files from back-end and front-end

      rm -rf backend/.bowerrc
      rm -rf backend/.jshintrc
      rm -rf backend/bower.json
      rm -rf backend/Gruntfile.js
      rm -rf backend/package.json
      rm -rf backend/src/main/webapp
      rm -rf backend/src/test/javascript
      
      rm -rf frontend/pom.xml
      rm -rf frontend/src/main/java
      rm -rf frontend/src/main/resources
      rm -rf frontend/src/test/gatling
      rm -rf frontend/src/test/java
      rm -rf frontend/src/test/resources
      
    4. Make changes in code to completely remove backend/frontend dependency

      • frontend/Gruntfile.js

        ...
        var parseVersionFromPomXml = function() {
            return '1.2.2.RELEASE';
        };
        ...
        browserSync: { ..., proxy: "localhost:8081" }
        
      • frontend/src/main/webapp/scripts/app/app.js

        angular.module('jhipsterApp', [...])
        .constant('API_URL', 'http://localhost:8080/')
        .run( ... )
        
      • frontend/src/main/webapp/scripts/**/*.service.js

        angular.module('jhipsterApp').factory(..., API_URL) {
            return $http.post(API_URL + 'api/authenticate', ...);
        }
        
        angular.module('jhipsterApp').factory('Account', function Account($resource, API_URL) {
            return $resource(API_URL + 'api/account', {}, {...});
        }
        
        // Make similar changes in all service files.
        
      • backend/pom.xml

        Remove yeoman-maven-plugin

      • backend/src/main/java/com/mycompany/myapp/SimpleCORSFilter.java

        // Copied from here: https://spring.io/guides/gs/rest-service-cors/
        
        @Component
        public class SimpleCORSFilter implements Filter {
            public void doFilter(...) {
                ...
                response.setHeader("Access-Control-Allow-Origin", "*");
                ...
            }
        }
        
    5. Run

      • Terminal Tab #1: BACKEND

        cd backend
        mvn spring-boot:run
        
        ...
        [INFO] com.mycompany.myapp.Application - Started Application in 11.529 seconds (JVM running for 12.079)
        [INFO] com.mycompany.myapp.Application - Access URLs:
        ----------------------------------------------------------
                Local:          http://127.0.0.1:8080
                External:       http://192.168.56.1:8080
        ----------------------------------------------------------
        
      • Terminal Tab #2: FRONTEND

        cd frontend/src/main/webapp
        npm install -g http-server
        http-server
        
        Starting up http-server, serving ./ on: http://0.0.0.0:8081
        Hit CTRL-C to stop the server
        
      • Terminal Tab #3: GRUNT

        cd frontend
        bower install
        npm install
        grunt serve
        
        ...
        [BS] Proxying: http://localhost:8081
        [BS] Access URLs:
         -------------------------------------
               Local: http://localhost:3000
            External: http://10.34.16.128:3000
         -------------------------------------
                  UI: http://localhost:3001
         UI External: http://10.34.16.128:3001
         -------------------------------------
        
    6. Browse http://localhost:3000/#/login

      Enter username:password as admin:admin

      Our BACKEND tab reads:

      [DEBUG] com.mycompany.myapp.security.Http401UnauthorizedEntryPoint - Pre-authenticated entry point called. Rejecting access
      

    Apparently, I'm doing something wrong. What is it?

    • Rori Stumpf
      Rori Stumpf about 9 years
      Just a thought, but perhaps you could double check that the back end is able to process valid credentials. See stackoverflow.com/questions/28269487/…
    • Daniel Gerber
      Daniel Gerber over 8 years
      Have you managed to get this running?
    • musa
      musa over 8 years
      @Daniel Unfortunately no. I stopped playing with jhipster short after I asked this question.
    • xeorem
      xeorem about 8 years
      @musa My answer below has helped a few others and is the way I solved the problem. Please take a look and consider marking it as the accepted answer.
  • Gaurav Wadhwani
    Gaurav Wadhwani over 4 years
    Now you want to deploy it on Prod, you will create a single war/jar to deploy. What all files will you have to change in the project?
  • Bilal Ahmed Yaseen
    Bilal Ahmed Yaseen over 4 years
    For deployment, better way is to deploy both frontend and backend separately. Backend on tomcat and frontend on apache.
  • Gaurav Wadhwani
    Gaurav Wadhwani over 4 years
    Thanks . But I want to deploy on Google App Engine . Should I make two different projects for it then ?
  • qleoz12
    qleoz12 over 3 years
    how do you connect the frontend app with backend app (yes i can use rest calls but...)?, I get SERVER_API_URL: ''