Need of Microservices Authentication using Cookie
Take the example of a servicing centre as shown the bellow picture. When customer calls the Servicing centre for any kind of help then he/she needs to provide consumer details to the call centre representative. The call centre representative validates the consumer details and provides desired solution. If the solution does not work for the customer then the customer needs to call the representative again and provide consumer detail again as the first time call. This process continues if the servicing centre is stateless as HTTP. It sounds weird.
Microservice web-server communicate with each other by means of HTTP where HTTP is a stateless protocol means one client sends request through HTTP to server and the server serves the response to the user or client and forgets it. Again when the client comes and sends request there is no connection between two consecutive requests. So to avoid these consequences we use different approach such as Session+Cookie Or JWT (JSON Web Token).
Note: Session+Cookie is limited only for the web application in browser
What is a microservice?
Microservices are an architectural approach to building applications. As an architectural framework, microservices are distributed and loosely coupled, so one team’s changes won’t break the entire app. The benefit to using microservices is that development teams are able to rapidly build new components of apps to meet changing business needs.
To know more click on link provided https://en.wikipedia.org/wiki/Microservices
Create Your own Application by taking this Video Reference
Requirements for building an Application based on Microservices Authentication and Authorization using Cookie
1. Add jbcrypt Dependencies
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>com.example</groupId> <artifactId>LoanService</artifactId> <version>0.0.1-SNAPSHOT</version> <name>LoanService</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-web</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.mindrot/jbcrypt --> <dependency> <groupId>org.mindrot</groupId> <artifactId>jbcrypt</artifactId> <version>0.3m</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>
2. Creation of Starter Or Main Class
LoanServiceApplication.java
package com.example.office;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class LoanServiceApplication {
public static void main(String[] args) { SpringApplication.run(LoanServiceApplication.class, args); }
}
3. Creation of Controllers
Account.java
package com.example.office.controller; public class Account { int accountNo; long amount; public int getAccountNo() { return accountNo; } public void setAccountNo(int accountNo) { this.accountNo = accountNo; } public long getAmount() { return amount; } public void setAmount(long amount) { this.amount = amount; } }
AccountError.java
package com.example.office.controller; public class AccountError { String message; public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
LoanController.java
package com.example.office.controller; import java.util.ArrayList; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.mindrot.jbcrypt.BCrypt; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; @RestController public class LoanController { @Autowired HttpSession session; @RequestMapping(value = "/login",method=RequestMethod.POST) public ResponseEntity validate(@RequestParam String uid,@RequestParam String pass) { HttpHeaders headers = new HttpHeaders();String cookie="xyz";
String hashedCookie=hashPassword(cookie);
int age=60*60*24*7;
headers.add("Set-Cookie",hashedCookie+"; Max-Age="+age);
session.setAttribute("token",cookie);
if(uid.equals("admin") && pass.equals("1234"))
{
ResponseEntity<?> res= ResponseEntity.status(HttpStatus.OK).headers(headers).body("Welcome "+uid);
return res;
}
else
{
ResponseEntity<?> res= ResponseEntity.status(HttpStatus.NOT_FOUND).body("Invalid credentials");
return res;
}
}
@RequestMapping("allAccount")
public List<?> getAllAccounts(HttpServletRequest request)
{
String rawCookie = request.getHeader("Cookie");
String hashedToken=rawCookie.substring(0,rawCookie.indexOf(";")); String token=(String)session.getAttribute("token");
if(checkPass(token,hashedToken))
{
List<Account> allAccount=new ArrayList<Account>();
for(int i=0;i<5;i++)
{
Account acc=new Account();
acc.setAccountNo(i+1000);
acc.setAmount((i+100)*200000);
allAccount.add(acc);
}
return allAccount;
}
else
{
List<AccountError> error=new ArrayList<AccountError>(); AccountError ae=new AccountError();
ae.setMessage("Authorization failed");
error.add(ae);
return error;
}
}
private String hashPassword(String plainTextPassword)
{
return BCrypt.hashpw(plainTextPassword, BCrypt.gensalt());
}
private boolean checkPass(String plainPassword, String hashedPassword)
{
if (BCrypt.checkpw(plainPassword, hashedPassword))
{
return true;
}
else
{
return false;
}
}
}
Procedure To Fetch data over Postman with appropriate images
- Run The Project In postman and give Request method as “POST” and Request url as “localhost: (port_number)/login”
- Click on Body tab and then on form data .
- Mention proper key and value to authenticate.
- Click on send and get the required “cookie” by clicking on Headers.
- Now in another tab give Request method as “GET” and Request url as “localhost: (port_number)/allAccount”.
- Click on headers, and in key type “Cookie” and in value paste the cookie you got from post method
- Click on Send and Fetch the result.
Note: By default port number is 8080, but it can be changed in application.properties file stating “server.port=(your desired port_number)”.
Download full Source Code for Microservices Authentication and Authorization using Cookie | Bcrypt in Microservice Authorization