Giter VIP home page Giter VIP logo

angularjs-jwt-spring-security-demo's Introduction

Angularjs JDBC Authentication JWT Spring Security demo

Overview

This is a demo of a Spring boot application with JDBC authentication of Spring Security along with JSON Web Token (JWT) authorization (with CSRF) with AngularJS front-end. This is just a demo application with two simple UI pages. One, a login page. Two, a Greeting page. And a logout page. The Greeting page appears once the user is authenticated. The subsequent interactions are based on JWT authorization (using JWT library for Java).

Pre-requisites

  • Java 1.8
  • MySQL server (v5.7)
  • AngularJS (v1.6.4)
  • Bower - for installing JS libraries/packages
  • Npm - for installing grunt plugins
  • Apache Maven (v3.3.9) - to manage project dependencies, build & run.
  • Grunt

Features

  • Spring Security - JDBC Authentication
  • JWT authorization (along with CSRF protection)
  • HTTPS enabled, HTTP to HTTPS automatic redirection (requires creating a keystore)
  • RESTful API endpoint based interaction
  • AngularJS v1.6.4
  • Used Grunt tasks to include JS/CSS files of libraries to index.html

Build/Run

The angularjs template page can be built by running grunt in command prompt (after navigating to the project's directory). Then start the application with the Spring Boot maven plugin command - mvn spring-boot:run. The application is running at https://localhost:8443

Features Explained

Spring Security - JDBC Authentication

With MySQL server installed in the machine, the following configuration properties are included in our application.properties.

# ===============================
# = DATA SOURCE
# ===============================
spring.datasource.url=jdbc:mysql://localhost:3306/db_example
spring.datasource.username=springuser
spring.datasource.password=ThePassword
spring.datasource.testWhileIdle = true
spring.datasource.validationQuery = SELECT 1

# ===============================
# = JPA / HIBERNATE
# ===============================
spring.jpa.show-sql = true
spring.jpa.hibernate.ddl-auto = update
spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect

Here, db_example is the schema that needs to be created in the MySQL server under the user springuser whose password is ThePassword. (This can be done using MySQL workbench)

The property value of spring.jpa.hibernate.ddl-auto has to be create the first time you run the application. After which, you can change it to update. (The lines are self-explanatory)

The JDBC authentication of Spring security is enabled by the following lines of code in one of our Configurtion classes,

protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
		auth.
			jdbcAuthentication()
				.usersByUsernameQuery(usersQuery)
				.authoritiesByUsernameQuery(authoritiesQuery)
				.dataSource(dataSource)
				.passwordEncoder(bCryptPasswordEncoder);
}

The parameters usersQuery & authoritiesQuery are defined in the class that bind the values from our application.properties.The dataSource properties are also defined in our application.properties.

spring.queries.users-query=select name, password, enabled from user where name=?
spring.queries.authorities-query=select u.name, a.authority from user u inner join user_authority ua on(u.user_id=ua.user_id) inner join authority a on(ua.authority_id=a.authority_id) where u.name=?

So, the application authenticates the user based on entries in three tables user user_authority & authority. Therefore, insert the records into the tables like,

INSERT INTO db_example.user VALUES(1,'[email protected]', true, 'ananthan', now(), 'sneha', '$2a$04$oRXJV.xZW8k2nXDIBvMXFOOpflEaXGVyxA.WxwoAQuZTIBI871RyG');

INSERT INTO db_example.authority VALUES (1,'ADMIN');

INSERT INTO db_example.user_authority VALUES (1, 1);

We use bcrypt to encrypt the passwords. Here is an online Bcrypt Generator. For encrypting passwords in our application, we use BCryptPasswordEncoder class provided by Spring Security itself. (Easy right!?)

JWT authorization with CSRF protection

Once the user is authenticated, the server returns a JWT token to the client. This JWT is used for authorising all the requests made by the logged-in user henceforth.

When it comes to securing web-apps against various attacks (Cross-site-request-forgery (CSRF), Cross-site-scripting (XSS), Eavesdropping, etc.. to list a few), there's a lot of discussion on different forums about choosing between the different standards.

Our app is secure against...

  • Eavesdropping - This application's traffic uses SSL tunneling.
  • CSRF attack
    • The username & password string is encrypted using JWT standard. Hence, extracting the username, password from the JWT token is impossible without the secret key (which only the server is aware of).
    • Every request made to the server is authorised using two tokens :
      • JWT token sent by the browser in the cookie
      • CSRF token in the request header

      CSRF token is appended by the JS application & not the browser. Thus, in a CSRF attack, the CSRF token is not sent to the malicious site!)

  • XSS attack - Storing the JWT token in the local storage exposes the same in an cross-site-scripting attack. Hence, the JWT token is stored in a secure, httpOnlycookie.

    secure cookie can be sent only through SSL tunnels (HTTPS). httpOnly cookie cannot be manipulated through scripts and can only be accessed by the browser.

  • Session Hijacking - We do not create any session for a logged-in user. Instead, we use token based authorization.

So, the JWT authorization is handled by the user-defined JWTFilter class which extends OncePerRequestFilter class provided by Spring framework. The doFilterInternal method is overridden where the JWT token is decrypted using the secret key, the username extracted and verified against the database.

(The password is not verified in this step as it is done by the UsernamePasswordAuthenticationFilter in the filter chain).

Next, the token is also validated against expiration time, etc. On passing these validations, the user details are passed on to the next filter in the chain - UsernamePasswordAuthenticationFilter.

In order to add our custom JWT filter JWTFilter in the Spring Security's filter chain, the following lines of code added in our SecurityConfiguration class.

http.addFilterBefore(jwtFilterBean(), UsernamePasswordAuthenticationFilter.class);

We also include a couple of other configuration properties in this class.

http
	.exceptionHandling().authenticationEntryPoint(jwtAuthEntryPoint)
	.and()
	// don't create session
    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
    .and()
	.authorizeRequests()
		.antMatchers("/", 
				"/login", 
				"/authenticate/**").permitAll()
		.antMatchers("/resources/**", 
				"/static/**", 
				"/css/**", 
				"/js/**", 
				"/bower_components/**", 
				"/html/**", 
				"/images/**").permitAll()
		.anyRequest()
		.authenticated()
		.and()
		.csrf()
        .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
        .and()
		.formLogin()
		.loginPage("/login")
		.permitAll()
		.and()
		.logout()
	    .logoutUrl("/logout")
	    .logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler())
	    .deleteCookies("XSRF_TOKEN", "AuthToken");
  • A custom JWTAuthEntryPoint class defines what is returned to the client when a request is rejected by the server.
  • SessionCreationPolicy.STATELESS will not create a session (thereby, making it a secure, stateless application).
  • anyRequest().authenticated() ensures that any request to our application requires the user to be authenticated.
  • Any authenticated user's requests are permitted if the URL in the request matches any of the antMatchers URL patterns.
  • After successful authentication, the server returns a CSRF token in a non-HttpOnly cookie (so that they can be accessed by the JS application).
  • formLogin().loginPage("/login").permitAll() specifies the location of the login page & grants all users (i.e. unauthenticated users) access to our log in page.
  • logout().logoutUrl("/logout") provides logout support with the URL that triggers log out to occur.
  • Upon successful logout, the HttpStatusReturningLogoutSuccessHandler allows you to provide a plain HTTP status code to be returned. If not configured a status code 200 will be returned by default.
  • Finally, deleteCookies("XSRF_TOKEN", "AuthToken") allows specifying the names of cookies to be removed on logout success.

GruntJS script to include JS/CSS files of libraries in index.html

In a Single Page Application which uses AngularJS, it's ideal to include the scripts & stylesheets in index.html using task runners like Grunt/Gulp. In this application, we have written Grunt tasks that would first lint the JS pages and then add them to our index.html.

Linting of scripts is important to ensure cross-browser compatibility of an application.

In order for the grunt-include-source task to work correctly, please add a "sources" property with value of the relative path of the JS/CSS files of the module to be included. It is included inside the bower.json file of each of the bower modules.

demo/src/main/resources/static/bower_components/angular/bower.json

  {
  "name": "angular",
  "version": "1.6.4",
  "license": "MIT",
  "main": "./angular.js",
  "ignore": [],
  "sources": {
    "js": "./*.js"
  },
  "dependencies": {
  }
}

By default, the sources property is not present in a bower.json file.

Since our application's security is strictly controlled by the URL patterns added in the Spring security configuration properties, it's a good practice to use $locationProvider.html5Mode(true) in our angular app's config block in config.js. And a <base href="/"> element in our index.html. Here's a nice article on why we include these.

That's all about this application. Please leave any feedback/comments on https://snehaananthan.wordpress.com/2017/04/28/angularjs-jdbc-authentication-jwt-spring-security-demo/.

Cheers! :)

References

angularjs-jwt-spring-security-demo's People

Contributors

snehaananthan avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.