Friday 16 October 2020

How to Use JWT (JSON Web Token) with Spring Security in Springboot

JWT (Java Web Token)

A compact URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS)structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted.


JWT Basic Steps

1. A user logs into an application and provides their credentials.
2. The Authentication server authenticates the user and creates a JWT which is returned to the user.
3. The user then makes various calls to the application and passes with these calls the newly created            JWT.
4 .The application can use the JWT to verify that the user has in fact been authenticated and proceed            with fulfilling the users’ requests.
























Directory Structure of JWT Application 



























JWT(JSON Web Token) and Spring Security Config classes 

SpingAPISecurityConfig.java

package in.jk.springboot.configuaration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import in.jk.springboot.jwt.JwtAuthenicationFilter;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SpingAPISecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private UserDetailsService userDetailsService;
@Autowired
private JwtAuthenicationFilter jwtAuthFilter;

protected void configure(HttpSecurity httpSecurity) throws Exception {


httpSecurity.csrf().disable().authorizeRequests()
                                             .antMatchers("/jwt/authenticate/**").hasAnyAuthority("USER","ADMIN")
                                             .and().authorizeRequests().antMatchers("/productapi/**")
             .hasAnyAuthority("ADMIN").
                                             and().httpBasic();

httpSecurity.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);

}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder authManager) throws Exception {

BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
authManager.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);

}

@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();

}

}

UserDetailServiceImpl.java

package in.jk.springboot.configuaration;

import java.util.Arrays;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
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;
import in.jk.springboot.entity.UserEntity;
import in.jk.springboot.repository.UserRepository;

@Service
public class UserDetailServiceImpl implements UserDetailsService {

@Autowired
private UserRepository userRepository;
private UserDetails userDetails;
@Override
public UserDetails loadUserByUsername(String userName)
throws UsernameNotFoundException {

List<UserEntity> userEntityList = userRepository.findUserByUserName(userName);
if (!userEntityList.isEmpty()) {
        UserEntity userEntity = userEntityList.get(0);
       GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(userEntity.getRole());
userDetails = new User(userEntity.getUserName(), userEntity.getPassword(),
          Arrays.asList(grantedAuthority));
        System.out.println("grantedAuthorizeUser :: " + userDetails);
} else {
System.out.println("User Not Present ");
}

return userDetails;
}

public UserDetails getUserDetails() {
return userDetails;
}

public void setUserDetails(UserDetails userDetails) {
this.userDetails = userDetails;
}

}


JwtUtils.java

package in.jk.springboot.jwt;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

@Component
public class JwtUtils implements Serializable {

private static final long serialVersionUID = 1L;
private static long JWT_TOKEN_VALIDITY=5*60*60;
private String secret="jwt_token";
    //retrieve username from jwt token
public String getUsernameFromToken(String token) {
return getClaimFromToken(token, Claims::getSubject);
}

//retrieve expiration date from jwt token
public Date getExpirationDateFromToken(String token) {
return getClaimFromToken(token, Claims::getExpiration);
}

public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
final Claims claims = getAllClaimsFromToken(token);
return claimsResolver.apply(claims);
}
    //for retrieveing any information from token we will need the secret key
private Claims getAllClaimsFromToken(String token) {
return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
}

//check if the token has expired
private Boolean isTokenExpired(String token) {
final Date expiration = getExpirationDateFromToken(token);
return expiration.before(new Date());
}

//generate token for user
public String generateToken(UserDetails userDetails) {
Map<String, Object> claims = new HashMap<>();
return doGenerateToken(claims, userDetails.getUsername());
}

//while creating the token -
//1. Define  claims of the token, like Issuer, Expiration, Subject, and the ID
//2. Sign the JWT using the HS512 algorithm and secret key.
//3. According to JWS Compact Serialization(https://tools.ietf.org/html/draft-ietf-jose-json-                     web-signature-41#section-3.1)
//   compaction of the JWT to a URL-safe string 
private String doGenerateToken(Map<String, Object> claims, String subject) {

return Jwts.builder().setClaims(claims).setSubject(subject)
                                                        .setIssuedAt(new Date(System.currentTimeMillis()))
               .setExpiration(new Date(System.currentTimeMillis() +                                                                                JWT_TOKEN_VALIDITY * 1000))
               .signWith(SignatureAlgorithm.HS512, secret).compact();
}

//validate token
public Boolean validateToken(String token, UserDetails userDetails) {
final String username = getUsernameFromToken(token);
return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
}

}

JwtAuthenticationController.java
package in.jk.springboot.jwt;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import in.jk.springboot.configuaration.UserDetailServiceImpl;
import in.jk.springboot.response.Response;



@RestController
@RequestMapping("/jwt")
public class JwtAuthenticationController {

@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JwtUtils jwtUtils;
@Autowired
private UserDetailServiceImpl userDetailService;

@RequestMapping(value = "/authenticate", method = RequestMethod.POST)
public Response getAuthenticationToken(@RequestBody JwtTokenRequest jwtTokenRequest) {
System.out.println("Authenicate Controller ...");

Response response = null;
JwtTokenResponse jwtTokenResponse = null;

response = new Response();
jwtTokenResponse = new JwtTokenResponse();
try {

if (authenticate(jwtTokenRequest.getUserName(), jwtTokenRequest.getPassword())) {

 UserDetails userDetails =  
                 userDetailService.loadUserByUsername(jwtTokenRequest.getUserName());                

final String token = jwtUtils.generateToken(userDetails);
System.out.println("Generated Token ::"+token);

jwtTokenResponse = new JwtTokenResponse();
jwtTokenResponse.setUserName(jwtTokenRequest.getUserName());
jwtTokenResponse.setToken(token);

response.setResponse("200", "Authentication Token", jwtTokenResponse, "");

}

} catch (Exception e) {

jwtTokenResponse = new JwtTokenResponse();
jwtTokenResponse.setUserName(jwtTokenRequest.getUserName());
jwtTokenResponse.setToken("Error in Token Generation ");

response.setResponse("500", "Error in Token Generation", 
                       jwtTokenResponse, e.getMessage());
}

return response;

}

private boolean authenticate(String userName, String password) throws Exception {

boolean status = Boolean.FALSE;

UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userName,
password);

try {
Authentication auth = authenticationManager.authenticate(authentication);
status = auth.isAuthenticated();
System.out.println("Authentication Status :: "+status);

}

catch (DisabledException e) {

throw new Exception("User Disabled ", e);

}

catch (BadCredentialsException e) {
throw new Exception("User Disabled ", e);

} catch (Exception e) {
throw new Exception(e);

}
return status;

}

}


JwtAuthenicationFilter.java

package in.jk.springboot.jwt;

import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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 in.jk.springboot.configuaration.UserDetailServiceImpl;
import io.jsonwebtoken.ExpiredJwtException;

@Component
public class JwtAuthenicationFilter extends OncePerRequestFilter {

@Autowired
private UserDetailServiceImpl UserDetailService;
@Autowired
private JwtUtils jwtUtils;

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

String userName = null;
String jwtToken = null;
TokenError tokenError =null;
        String jwtTokenHeader = request.getHeader("Authorization");
String isAuthorizationRequired = request.getHeader("IsAuthorizationRequired");
RequestDispatcher dispatcher = request.getRequestDispatcher("/errorapi/error");
StringBuffer url =request.getRequestURL();
System.out.println("Request URL :: "+url);
System.out.println("Token :: "+jwtTokenHeader);
System.out.println("IsAuthorizationRequired :: "+isAuthorizationRequired);
     if (jwtTokenHeader != null && jwtTokenHeader.startsWith("jwt ")) {
            jwtToken = jwtTokenHeader.replace("jwt ", "");
System.out.println("Token :: "+jwtToken);
            try {
userName = jwtUtils.getUsernameFromToken(jwtToken);

}

catch (ExpiredJwtException e) {
System.out.println("Token Expired :: " + e);
tokenError =new TokenError();
tokenError.setToken(jwtToken);
tokenError.setUserName(userName);
tokenError.setTokenErrorType("Token Expire :: "+e.getMessage());
request.setAttribute("tokenError", tokenError);
dispatcher.forward(request, response);
return;

} catch (Exception e) {

System.out.println("Error in Token :: " + e);
tokenError =new TokenError();
tokenError.setToken(jwtToken);
tokenError.setUserName(userName);
tokenError.setTokenErrorType("Error in Token  :: "+e.getMessage());
request.setAttribute("tokenError", tokenError);
dispatcher.forward(request, response);
return;
}

} else {
    if(isAuthorizationRequired==null || "Y".equals(isAuthorizationRequired) ) {
System.out.println("Request Without Token  :: Token Required for Authorization");
            }
else {
System.out.println("Request Without Token :: Token Not Required ");
}
}
if(userName!=null && SecurityContextHolder.getContext().getAuthentication()==null )
{
UserDetails userDetails = UserDetailService.loadUserByUsername(userName);
System.out.println("UserDetails ::  "+userDetails);
if(jwtUtils.validateToken(jwtToken, userDetails)) {
UsernamePasswordAuthenticationToken                                                                                                      usernamePasswordAuthenticationToken=null;
usernamePasswordAuthenticationToken = 
                                new  UsernamePasswordAuthenticationToken(userDetails,
                                null,userDetails.getAuthorities());
usernamePasswordAuthenticationToken.setDetails(
                                new WebAuthenticationDetailsSource().buildDetails(request));             
SecurityContextHolder.getContext()
                               .setAuthentication(usernamePasswordAuthenticationToken);
}
}
try {
filterChain.doFilter(request, response);
    }catch(Exception e) {
    System.out.println(e);
   
    }

}
}

JwtTokenRequest.java

package in.jk.springboot.jwt;

public class JwtTokenRequest {
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;
}
@Override
public String toString() {
return "JwtRequest [userName=" + userName + ", password=" + password + "]";
}

}

JwtTokenResponse.java

package in.jk.springboot.jwt;

public class JwtTokenResponse {
private String userName;
private String token;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
@Override
public String toString() {
return "JwtTokenResponse [userName=" + userName + ", token=" + token + "]";
}

}

TokenError.java

package in.jk.springboot.jwt;

public class TokenError {
private String userName;
private String token;
private String tokenErrorType;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getToken() {
return token;
}
public void setToken(String token) {
this.token = token;
}
public String getTokenErrorType() {
return tokenErrorType;
}
public void setTokenErrorType(String tokenErrorType) {
this.tokenErrorType = tokenErrorType;
}
@Override
public String toString() {
return "TokenError [userName=" + userName + ", token=" + token + ",
                tokenErrorType=" + tokenErrorType + "]";
}
}

SwaggerConfig.java

package in.jk.springboot.configuaration;

import java.util.ArrayList;
import java.util.List;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {                                    
    @Bean
    public Docket api() { 
   
    //Adding Header
    ParameterBuilder authorizationParameterBuilder = new ParameterBuilder();
    authorizationParameterBuilder.name("Authorization")
        .modelRef(new ModelRef("string")).parameterType("header").required(false)
       .description("Enter Token ").build();
      ParameterBuilder isauthorizationRequiredBuilder = new ParameterBuilder();
      isauthorizationRequiredBuilder.name("IsAuthorizationRequired")
       .modelRef(new ModelRef("string")).parameterType("header").required(true)
       .description("Enter Y or N ").build();
    List<Parameter> aParameters = new ArrayList<Parameter>();
    aParameters.add(authorizationParameterBuilder.build());
    aParameters.add(isauthorizationRequiredBuilder.build());
   
        return new Docket(DocumentationType.SPRING_WEB)  
          .select()                                  
          .apis(RequestHandlerSelectors.any())              
          .paths(PathSelectors.any())                          
          .build().pathMapping("").globalOperationParameters(aParameters);                                          
    }
}




JWT application Request POJO classes

EmployeeRequest.java

package in.jk.springboot.request;

public class EmployeeRequest {
private int empId;
private String name;
private String company;
//Getters and Setters 
         @Override
public String toString() {
return "Employee [empId=" + empId + ", name=" + name + ", company=" + company + "]";
}
}

UserRequest .java

package in.jk.springboot.request;

public class UserRequest {
private int userId;
private String  name;
private String userName;
private String password;
private String role;
//Getters and Setters

@Override
public String toString() {
return "UserRequest [userId=" + userId + ", name=" + name + ", userName=" + userName + ", password=" + password
+ ", role=" + role + "]";
}
 

}




Jwt application service interface

UserService.java

package in.jk.springboot.service;
import in.jk.springboot.request.UserRequest;
import in.jk.springboot.response.Response;

public interface UserService {
public Response findUserByUserId(Integer userId);
public Response addUser(UserRequest userRequest);
public Response findUserByUserName(String userName);

}

EmployeeService.java

package in.jk.springboot.service;
import in.jk.springboot.request.EmployeeRequest;
import in.jk.springboot.response.Response;

public interface EmployeeService {

public Response findEmployeeById(Integer empId);
public Response addEmployee(EmployeeRequest employeeRequest);
}






JWT application service interface  implementation 

EmployeeServiceImpl.java

package in.jk.springboot.serivce.impl;

import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import in.jk.springboot.entity.Employee;
import in.jk.springboot.repository.EmployeeRespository;
import in.jk.springboot.request.EmployeeRequest;
import in.jk.springboot.response.Response;
import in.jk.springboot.service.EmployeeService;

@Service
public class EmployeeServiceImpl implements EmployeeService {

@Autowired
EmployeeRespository employeeRespository;

public Response findEmployeeById(Integer empId) {

Response response = null;
Object responseData=null;

response = new Response();
try {
Employee employee = employeeRespository.getOne(empId);
System.out.println(employee);
responseData =employee;
response.setResponse("200", "Request Successfull.", responseData, null);
} catch (Exception e) {

response.setResponse("400", "Request UnSuccessfull.", null, e.getMessage());
}

return response;

}

@Override
public Response addEmployee(EmployeeRequest employeeRequest) {

Response response = null;
Employee employee = new Employee();
employee.setEmpId(employeeRequest.getEmpId());
employee.setName(employeeRequest.getName());
employee.setCompany(employeeRequest.getCompany());
        response = new Response();
        
        
try {
Employee employeeEnity = employeeRespository.save(employee);
System.out.println(employeeEnity);
Map<String,Object> responseMap = new HashMap<String,Object>();
responseMap.put("employee", employeeEnity);
response.setResponse("200", "Request Successfull.", responseMap, null);
} catch (Exception e) {

response.setResponse("200", "Request Successfull.", employee, null);
}

return response;
}

}

UserServiceImpl.java

package in.jk.springboot.serivce.impl;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import in.jk.springboot.entity.UserEntity;
import in.jk.springboot.repository.UserRepository;
import in.jk.springboot.request.UserRequest;
import in.jk.springboot.response.Response;
import in.jk.springboot.service.UserService;

@Service
public class UserServiceImpl implements UserService {

@Autowired
private UserRepository userRepository;

@Override
public Response findUserByUserId(Integer userId) {
Response response = null;
Object responseData = null;

response = new Response();
try {
UserEntity userEntity = userRepository.getOne(userId);
System.out.println(userEntity);
responseData = userEntity;
response.setResponse("200", "Request Successfull.", responseData, null);
} catch (Exception e) {

response.setResponse("400", "Request UnSuccessfull.", null, e.getMessage());
}

return response;
}

@Override
public Response addUser(UserRequest userRequest) {

Response response = null;
Object responseData = null;

response = new Response();
try {
UserEntity userEntity = new UserEntity();
userEntity.setUserId(userRequest.getUserId());
userEntity.setName(userRequest.getName());
userEntity.setUserName(userRequest.getUserName());
userEntity.setRole(userRequest.getRole());

BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
                        String password = passwordEncoder.encode(userRequest.getPassword());
                        userEntity.setPassword(password);

userEntity = userRepository.save(userEntity);
System.out.println(userEntity);
responseData = userEntity;
response.setResponse("200", "User Saved Successfull.", responseData, null);
} catch (Exception e) {

response.setResponse("400", "User Saved  Request Unsuccessfull.",
                       null, e.getMessage());
}

return response;
}

@Override
public Response findUserByUserName(String userName) {
Response response = null;
Object responseData = null;
List<UserEntity> userList = null;

response = new Response();
try {

userList = userRepository.findUserByUserName(userName);
if (!userList.isEmpty()) {

UserEntity userEntity = userList.get(0);
System.out.println(userEntity);
responseData = userEntity;

}

response.setResponse("200", "Request Successfull.", responseData, null);
} catch (Exception e) {

response.setResponse("400", "Request UnSuccessfull.", null, e.getMessage());
}

return response;

}
}

JWT applicaton Entity class 
Employee.java

package in.jk.springboot.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="jwt_employee_details")
public class Employee {
@Id
@Column(name="emp_id")
private int empId;
@Column(name="name")
private String name;
@Column(name="company")
private String company;

        //Getters and Setters

}

UserEntity.java

package in.jk.springboot.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="jwt_user")
public class UserEntity {
@Id
@Column(name="user_id")
private Integer userId;
@Column(name="user_name" ,unique = true)
private String userName;
@Column(name="name")
private String name;
@Column(name="password")
private String password;
@Column(name="email_id")
private String emailId;
@Column(name="role")
private String  role;

       //Getters and Setters

}

JWT  Application Repository 

UserRepository.java

package in.jk.springboot.repository;

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import in.jk.springboot.entity.UserEntity;

public interface UserRepository extends JpaRepository<UserEntity, Integer> {
@Query("From UserEntity user where user.userName=:userName")
public List<UserEntity> findUserByUserName(@Param("userName") String userName); 

}

EmployeeRespository .java

package in.jk.springboot.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import in.jk.springboot.entity.Employee;

public interface EmployeeRespository extends JpaRepository<Employee, Integer> {

}


Response class 
Response .java

package in.jk.springboot.response;

public class Response {

private String responseCode;
private String responseMessage;
private Object responseData;
private String errorMessage;

public void setResponse(String responseCode, String responseMessage, Object responseData, String errorMessage) {

this.setResponseCode(responseCode);
this.setResponseMessage(responseMessage);
this.setResponseData(responseData);
this.setErrorMessage(errorMessage);

}

public String getResponseCode() {
return responseCode;
}

public void setResponseCode(String responseCode) {
this.responseCode = responseCode;
}

public String getResponseMessage() {
return responseMessage;
}

public void setResponseMessage(String responseMessage) {
this.responseMessage = responseMessage;
}

public Object getResponseData() {
return responseData;
}

public void setResponseData(Object responseData) {
this.responseData = responseData;
}

public String getErrorMessage() {
return errorMessage;
}

public void setErrorMessage(String errorMessage) {
this.errorMessage = errorMessage;
}

}


JWT Application Controller class 

package in.jk.springboot.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import in.jk.springboot.request.EmployeeRequest;
import in.jk.springboot.response.Response;
import in.jk.springboot.service.EmployeeService;


@CrossOrigin
@RestController
@RequestMapping("/adminapi")
public class AdminController {
@Autowired
EmployeeService employeeService;
@RequestMapping(value = "/employee/{empId}" , produces = "application/json", 
        method = RequestMethod.GET)
public Response findEmployeeById(@PathVariable Integer empId) {
return employeeService.findEmployeeById(empId);
}
@RequestMapping(value = "/employee" , produces = "application/json",  
           method = RequestMethod.POST)
public Response addEmployee(@RequestBody EmployeeRequest employeeRequest) {
return employeeService.addEmployee(employeeRequest);
}
}


UserController.java

package in.jk.springboot.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import in.jk.springboot.request.UserRequest;
import in.jk.springboot.response.Response;
import in.jk.springboot.service.UserService;

@CrossOrigin
@RestController
@RequestMapping("/userapi")
public class UserController {

@Autowired
UserService userService;
    @Autowired
HttpServletRequest httpServletRequest;

@RequestMapping(value = "/findUserByUserId/{userId}", produces = "application/json", 
            method = RequestMethod.GET)
public Response findUserByUserId(@PathVariable Integer userId) {

return userService.findUserByUserId(userId);

}

@RequestMapping(value = "/addUser", produces = "application/json", method = RequestMethod.POST)
public Response addUser(@RequestBody UserRequest userRequest) {

return userService.addUser(userRequest);

}

}

ErrorController.java

package in.jk.springboot.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import in.jk.springboot.jwt.TokenError;
import in.jk.springboot.response.Response;

@CrossOrigin
@RestController
@RequestMapping("/errorapi")
public class ErrorController {
  @Autowired
HttpServletRequest httpServletRequest;
  
  @RequestMapping(value = "/error", produces = "application/json", 
           method = {RequestMethod.GET,RequestMethod.POST})
public Response tokenError() {
           
    System.out.println("Error in token Authorization");
        Response response = new Response();
        TokenError tokenError = (TokenError) httpServletRequest.getAttribute("tokenError");
        response.setResponse("500", "Token Error ", tokenError, "Error in Token");

return response;

}

}









pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>in.jk</groupId>
<artifactId>springbootjwt</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootWithJWT</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--   JWT Dependency -->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>     
</dependency>

<!-- Swagger Dependency  -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>


<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

application.properties 

For Database configuration we have Postgress database .

spring.datasource.url =jdbc:postgresql://localhost:5432/postgres
SET SQL_SAFE_UPDATES = 0;
spring.datasource.username=postgres
spring.datasource.password=jk123

spring.datasource.driverClassName=org.postgresql.Driver

spring.jpa.hibernate.dialect=org.hibernate.dialect.SQLPostgresSQLDialect
#spring.jpa.show-sql=true
spring.jpa.show-sql = true
#ddl2auto commannd
spring.jpa.hibernate.ddl-auto = update
spring.jackson.serialization.fail-on-empty-beans=false


JWT Application Starter class

package in.jk.springboot;

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

@SpringBootApplication
public class SpringbootApplication {

public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
    System.out.println("Spring Application Started ........... ");
}

}


For JWT Application Testing First Start the Application using  SpringbootApplication  class

1 . Open the Browser then type the follwing url Swagger API Tool.

http://localhost:8080/swagger-ui.html


























For each Service in this application you require two header parameter 

IsAuthorizationRequired :- This Header parameter is used enbale and disable toekn based authorization . 
                           IsAuthorizationRequired  takes two value 
                           Y:- To Enable Autorization 
                           N:- To Disable Autorization 


Authorization :- This Header parameter takes local computed toekn string if IsAuthorizationRequired  value Y otherwise it have no value or blank .


Note : - In Order to compute string localy in this application we have add jwt in prifix of token string response by token service 

         Local computed Token String = jwt+" " +token String ; 
         Example 

        Authorization": "jwt eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJqb2huIiwiZXhwIjoxN


2. For Getting Token First we need to add a User with user service so open user service the add one user following user details


Header Paramter Value 

Authorization :- No value 
IsAuthorizationRequired  :- N


User Name = John
userId    = john
password  = john
role      = ADMIN


Add User Service 



























3. For Getting Token Open Authenticate Service enter userName and password of added user .

Header Paramter Value 

Authorization :- No value 
IsAuthorizationRequired  :- N


Authenticate Service Token Request 




























Authenticate Service Token Response 









































4 . Now finally to Test Token authorization open Employee Service 

To Calling Add Employee enter header parameter like following 


Header Paramter example Value 

Authorization :- jwt+" "+ token retrive from Authenticate Service Token Request
IsAuthorizationRequired  :- Y


Add Employee Service Request 





















   





Add Employee Service Response 



























5. Find Employee Service with valid token




























6. Find Employee Service with invalid token


















  









This is how we can used JWT(JSON Web Token) with Spring Secuirty in Springboot .


please comment if you find any mistake .


Source Code JWT Application 

Dowload Source code from here ....












References





























Friday 9 October 2020

How to Use Spring Security with UserDetailService in SpringBoot to Secure Rest Service End Point



Spring Security is a powerful and highly customizable authentication and access-control framework. 
It is the de-facto standard for securing Spring-based applications.


UserDetailsService Interface

UserDetailsService import org.springframework.security.core.userdetails.UserDetailsService
is interface that one method 

public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException

which invoke during authentication of user for fetching user details from database.

UserDetailServiceImpl.java

package in.jk.springbootapplication.configuration;

import java.util.Arrays;
import org.springframework.stereotype.Service;
import in.jk.springbootapplication.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;


@Service
public class UserDetailServiceImpl implements UserDetailsService {
@Autowired
private AdminService adminService;
private UserDetails userDetails;

@Override
public UserDetails loadUserByUsername(String userName) 
        throws UsernameNotFoundException {
in.jk.springbootapplication.entity.User user= null;
                user=adminService.findUserByUserName(userName);
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(user.getRole());
userDetails = new org.springframework.security.core.userdetails.User(user.getUserName()                       , user.getPassword(),Arrays.asList(grantedAuthority));
  System.out.println("grantedAuthorizeUser :: " +userDetails);
 
  return userDetails;
}

public UserDetails getUserDetails() {
return userDetails;
}

public void setUserDetails(UserDetails userDetails) {
this.userDetails = userDetails;
}

Spring provide  WebSecurityConfigurerAdapter cofigure the Spring Security.
WebSecurityConfigurerAdapter class provides a 

public void configure(HttpSecurity http){}

method that contains the following default configuration.
The following class enable Spring Web Security with in memory authentication with provided users details .

SpingAPISecurityConfig.java

package in.jk.springbootapplication.configuration;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SpingAPISecurityConfig extends WebSecurityConfigurerAdapter 
{

@Autowired
private UserDetailsService userDetailsService;

protected void configure(HttpSecurity httpSecurity) throws Exception {

httpSecurity.csrf().disable()
                                            .authorizeRequests().antMatchers("/adminapi/employee/**")
                                            .hasAnyAuthority("ADMIN")
                                             .and().authorizeRequests().antMatchers("adminapi/product/**")
                                             .hasAnyAuthority("USER").and().httpBasic();

}

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
       auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);

}

}


Dirctory Structure of Spring boot application



























Maven Dependency for Spring Security 

                  <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>


Controller 
 In this application controller class contain three type of URL one for user service to add user the service URL start with user and other two start with employee and product protected with spring security . they require authentication access them .


AdminController.java

package in.jk.springbootapplication.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import in.jk.springbootapplication.request.EmployeeRequest;
import in.jk.springbootapplication.request.ProductRequest;
import in.jk.springbootapplication.request.UserRequest;
import in.jk.springbootapplication.response.Response;
import in.jk.springbootapplication.service.AdminService;

@RestController
@RequestMapping("/adminapi")
public class AdminController {

@Autowired
private AdminService adminService;


@RequestMapping(value = "/user/findUserById/{userId}", method = RequestMethod.GET)
public Response findUserById(@PathVariable Integer userId) {
return adminService.findUserById(userId);

}

@RequestMapping(value = "/user/addUser", method = RequestMethod.POST)
public Response addProduct(@RequestBody UserRequest user) {
return adminService.addUser(user);

}

@RequestMapping(value = "/employee/findEmployeeById/{employeeId}", 
          method = RequestMethod.GET)
public Response findEmployeeById(@PathVariable Integer employeeId) {

return adminService.findEmployeeById(employeeId);

}

@RequestMapping(value = "/employee/addEmployee", method = RequestMethod.POST)
public Response addEmployee(@RequestBody EmployeeRequest employee) {

return adminService.addEmployee(employee);

}

@RequestMapping(value = "/product/findProductById/{productId}",
         method = RequestMethod.GET)
public Response findProductById(@PathVariable Integer productId) {

return adminService.findProductById(productId);

}

@RequestMapping(value = "/product/addProduct", method = RequestMethod.POST)
public Response addProduct(@RequestBody ProductRequest product) {

return adminService.addProduct(product);

}

}

EmployeeRequest.java

package in.jk.springbootapplication.request;

public class EmployeeRequest {
private int employeeId;
private String name;
private String company;
        //Getters and Setters 
@Override
public String toString() {
return "Employee [employeeId=" + employeeId + ", 
               name=" + name + ", comapny=" + company + "]";
}
}

ProductRequest.java

package in.jk.springbootapplication.request;

public class ProductRequest {
private int productId;
private String productName;
private int price;
private String company;
       //Getters and Setters
@Override
public String toString() {
return "ProductRequest [productId=" + productId + ", 
                productName=" + productName + ", price=" + price
+ ", company=" + company + "]";
}
}

UserRequest.java

package in.jk.springbootapplication.request;
public class UserRequest {
private Integer userId;
private String userName;
private String name;
private String password;
private String emailId;
private String  role;
       //Getters and Setters
@Override
public String toString() {
return "UserRequest [userId=" + userId + ", userName=" + userName + ", 
                name=" + name + ", password=" + password
+ ", emailId=" + emailId + ", role=" + role + "]";
}
}

Spring Security application entity classes 

package in.jk.springbootapplication.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity
@Table(name="springboot.employee")
@NamedQuery(name="findEmployeeByName",query = "FROM Employee employee where employee.name=:name")
public class Employee {

@Id
@Column(name="employee_id")
private Integer employeeId;
@Column(name="name")
private String name;
@Column(name="company")
private String company;

// Getters and Setters

@Override
public String toString() {
return "Employee [employeeId=" + employeeId + ", name=" + name + ", 
       comapny=" + company + "]";
}
}


package in.jk.springbootapplication.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="springboot_product")
public class Product {
@Id
@Column(name="product_id")
private int productId;
@Column(name="product_name")
private String productName;
@Column(name="price")
private int price;
@Column(name="company")
private String company;
        //Getters and Setters
@Override
public String toString() {
return "ProductRequest [productId=" + productId + ", productName=" + 
                productName + ", price=" + price+ ", company=" + company + "]";
}

}

User.java

package in.jk.springbootapplication.entity;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="springboot_user")
public class User {
@Id
@Column(name="user_id")
private Integer userId;
@Column(name="user_name")
private String userName;
@Column(name="name")
private String name;
@Column(name="password")
private String password;
@Column(name="email_id")
private String emailId;
@Column(name="role")
private String  role;
        //Getters and Setters
@Override
public String toString() {
return "UserRequest [userId=" + userId + ", userName=" + userName + ", 
                name=" + name + ", password=" + password
+ ", emailId=" + emailId + ", role=" + role + "]";
}
}

Spring Security application Repository classes 
EmployeeRepositry.java

package in.jk.springbootapplication.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import in.jk.springbootapplication.entity.Employee;

public interface EmployeeRepositry extends JpaRepository<Employee, Integer> {

}

ProductRepository.java
package in.jk.springbootapplication.repository;

import org.springframework.data.jpa.repository.JpaRepository;

import in.jk.springbootapplication.entity.Product;

public interface ProductRepository  extends JpaRepository<Product, Integer>{
}

UserRepository.java

package in.jk.springbootapplication.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import in.jk.springbootapplication.entity.User;

public interface UserRepository extends JpaRepository<User, Integer> {
}

Spring Security Application class 
Response.java

package in.jk.springbootapplication.response;

public class Response {
private Object responseData;
private String responseMessage;
private String responseCode;
public void setResponse(String responseCode,Object data, String responseMessage) {
this.responseCode=responseCode;
this.responseData =data;
this.responseMessage=responseMessage;
}
public Object getResponseData() {
return responseData;
}
public void setResponseData(Object responseData) {
this.responseData = responseData;
}
public String getResponseMessage() {
return responseMessage;
}
public void setResponseMessage(String responseMessage) {
this.responseMessage = responseMessage;
}
public String getResponseCode() {
return responseCode;
}
public void setResponseCode(String responseCode) {
this.responseCode = responseCode;
}
@Override
public String toString() {
return "Response [responseData=" + responseData + ", responseMessage=" + 
                responseMessage + ", responseCode="
+ responseCode + "]";
}

}


Service Interface and class of Spring Security Application 
AdminService.java
package in.jk.springbootapplication.service;

import in.jk.springbootapplication.entity.User;
import in.jk.springbootapplication.request.EmployeeRequest;
import in.jk.springbootapplication.request.ProductRequest;
import in.jk.springbootapplication.request.UserRequest;
import in.jk.springbootapplication.response.Response;

public interface AdminService {

public Response findUserById(Integer userId);

public Response addUser(UserRequest user);
public User findUserByUserName(String userName);
        public Response findEmployeeById(Integer employeeId);

public Response addEmployee(EmployeeRequest employee);

public Response findProductById(Integer productId);

public Response addProduct(ProductRequest product);

}

AdminServiceImpl.java
 
package in.jk.springbootapplication.service.impl;

import java.util.List;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import in.jk.springbootapplication.entity.Employee;
import in.jk.springbootapplication.entity.Product;
import in.jk.springbootapplication.entity.User;
import in.jk.springbootapplication.repository.EmployeeRepositry;
import in.jk.springbootapplication.repository.ProductRepository;
import in.jk.springbootapplication.repository.UserRepository;
import in.jk.springbootapplication.request.EmployeeRequest;
import in.jk.springbootapplication.request.ProductRequest;
import in.jk.springbootapplication.request.UserRequest;
import in.jk.springbootapplication.response.Response;
import in.jk.springbootapplication.service.AdminService;

@Service
public class AdminServiceImpl implements AdminService {

@Autowired
private UserRepository userRepository;
@Autowired
private EmployeeRepositry employeeRepositry;
@Autowired
private ProductRepository productRepository;

@Override
public Response findUserById(Integer userId) {

Response response = null;
User entity = null;

response = new Response();
try {
Optional<User> user = userRepository.findById(userId);
if (user.isPresent()) {
entity = user.get();
response.setResponse("200", entity, "User Find Succussfully ");

} else {
response.setResponse("200", entity, "User Not Present ");

}

} catch (Exception e) {
response.setResponse("500", e.getMessage(), "Error in Finding User ");
}

return response;
}

@Override
public Response addUser(UserRequest userRequest) {

Response response = null;
User user = new User();
user.setUserId(userRequest.getUserId());
user.setName(userRequest.getName());
user.setUserName(userRequest.getUserName());
user.setEmailId(userRequest.getEmailId());
user.setRole(userRequest.getRole());

BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String password = passwordEncoder.encode(userRequest.getPassword());

user.setPassword(password);

response = new Response();
try {
userRepository.save(user);
response.setResponse("200", user, "User Added Succussfully ");
} catch (Exception e) {
response.setResponse("500", e.getMessage(), "Error in Adding User ");
}

return response;
}

       @Override
public User findUserByUserName(String userName) {
User user = null;

try {
List<User> userList = userRepository.findUserByUserName(userName);
if (!userList.isEmpty()) {

user = userList.get(0);
}

} catch (Exception e) {

System.out.println("Invalid User and Password ");
}

return user;
}


@Override
public Response findEmployeeById(Integer employeeId) {

Response response = null;
Employee entity = null;

response = new Response();
try {
Optional<Employee> employee = employeeRepositry.findById(employeeId);
if (employee.isPresent()) {
entity = employee.get();
response.setResponse("200", entity, "Employee Find Succussfully ");

} else {
response.setResponse("200", entity, "Employee Not Present ");

}

} catch (Exception e) {
response.setResponse("500", null, "Error in Finding Employee ");
}

return response;
}

@Override
public Response addEmployee(EmployeeRequest employee) {
Response response = null;
Employee entity = new Employee();
entity.setEmployeeId(employee.getEmployeeId());
entity.setName(employee.getName());
entity.setCompany(employee.getCompany());

response = new Response();
try {
employeeRepositry.save(entity);
response.setResponse("200", entity, "Employee Added Succussfully ");
} catch (Exception e) {
response.setResponse("500", null, "Error in Adding Employee ");
}

return response;
}

@Override
public Response findProductById(Integer productId) {

Response response = null;
Product entity = null;

response = new Response();
try {
Optional<Product> product = productRepository.findById(productId);
if (product.isPresent()) {
entity = product.get();
response.setResponse("200", entity, "Product Find Succussfully ");

} else {
response.setResponse("200", entity, "Product Not Present ");

}

} catch (Exception e) {
response.setResponse("500", e.getMessage(), "Error in Finding Product ");
}

return response;
}

@Override
public Response addProduct(ProductRequest product) {

Response response = null;
Product entity = new Product();
entity.setProductId(product.getProductId());
entity.setProductName(product.getProductName());
entity.setPrice(product.getPrice());
entity.setCompany(product.getCompany());

response = new Response();
try {
productRepository.save(entity);
response.setResponse("200", entity, "Product Added Succussfully ");
} catch (Exception e) {
response.setResponse("500", e.getMessage(), "Error in Adding Product ");
}

return response;
}

}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.4.0-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>in.jk</groupId>
<artifactId>springbootapplication</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootapplication</name>
<description>Demo project for Spring Boot</description>

<properties>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--  Jackson Dependency for json conversion -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>     
</dependency>

<!-- Swagger Dependency .. -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</pluginRepository>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>

</project>

Spring Security Swagger Config 
SwaggerConfig.java

package in.jk.springbootapplication.configuration;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@Configuration
@EnableSwagger2
public class SwaggerConfig {                                    
    @Bean
    public Docket api() { 
        return new Docket(DocumentationType.SPRING_WEB)  
          .select()                                  
          .apis(RequestHandlerSelectors.any())              
          .paths(PathSelectors.any())                          
          .build();                                           
    }
}

SpringbootApplication.java

package in.jk.springbootapplication;

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

@SpringBootApplication
public class SpringbootApplication {

public static void main(String[] args) {
SpringApplication.run(SpringbootApplication.class, args);
System.out.println("Spring Boot Application started .....");
}

}


How to test Spring Security application 

1. Right click on SpringbootApplication and start application open new Browser type following URL 

http://localhost:8080/swagger-ui.html#










User Service URL is not protected with spring security so it does not require authentication .
Now add two User with using Swagger URL using add user Post URL

First User Details
   
 UserId = 1
 UserName = "jk123"
 Password = "jk123"
 Role     = "USER"


Second User Details 

   UserId = 1
   UserName = "john"
   Password = "john"
   Role     = "ADMIN"

After adding above two user open new Browser type following URL for user Service with userId 1

http://localhost:8080/adminapi/user/findUserById/1








2.Testing of Employee Service 

Employee Service is protected by Spring Security it require authentication for employee Service we have set following username ,password and role
 
username = john
password = john
role     = ADMIN

Open new Browser window and type following URL
http://localhost:8080/adminapi/employee/findEmployeeById/1

after entering above URL it open a login form like bellow









After the entering username and password click on login button it authenticate user and gives following response .











So So Until we didn't added any employee in our application so go to Swagger UI and add one employee with employeeId 1 and then add following URL

http://localhost:8080/adminapi/employee/findEmployeeById/1

above URL gives Response with Employee Id 1










Note :- IF you try access product service URL which protect by other user details then 
it gives following response with Product Service URL

http://localhost:8080/adminapi/product/findProductById/1












3.Testing of Product Service 

Product Service is protected by Spring Security it require authentication for Product Service we have set following username ,password and role
 
username = jk123
password = jk123
role     = USER

Open new Browser window and type following URL

http://localhost:8080/adminapi/product/findProductById/10
after entering above URL it open a login form like bellow







After the entering username and password click on login button it authenticate use and gives following response .




So until we didn't added any product in our application so go to Swagger UI and add one product with productId 1 and then add following URL

http://localhost:8080/adminapi/product/findProductById/1

above URL gives Response with productId 1






Note :- IF you try access employee service URL which employee by other user details then 
it gives following response with Employee Service URL

http://localhost:8080/adminapi/employee/findEmployeeById/1








 






This is  how we can implement Spring Security in Springboot application .

please comment if you find any mistake ....