Spring Security with JWT (Symmetric Encryption)

JwtUtil

package com.springSecurity.jwt;

import com.springSecurity.user.UserDetailsServiceImpl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class JwtFilter extends OncePerRequestFilter {

	@Autowired
	private JwtUtil jwtUtil;
	@Autowired
	private UserDetailsServiceImpl userDetailsServiceImpl;

	@Override
	protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
			FilterChain filterChain) throws ServletException, IOException {

		String authorizationHeader = httpServletRequest.getHeader("Authorization");

		String token = null;
		String userName = null;

		if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
			token = authorizationHeader.substring(7);
			userName = jwtUtil.extractUsername(token);
		}

		if (userName != null && SecurityContextHolder.getContext().getAuthentication() == null) {

			UserDetails userDetails = userDetailsServiceImpl.loadUserByUsername(userName);

			if (jwtUtil.validateToken(token, userDetails)) {

				UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
						userDetails, null, userDetails.getAuthorities());
				usernamePasswordAuthenticationToken
						.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
				SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
			}
		}
		filterChain.doFilter(httpServletRequest, httpServletResponse);
	}
}

JwtFilter

package com.springSecurity.jwt;

import com.springSecurity.user.UserDetailsServiceImpl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Component
public class JwtFilter extends OncePerRequestFilter {

	@Autowired
	private JwtUtil jwtUtil;
	@Autowired
	private UserDetailsServiceImpl userDetailsServiceImpl;

	@Override
	protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
			FilterChain filterChain) throws ServletException, IOException {

		String authorizationHeader = httpServletRequest.getHeader("Authorization");

		String token = null;
		String userName = null;

		if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
			token = authorizationHeader.substring(7);
			userName = jwtUtil.extractUsername(token);
		}

		if (userName != null && SecurityContextHolder.getContext().getAuthentication() == null) {

			UserDetails userDetails = userDetailsServiceImpl.loadUserByUsername(userName);

			if (jwtUtil.validateToken(token, userDetails)) {

				UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
						userDetails, null, userDetails.getAuthorities());
				usernamePasswordAuthenticationToken
						.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
				SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
			}
		}
		filterChain.doFilter(httpServletRequest, httpServletResponse);
	}
}

AuthRequest.java

package com.springSecurity.jwt;

public class AuthRequest {
	
	private String userName;
	private String password;
	
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}	
}

JWTController.java

package com.springSecurity.jwt;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class JWTController {
	
	@Autowired
    private JwtUtil jwtUtil;
    @Autowired
    private AuthenticationManager authenticationManager;
	
	@PostMapping("/authenticate")
	public String generateToken(@RequestBody AuthRequest authRequest) throws Exception {
		try {
			authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authRequest.getUserName(), authRequest.getPassword()));
		} catch (Exception ex) {
			throw new Exception("inavalid username/password");
		}
		return jwtUtil.generateToken(authRequest.getUserName());
	}
}

SecurityConfig.java

package com.springSecurity;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import com.springSecurity.jwt.JwtFilter;
import com.springSecurity.user.UserDetailsServiceImpl;

@Configuration
@EnableWebSecurity
@ConditionalOnProperty(name = "myproject.security.enabled", havingValue = "true", matchIfMissing = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	UserDetailsServiceImpl userDetailsServiceImpl;

	@Autowired
	private JwtFilter jwtFilter;

	/**
	 * @Override protected void configure(AuthenticationManagerBuilder auth) throws
	 *           Exception { auth .inMemoryAuthentication()
	 *           .withUser("admin1").password(passwordEncoder().encode("admin")).roles("ADMIN").and()
	 *           .withUser("admin2").password(passwordEncoder().encode("admin")).roles("ADMIN").authorities("MANAGER").and()
	 *           .withUser("user1").password(passwordEncoder().encode("user")).roles("USER").and()
	 *           .withUser("user2").password(passwordEncoder().encode("user")).roles("USER").authorities("LEAD");
	 *           }
	 */

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.authenticationProvider(authenticationProvider());
	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {

		http.csrf().disable();

		http.authorizeRequests().antMatchers("/").permitAll()// bypass authetication and authorization
				.antMatchers("/authenticate").permitAll().antMatchers("/empList").permitAll()// bypass authetication and
																								// authorization
				.antMatchers("/empList2").permitAll()// bypass authetication and authorization
				.antMatchers("/profile").authenticated()// Authentication only required
				.antMatchers("/user/**").hasRole("USER")// Authetication and Authorization required
				.antMatchers("/admin/**").hasRole("ADMIN")// Authetication and Authorization required
				.antMatchers("/useroradmin").hasAnyRole("ADMIN", "USER")// Either admin or user role required
				// permissions
				.antMatchers("/listTeam").hasAuthority("LEAD")// Authetication, Authorization (since /user/** is
																// required) and permission required
				.antMatchers("/listEmp").hasAuthority("MANAGER")// Authetication, Authorization and permission required
				.antMatchers("/**").denyAll().and().httpBasic();
		http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

		http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);
	}

	@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
	@Override
	public AuthenticationManager authenticationManagerBean() throws Exception {
		return super.authenticationManagerBean();
	}

	@Bean
	DaoAuthenticationProvider authenticationProvider() {
		DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
		daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
		daoAuthenticationProvider.setUserDetailsService(userDetailsServiceImpl);
		return daoAuthenticationProvider;
	}

	@Bean
	PasswordEncoder passwordEncoder() {
		return NoOpPasswordEncoder.getInstance();
//		return new BCryptPasswordEncoder();
	}

}

User.java

package com.springSecurity.user;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class User {
	
	private String id;
	private String username;
	private String password;
	private String roles;
	private String permissions;
	
	public User() {
		
	}
	public User(String id, String username, String password, String roles, String permissions) {
		this.id = id;
		this.username = username;
		this.password = password;
		this.roles = roles;
		this.permissions = permissions;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getRoles() {
		return roles;
	}
	public void setRoles(String roles) {
		this.roles = roles;
	}
	public String getPermissions() {
		return permissions;
	}
	public void setPermissions(String permissions) {
		this.permissions = permissions;
	}
	public List<String> getRolesList(){
		List<String> arrayList = new ArrayList<>(); 
		if(this.roles.length()>0) {
			Collections.addAll(arrayList,this.roles.split(",")); 
		}
		return arrayList;
	}
	
	public List<String> getPermissionsList(){
		List<String> arrayList = new ArrayList<>(); 
		if(this.roles.length()>0) {
			Collections.addAll(arrayList,this.permissions.split(",")); 
		}
		return arrayList;
	}
}

UserDAO.java

package com.springSecurity.user;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

@Repository
public class UserDAO {
	
	@Autowired
	JdbcTemplate jdbcTemplate;
	
	public User getEmpDetails(String userName) {
		StringBuilder query = new StringBuilder();
		query.append("select EMP_ID, EMP_USERNAME, EMP_PASS, EMP_ROLES, EMP_PERMISSIONS from emp_temp where EMP_USERNAME=?");
		User user =jdbcTemplate.queryForObject(query.toString(),new Object[] {userName}, new RowMapper<User>() {

			@Override
			public User mapRow(ResultSet rs, int rowNum) throws SQLException {
				return new User(
						rs.getString("EMP_ID"),
						rs.getString("EMP_USERNAME"),
						rs.getString("EMP_PASS"),
						rs.getString("EMP_ROLES"),
						rs.getString("EMP_PERMISSIONS"));
			}
			
		});
		return user;
	}
}

UserDetailsImpl.java

package com.springSecurity.user;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

public class UserDetailsImpl implements UserDetails{
	
	private static final long serialVersionUID = 1L;

	private User user;
	
	public UserDetailsImpl(User user) {
		this.user = user;
	}

	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		List<GrantedAuthority> authorityList = new ArrayList<>();
		this.user.getPermissionsList().forEach(p -> {
			GrantedAuthority authority = new SimpleGrantedAuthority(p);
			authorityList.add(authority);
		});
		
		this.user.getRolesList().forEach(p -> {
			GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_"+p);
			authorityList.add(authority);
		});
		
		return authorityList;
	}

	@Override
	public String getPassword() {
		return user.getPassword();
	}

	@Override
	public String getUsername() {
		return user.getUsername();
	}

	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	@Override
	public boolean isEnabled() {
		return true;
	}
}

UserDetailsServiceImpl.java

package com.springSecurity.user;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

@Service
public class UserDetailsServiceImpl implements UserDetailsService{

	@Autowired
	UserDAO userDAO;
	
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		User user = userDAO.getEmpDetails(username);
		UserDetailsImpl userPrincipal = new UserDetailsImpl(user);
		return userPrincipal;
	}
}

Controller.java

package com.springSecurity;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.security.RolesAllowed;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class Controller {
	
	/**
	 * Accessable without Authentication and authorization
	 * @return
	 */
	@GetMapping("/")
	public String getWelcomePage() {
		return "Hello....welcome to our website";
	}
	
	/**
	 * All logged in users
	 * Accessable with authentication but authorization not required
	 * @return
	 */
	@GetMapping("/profile")
	public String getProfile() {
		return "Welcome to profile page";
	}
	
	/**
	 * Only logged in user with role USER can access this
	 * @return
	 */
	@GetMapping("/user")
	public String getUser() {
		return "Hello User Role";
	}
	
	/**
	 * Only loggged in admin can access this
	 * @return
	 */
	@GetMapping("/admin")
	public String getAdmin() {
		return "Hello Admin Role";
	}
	
	/**
	 * Either User or Admin
	 * @return
	 */
	@GetMapping("/useroradmin")
	public String getUserOrAdmin() {
		return "Hello User or Admin Role";
	}
	
	@GetMapping("/listTeam")
	public List<String> listTeam() {
		List<String> list = new ArrayList();
		list.add("Team Memeber 1");
		list.add("Team Memeber 2");
		list.add("Team Memeber 3");
		return list;
	}
	
	@GetMapping("/listEmp")
	public List<String> listEmp() {
		List<String> list = new ArrayList();
		list.add("Team Memeber 1");
		list.add("Team Memeber 2");
		list.add("Team Memeber 3");
		list.add("Team Lead 1");
		list.add("Team Lead 2");
		return list;
	}
}

App.java

package com.springSecurity;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;

@SpringBootApplication
(exclude = {org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class})
public class App {
	public static void main(String[] args) {
		ApplicationContext applicationContext = SpringApplication.run(App.class, args);
	}
}

Release.sql

create table emp_temp
(
EMP_ID number(2),
EMP_USERNAME varchar2(10),
EMP_PASS varchar2(10),
EMP_ROLES varchar2(50),
EMP_PERMISSIONS varchar2(50)
);


insert into emp_temp values (1,'Tyson','123','ADMIN','');
insert into emp_temp values (2,'Justin','123','USER','');
insert into emp_temp values (3,'Martin','123','ADMIN','MANAGER');
insert into emp_temp values (4,'Jake'',123','USER','MANAGER');
insert into emp_temp values (5,'Duke','123','ADMIN','LEAD');
insert into emp_temp values (6,'Fade'',123','USER','LEAD');

Screenshots:

Generating JWT
RequestWithJWT

Reference :

Leave a Comment