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:
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
Make two copies of the project as jhipster/backend
and jhipster/frontend
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
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", "*");
...
}
}
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
-------------------------------------
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?
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");