User Authentication & Role Management

by ADMIN 38 views

Introduction

User authentication and role management are crucial components of any web application, ensuring that only authorized users can access sensitive data and perform specific actions. In this article, we will delve into the implementation of user authentication and role management using Spring Boot, focusing on tasks 7-12.

Task 7: Implement User Entity and Repository

The first step in implementing user authentication is to create a User entity and repository. The User entity represents a user in the system, containing attributes such as username, password, email, and role. The repository is responsible for interacting with the database, providing methods for creating, reading, updating, and deleting users.

User Entity

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    private String email;
    @Enumerated(EnumType.STRING)
    private Role role;
    // Getters and setters
}

User Repository

public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByUsername(String username);
}

Task 8: Create a UserService for Authentication Logic

The UserService is responsible for encapsulating authentication logic, providing methods for user registration, login, and password recovery. This layer acts as an intermediary between the controller and the repository, ensuring that business logic is separated from the presentation layer.

UserService

@Service
public class UserService {
    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    
    public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
    }
    
    public User registerUser(User user) {
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        return userRepository.save(user);
    }
    
    public User login(String username, String password) {
        User user = userRepository.findByUsername(username).orElse(null);
        if (user != null && passwordEncoder.matches(password, user.getPassword())) {
            return user;
        }
        return null;
    }
}

Task 9: Implement JWT Authentication (Login, Token Generation, Validation)

JSON Web Tokens (JWT) are a popular choice for authentication, providing a secure and stateless way to verify user identities. In this task, we will implement JWT authentication, focusing on login, token generation, and validation.

JWT Login

@RestController
public class LoginController {
    private final UserService userService;
    private final JwtTokenProvider jwtTokenProvider;
    
    public LoginController(UserService userService, JwtTokenProvider jwtTokenProvider) {
        this.userService = userService;
        this.jwtTokenProvider = jwtTokenProvider;
    }
    
    @PostMapping("/login")
    public String login(@RequestBody LoginRequest loginRequest) {
        User user = userService.login(loginRequest.getUsername(), loginRequest.getPassword());
        if (user != null) {
            String token = jwtTokenProvider.generateToken(user);
            return token;
        }
        return "Invalid username or password";
    }
}

JWT Token Generation

public class JwtTokenProvider {
    private final String secretKey;
    
    public JwtTokenProvider(String secretKey) {
        this.secretKey = secretKey;
    }
    
    public String generateToken(User user) {
        return Jwts.builder()
                .setSubject(user.getUsername())
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + 86400000))
                .signWith(SignatureAlgorithm.HS256, secretKey)
                .compact();
    }
}

JWT Token Validation

public class JwtTokenProvider {
    // ...
    
    public boolean validateToken(String token) {
        try {
            Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
            return true;
        } catch (Exception e) {
            return false;
        }
    }
}

Task 10: Secure API Endpoints with JWT & Spring Security

Spring Security provides a robust framework for securing API endpoints, integrating seamlessly with JWT authentication. In this task, we will configure Spring Security to secure API endpoints using JWT.

Spring Security Configuration

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private JwtTokenProvider jwtTokenProvider;
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/register", "/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .addFilter(new JwtAuthenticationFilter(authenticationManager(), jwtTokenProvider));
    }
}

JWT Authentication Filter

public class JwtAuthenticationFilter extends OncePerRequestFilter {
    private final AuthenticationManager authenticationManager;
    private final JwtTokenProvider jwtTokenProvider;
    
    public JwtAuthenticationFilter(AuthenticationManager authenticationManager, JwtTokenProvider jwtTokenProvider) {
        this.authenticationManager = authenticationManager;
        this.jwtTokenProvider = jwtTokenProvider;
    }
    
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        String token = request.getHeader("Authorization");
        if (token != null && jwtTokenProvider.validateToken(token)) {
            Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(token, null));
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        chain.doFilter(request, response);
    }
}

Task 11: Implement Role-Based Access Control (Admin, Recruiter, Job Seeker)

Role-based access control is a critical component of any web application, ensuring that users have the necessary permissions to perform specific actions. In this task, we will implement role-based access control, focusing on Admin, Recruiter, and Job Seeker roles.

Role Enum

public enum Role {
    ADMIN,
    RECRUITER,
    JOB_SEEKER
}

User Service Update

@Service
public class UserService {
    // ...
    
    public User registerUser(User user) {
        user.setRole(Role.JOB_SEEKER);
        user.setPassword(passwordEncoder.encode(user.getPassword()));
        return userRepository.save(user);
    }
    
    public User login(String username, String password) {
        User user = userRepository.findByUsername(username).orElse(null);
        if (user != null && passwordEncoder.matches(password, user.getPassword())) {
            return user;
        }
        return null;
    }
}

Security Configuration Update

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    // ...
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/register", "/login").permitAll()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .antMatchers("/recruiter/**").hasRole("RECRUITER")
                .antMatchers("/job-seeker/**").hasRole("JOB_SEEKER")
                .anyRequest().authenticated()
                .and()
                .addFilter(new JwtAuthenticationFilter(authenticationManager(), jwtTokenProvider));
    }
}

Task 12: Develop POST /register and POST /login APIs

The final task is to develop POST /register and POST /login APIs, providing a user-friendly interface for users to register and login.

Register API

@RestController
public class RegisterController {
    private final UserService userService;
    
    public RegisterController(UserService userService) {
        this.userService = userService;
    }
    
    @PostMapping("/register")
    public String register(@RequestBody RegisterRequest registerRequest) {
        User user = userService.registerUser(registerRequest.toUser());
        return "User registered successfully";
    }
}

Login API

@RestController
public class LoginController {
    private final UserService userService;
    private final JwtTokenProvider jwtTokenProvider;
    
    public LoginController(UserService userService, JwtTokenProvider jwtTokenProvider) {
        this.userService = userService;
        this.jwtTokenProvider = jwtTokenProvider;
    }
    
    @PostMapping("/login")
    public String login(@RequestBody LoginRequest loginRequest) {
        User user = userService.login(loginRequest.getUsername(), loginRequest.getPassword());
        if (user != null) {
            String token = jwtTokenProvider.generateToken(user);
            return token;
        }
        return "Invalid username or password";
    }
}

Q1: What is user authentication, and why is it important?

A1: User authentication is the process of verifying a user's identity, ensuring that only authorized users can access sensitive data and perform specific actions. It is essential for maintaining the security and integrity of a web application.

Q2: What is role-based access control (RBAC), and how does it work?

A2: RBAC is a security approach that assigns users to specific roles, which determine their level of access to resources and actions within a system. Users are granted permissions based on their role, ensuring that they can only perform actions that are relevant to their position.

Q3: What is JSON Web Token (JWT), and how is it used for authentication?

A3: JWT is a compact, URL-safe means of representing claims to be transferred between two parties. In the context of authentication, JWT is used to verify a user's identity by generating a token that contains user information and is signed with a secret key.

Q4: What is the difference between JWT and OAuth?

A4: JWT and OAuth are both used for authentication, but they serve different purposes. JWT is used for verifying a user's identity, while OAuth is used for granting access to resources on behalf of the user.

Q5: How do I implement JWT authentication in a Spring Boot application?

A5: To implement JWT authentication in a Spring Boot application, you can use the following steps:

  1. Create a User entity and repository.
  2. Create a UserService for authentication logic.
  3. Implement JWT authentication using a library such as Spring Security.
  4. Configure Spring Security to secure API endpoints using JWT.

Q6: How do I secure API endpoints using Spring Security?

A6: To secure API endpoints using Spring Security, you can use the following steps:

  1. Configure Spring Security to use JWT authentication.
  2. Use the @Secured annotation to specify the roles required for each API endpoint.
  3. Use the @PreAuthorize annotation to specify the conditions under which an API endpoint can be accessed.

Q7: How do I implement role-based access control (RBAC) in a Spring Boot application?

A7: To implement RBAC in a Spring Boot application, you can use the following steps:

  1. Create a Role enum to define the different roles in your application.
  2. Create a User entity and repository to store user information and roles.
  3. Create a UserService to manage user roles and permissions.
  4. Configure Spring Security to use RBAC.

Q8: How do I handle user registration and login in a Spring Boot application?

A8: To handle user registration and login in a Spring Boot application, you can use the following steps:

  1. Create a RegisterController to handle user registration requests.
  2. Create a LoginController to handle user login requests.
  3. Use a library such as Spring Security to secure the registration and login endpoints.

Q9: How do I implement password encryption in a Spring Boot application?

A9: To implement password encryption in a Spring Boot application, you can use a library such as BCrypt to encrypt passwords before storing them in the database.

Q10: How do I troubleshoot authentication issues in a Spring Boot application?

A10: To troubleshoot authentication issues in a Spring Boot application, you can use the following steps:

  1. Check the application logs for authentication-related errors.
  2. Verify that the user credentials are correct.
  3. Check that the authentication configuration is correct.
  4. Use a debugging tool to step through the authentication code.