Java Microservice with Authentication and User Interface

2 min read

Java Microservice with Authentication and User Interface

Microservice architecture, integrating a user interface (UI) involves designing a dynamic frontend that interacts seamlessly with the backend microservices. The UI serves as the entry point for users, where authentication, data visualization, and resource access occur.

This article details the integration of a user interface with a Java-based microservices architecture and provides a comprehensive system design with examples.

System Components with UI Integration

  1. Frontend (User Interface):
    • Built using ReactJS, Angular, or any other modern frontend framework.
    • Handles user interactions like login, account management, and resource access.
    • Communicates with the backend via HTTP (REST) or GraphQL.
  2. API Gateway:
    • Acts as the intermediary between the UI and backend services.
    • Verifies authentication tokens, handles routing, and implements rate limiting.
  3. Authentication Server:
    • Authenticates user credentials and issues tokens (e.g., JWT).
    • Enables secure communication between the client and backend services.
  4. Backend Microservices:
    • Perform specific business functions such as user management, order processing, and payments.
  5. Database:
    • Each microservice has an isolated database for storing domain-specific data.

High-Level Architecture Diagram

Here’s an integrated architecture combining the user interface and microservices:

+-----------------------+
|      User Interface   |  Built with ReactJS/Angular
| (Web App / Mobile App)|         Handles user interactions.
+-----+-----------------+
      | HTTP/GraphQL
      v
+------------------------------------+
|          API Gateway               |
| Token Validation, Routing, etc.    |
+-------------+----------------------+
              |
   +----------+----------+----------+
   |                     |          |
+--v---+             +---v---+  +---v---+
| Auth |             | Users  |  | Other |
|Service|            |Service |  |Service|
+-------+             +-------+  +-------+
              Microservices

Step-by-Step Implementation

1. User Interface (Frontend)

The UI is built as a Single Page Application (SPA) using ReactJS. It handles user actions and communicates with the backend.

Login Form: A simple form collects user credentials and sends them to the authentication service.

function Login() {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");

  const handleSubmit = async (e) => {
    e.preventDefault();
    const response = await fetch("http://localhost:8080/auth/login", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ username, password }),
    });
    const data = await response.json();
    localStorage.setItem("token", data.token); // Store JWT locally
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" onChange={(e) => setUsername(e.target.value)} placeholder="Username" />
      <input type="password" onChange={(e) => setPassword(e.target.value)} placeholder="Password" />
      <button type="submit">Login</button>
    </form>
  );
}

Protected Route: Use a higher-order component (HOC) to guard routes that require authentication.

function ProtectedRoute({ children }) {
  const token = localStorage.getItem("token");
  if (!token) {
    return <Redirect to="/login" />;
  }
  return children;
}

2. API Gateway

The API Gateway validates the token before routing requests to microservices.

Dependency: Add Spring Cloud Gateway to the project:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>

Route Configuration:

spring:
  cloud:
    gateway:
      routes:
        - id: auth_route
          uri: http://auth-service
          predicates:
            - Path=/auth/**
        - id: user_route
          uri: http://user-service
          predicates:
            - Path=/users/**

Token Validation: Add a filter to validate tokens before routing:

@Bean
public GlobalFilter tokenValidationFilter() {
    return (exchange, chain) -> {
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (token == null || !isValidToken(token)) {
            return exchange.getResponse().setComplete();
        }
        return chain.filter(exchange);
    };
}

private boolean isValidToken(String token) {
    // Token validation logic here
}

3. Backend Microservice

Example: User Service

User Entity:

@Entity
public class User {
    @Id
    @GeneratedValue
    private Long id;
    private String username;
    private String password;
    private String role;
}

REST Controller:

@RestController
@RequestMapping("/users")
public class UserController {
    @GetMapping
    public ResponseEntity<List<User>> getUsers() {
        return ResponseEntity.ok(userRepository.findAll());
    }
}

Token Parsing for Authorization:

@PreAuthorize("hasRole('ADMIN')")
@GetMapping("/admin")
public ResponseEntity<String> adminEndpoint() {
    return ResponseEntity.ok("Access granted to admin");
}

4. Authentication Server

The authentication server validates user credentials and issues JWTs.

Login Endpoint:

@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody LoginRequest request) {
    // Validate user credentials
    String token = jwtUtil.generateToken(request.getUsername());
    return ResponseEntity.ok(new LoginResponse(token));
}

JWT Utility:

public String generateToken(String username) {
    return Jwts.builder()
        .setSubject(username)
        .signWith(SignatureAlgorithm.HS256, secretKey)
        .compact();
}

Features of the System

  1. Scalability: Microservices and UI components can scale independently based on demand.
  2. Security: JWT authentication ensures secure communication between clients and backend services.
  3. Seamless User Experience: The React-based SPA provides a responsive and dynamic interface.
  4. Customizable Authorization: Role-based access control enforces proper access to resources.

Conclusion

Integrating a user interface with a Java microservices architecture involves designing a dynamic and secure frontend while leveraging backend components like an API Gateway, authentication service, and microservices. By incorporating JWT authentication, token validation, and role-based access, this system ensures a seamless and secure user experience.

🤞 Never miss a story from us, get weekly updates to your inbox!