Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

️ Role-Based Access Control (RBAC) & Custom Error Handling

Project Overview

Authentication is only half the battle. This project demonstrates how to differentiate between standard Users and Admins. It also shows how to "gracefully fail" by returning clean, professional JSON error messages when a user tries to access a resource they aren't authorized for.


Technical Concepts

1. Method-Level Security (@EnableMethodSecurity)

Instead of just securing URLs in the config file, we use annotations directly on the Controller methods.

  • @PreAuthorize("hasRole('ADMIN')"): This is powerful because it checks the user's authority before the method even executes. If the check fails, an AccessDeniedException is thrown.

2. Custom Access Denied Handler

By default, Spring Security returns a generic "Whitelabel Error Page" for 403 Forbidden errors. We implemented CustomAccessDeniedHandler to:

  • Intercept authorization failures.
  • Return a structured JSON response (ideal for modern frontend/mobile apps).
  • Provide specific context like the requested path and a custom message.

3. Hierarchical Permissions

In SecurityConfig.java, we define two users:

  • Ejaz: Has the role USER.
  • Amiya: Has the roles ADMIN and USER. This allows Amiya to access everything, while Ejaz is restricted to his own profile.

Component Reference

UserController.java

Contains three tiers of access:

  1. Public: /auth/welcome (No login required).
  2. Private (User): /auth/user/userProfile (Requires USER role).
  3. Restricted (Admin): /auth/admin/adminProfile (Requires ADMIN role).

GlobalExceptionHandler.java

Uses @ControllerAdvice to catch AccessDeniedException across the entire application. This ensures that even if an error occurs outside of the standard filter chain, the user receives a consistent response.


Testing the Security Matrix

User Endpoint Expected Result Why?
Anonymous /auth/welcome 200 OK Permitted to all.
Ejaz (User) /auth/user/userProfile 200 OK Has required USER role.
Ejaz (User) /auth/admin/adminProfile 403 Forbidden Custom JSON error triggered.
Amiya (Admin) /auth/admin/adminProfile 200 OK Has required ADMIN role.

Key Concepts Explained Simply:

CustomAccessDeniedHandler

AccessDeniedHandler:

  • Triggered when a user is authenticated but lacks the required role/authority.
  • Example: A logged-in user with role USER tries to access /admin.

Default Behavior:

  • Spring Security normally shows a generic error page (HTML).
  • Custom Behavior (this class):
  • Returns a JSON response instead of HTML.
  • Makes it easier for front-end apps (React, Angular, Vue, etc.) to handle errors.
  • Response Example:
{
 "status": 403,
 "error": "Forbidden",
 "message": "You do not have permission to access this admin's resources",
 "path": "/admin/dashboard"
 } 

SecurityConfig

  • @EnableMethodSecurity: Allows method-level annotations like @PreAuthorize("hasRole('ADMIN')").
  • CustomAccessDeniedHandler: Returns JSON instead of default HTML error page when access is denied.

Authorization Rules:

  • /auth/welcome → public.
  • /auth/user/** → requires USER role.
  • /auth/admin/** → requires ADMIN role.
  • Form Login: Redirects to /auth/welcome after login.
  • HTTP Basic: Allows API clients to authenticate with headers.
  • InMemoryUserDetailsManager: Stores demo users (Amiya as ADMIN+USER, Ejaz as USER).

GlobalExceptionHandler

  • @ControllerAdvice: Centralizes exception handling → applies to all controllers.
  • @ExceptionHandler(AccessDeniedException.class): Handles authorization failures globally.
  • AccessDeniedException: Thrown when a logged-in user tries to access a resource they don’t have permission for.
  • ResponseEntity: Lets you return both a body (JSON message) and a status code.
  • Map.of(...): Creates a simple JSON-like response →
 { "message": "Access Denied: You are not an Admin!" }

UserController

  • @RestController: Exposes endpoints that return plain text/JSON responses.
  • @RequestMapping("/auth"): Base path → all endpoints start with /auth.
  • @PreAuthorize: Method-level security → checks roles before executing the method.

Role-based Access:

  • /auth/welcome → public (no login required).
  • /auth/user/userProfile → requires USER role.
  • /auth/admin/adminProfile → requires ADMIN role.

SpringSecurityAuthenticationAuthorizationDemoApplication

  • @SpringBootApplication: Marks this as the main Spring Boot app → auto-configures everything.
  • SpringApplication.run(): Starts the app → loads beans, controllers, and security configuration.

Integration:

  • Loads your SecurityConfig (role-based rules + custom access denied handler).
  • Loads your UserController (endpoints for welcome, user, and admin).
  • Connects exception handling (GlobalExceptionHandler).

How to Test

  1. Run Application: Start SpringSecurityAuthenticationAuthorizationDemoApplication.
  2. Public Test: Open http://localhost:8080/auth/welcome. No login needed.
  3. Authorization Test (Failure):
    • Login as Ejaz (Password: 456).
    • Try to access http://localhost:8080/auth/admin/adminProfile.
    • Result: You will see the custom JSON message: "You do not have permission to access this admin's resources".
  4. Authorization Test (Success):
    • Login as Amiya (Password: 123).
    • Access the Admin profile. Success!

About

Advanced RBAC implementation using Spring Security 6. Includes Method-Level Security (@PreAuthorize), custom AccessDeniedHandler, and Global Exception Handling.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages