Overview
Trippins implements a role-based access control (RBAC) system with three distinct user types: Anonymous users, Registered users (Clients), and Administrators. Each role has different permissions and access levels within the platform.
User Role Hierarchy
Anonymous Public visitors (no account)
Registered User Authenticated clients (ROLE_USER)
Administrator Platform admins (ROLE_ADMIN)
User Entity Structure
Base User Entity
All users inherit from a common base entity:
@ Entity
@ Table ( name = "User" )
public class User {
@ Id
@ Column ( name = "dni" , nullable = false , unique = true , length = 9 )
private String dni ;
@ Column ( name = "name" , nullable = false , unique = true , length = 100 )
private String name ;
@ Column ( name = "number" , nullable = false , unique = true , length = 9 )
private Integer number ;
@ Column ( name = "password" , nullable = false , length = 20 )
private String password ;
@ Column ( name = "email" , nullable = false , unique = true , length = 40 )
private String email ;
@ Column ( name = "is_admin" , nullable = false )
protected Boolean admin ;
@ ElementCollection ( fetch = FetchType . EAGER )
private List < String > roles ;
@ Column ( name = "encoded_password" , nullable = true )
private String encodedPassword ;
}
Client Entity
Regular users are represented by the Client entity:
@ Entity
public class Client extends User {
public Client () {}
public Client ( String dni , String name , Integer number , String password , String email ) {
super (dni, name, number, password, email);
this . admin = false ; // Not an admin
}
}
Admin Entity
Administrators have elevated privileges:
@ Entity
public class Admin extends User {
public Admin () {}
public Admin ( String dni , String name , Integer number , String password , String email ) {
super (dni, name, number, password, email);
this . admin = true ; // Is an admin
}
}
Anonymous Users
Capabilities
Anonymous users (not logged in) can:
Browse Properties View the housing catalog at /room
Search & Filter Use search functionality with tags and stars
View Public Pages Access home, about, contact pages
Register Account Create a new user account
Restrictions
Anonymous users cannot :
View property details
Make reservations
Write reviews
Access user profile
Create new properties
Security Configuration
. authorizeHttpRequests (auth -> auth
// Public endpoints for anonymous users
. requestMatchers ( "/" , "/index" , "/about" , "/contact" , "/register" ). permitAll ()
. requestMatchers ( "/room" , "/v1/api/query" ). permitAll ()
. requestMatchers ( HttpMethod . POST , "/addUser" , "/v1/api/users" ). permitAll ()
. requestMatchers ( HttpMethod . POST , "/v1/api/login" ). permitAll ()
// ... authenticated routes require login
)
When an anonymous user tries to access a protected resource, they are redirected to the login page with a returnUrl parameter to redirect back after authentication.
Registered Users (Clients)
Role Assignment
When users register, they automatically receive the ROLE_USER role:
// During registration
this . userService . createAccount ({
name: formData . name ,
email: formData . email ,
dni: formData . dni ,
number: formData . number ,
password: formData . password
}). subscribe ({
next : () => {
// User created with ROLE_USER
this . router . navigate ([ 'new/login' ]);
}
});
User Capabilities
Registered users have all anonymous capabilities plus :
View Property Details
Access full property information at /room/{code}
Make Reservations
Book accommodations for specific dates
Write Reviews
Submit ratings and comments for properties
Manage Profile
View and update personal information
Create Properties
Submit new hotel listings (requires admin approval)
User DTO Structure
public class UserDTO {
private String dni ;
private String name ;
private Integer number ;
private String email ;
private Boolean admin ; // false for regular users
private List < String > roles ; // ["ROLE_USER"]
}
User Permissions in Security Config
. authorizeHttpRequests (auth -> auth
// Authenticated users (ROLE_USER and ROLE_ADMIN)
. requestMatchers ( "/room/{code}" , "/roomDetails" ). authenticated ()
. requestMatchers ( "/newHotel" , "/booking" , "/profile" ). authenticated ()
. requestMatchers ( HttpMethod . POST , "/addHotel" ). hasAnyRole ( "USER" , "ADMIN" )
// ...
)
Checking User Authentication
// Check if user is logged in
isLoggedIn (): boolean {
return !! this . getJwt ();
}
// Get user roles
getRoles (): string [] {
const rolesJson = localStorage . getItem ( this . ROLES_KEY );
return rolesJson ? JSON . parse ( rolesJson ) : [];
}
// Check specific role
hasRole ( role : string ): boolean {
return this . getRoles (). includes ( role );
}
Administrators
Admin Capabilities
Administrators have all user capabilities plus exclusive admin functions:
User Management View, create, update, and delete all users
Review Moderation Manage all reviews across the platform
Property Approval Approve or reject housing submissions
Reservation Management View and manage all reservations
Admin-Only Endpoints
. authorizeHttpRequests (auth -> auth
// Admin-only access
. requestMatchers ( "/v1/api/users/**" ). hasRole ( "ADMIN" )
. requestMatchers ( "/v1/api/reviews/**" ). hasRole ( "ADMIN" )
. requestMatchers ( "/v1/api/admin/**" ). hasRole ( "ADMIN" )
. requestMatchers ( "/admin/**" , "/admin" ). hasRole ( "ADMIN" )
// ...
)
Admin Panel Routes
// Angular routing with admin guard
{
path : 'admin' ,
component : AdminComponent ,
canActivate : [ AdminGuard ], // Checks for ROLE_ADMIN
children : [
{ path: 'housing' , component: HousingPanelComponent },
{ path: 'reservations' , component: ReservationPanelComponent },
{ path: 'users' , component: UserPanelComponent },
{ path: 'reviews' , component: ReviewPanelComponent }
]
}
Admin Role Verification
// Check if current user is admin
isAdmin (): boolean {
return this . authService . hasRole ( 'ROLE_ADMIN' );
}
// Check for any required role
hasAnyRole ( roles : string []): boolean {
var currentRoles : string [] = this . getRoles ();
for ( let index = 0 ; index < roles . length ; index ++ ) {
if ( currentRoles . includes ( roles [ index ])) {
return true ;
}
}
return false ;
}
Role-Based API Access
User Management APIs
GET /v1/api/users Get all users (admin only)
@ GetMapping
@ SecurityRequirement ( name = "JWT" )
public ResponseEntity < List < UserDTO >> getAllUsers () {
// Only accessible to ROLE_ADMIN
List < UserDTO > users = userService . getAllUsers ();
return ResponseEntity . ok (users);
}
POST /v1/api/users Create new user (public for registration)
@ PostMapping
@ SecurityRequirement ( name = "JWT" )
public ResponseEntity < UserDTO > createUser (@ RequestBody RegisteredUserDTO user) {
UserDTO createdUser = userService . createUser (user);
return ResponseEntity . status ( HttpStatus . CREATED ). body (createdUser);
}
PUT /v1/api/users/{id} Update user (admin only)
DELETE /v1/api/users/{id} Delete user (admin only)
Review Management APIs
POST /v1/api/reviews - Create Review
Access : Any authenticated user (ROLE_USER or ROLE_ADMIN)Users can create reviews for properties they’ve visited.
GET /v1/api/reviews - Get All Reviews
Access : Admin only (ROLE_ADMIN)Retrieve complete list of all reviews across all properties.
PUT /v1/api/reviews/{id} - Update Review
Access : Admin only (ROLE_ADMIN)Modify any review (useful for moderation).
DELETE /v1/api/reviews/{id} - Delete Review
Access : Admin only (ROLE_ADMIN)Remove inappropriate or spam reviews.
Permission Matrix
Action Anonymous Registered User Administrator View housing list ✅ ✅ ✅ Search properties ✅ ✅ ✅ View property details ❌ ✅ ✅ Make reservation ❌ ✅ ✅ Write review ❌ ✅ ✅ Create property ❌ ✅ (pending approval) ✅ Approve property ❌ ❌ ✅ View all users ❌ ❌ ✅ Manage users ❌ ❌ ✅ Moderate reviews ❌ ❌ ✅ View all reservations ❌ Own only ✅ All
Role Checking in Components
Frontend Role Guards
// Admin guard
@ Injectable ()
export class AdminGuard implements CanActivate {
constructor ( private authService : AuthService , private router : Router ) {}
canActivate () : boolean {
if ( this . authService . hasRole ( 'ROLE_ADMIN' )) {
return true ;
}
this . router . navigate ([ '/' ]);
return false ;
}
}
// Auth guard (any logged-in user)
@ Injectable ()
export class AuthGuard implements CanActivate {
constructor ( private authService : AuthService , private router : Router ) {}
canActivate ( route : ActivatedRouteSnapshot ) : boolean {
if ( this . authService . isLoggedIn ()) {
return true ;
}
// Redirect to login with return URL
this . router . navigate ([ '/new/login' ], {
queryParams: { returnUrl: route . url }
});
return false ;
}
}
Conditional UI Elements
< div * ngIf = "authService.isLoggedIn()" >
<!-- Shown to logged - in users -->
< button ( click ) = "makeReservation()" > Book Now </ button >
</ div >
< div * ngIf = "authService.hasRole('ROLE_ADMIN')" >
<!-- Shown only to admins -->
< button ( click ) = "approveProperty()" > Approve </ button >
< button ( click ) = "deleteUser()" > Delete User </ button >
</ div >
< div * ngIf = "!authService.isLoggedIn()" >
<!-- Shown to anonymous users -->
< a routerLink = "/new/login" > Log in to book </ a >
</ div >
JWT Token and Roles
Token Structure
When users log in, they receive a JWT token containing their roles:
{
"jwt" : "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." ,
"roles" : [ "ROLE_USER" ] // or ["ROLE_ADMIN"]
}
Role Storage
// Store roles in localStorage
private storeRoles ( roles : string []): void {
localStorage . setItem ( this . ROLES_KEY , JSON . stringify ( roles ));
}
// Retrieve roles
getRoles (): string [] {
const rolesJson = localStorage . getItem ( this . ROLES_KEY );
return rolesJson ? JSON . parse ( rolesJson ) : [];
}
@ PostMapping ( "/v1/api/login" )
public ResponseEntity < ? > createAuthenticationToken (
@ RequestBody AuthenticationRequest authenticationRequest) {
// Authenticate user
authenticationManager . authenticate (
new UsernamePasswordAuthenticationToken (
authenticationRequest . getEmail (),
authenticationRequest . getPassword ()
)
);
// Load user details
final UserDetails userDetails = userDetailsService
. loadUserByUsername ( authenticationRequest . getEmail ());
// Generate JWT
final String jwt = jwtUtil . generateToken (userDetails);
// Extract roles from authorities
List < String > roles = userDetails . getAuthorities (). stream ()
. map (GrantedAuthority :: getAuthority)
. collect ( Collectors . toList ());
return ResponseEntity . ok ( new AuthenticationResponse (jwt, roles));
}
Best Practices
Principle of Least Privilege
Grant users only the minimum permissions needed to perform their tasks. Don’t give admin rights unnecessarily.
Hide or disable UI elements that users don’t have permission to use: < button * ngIf = "canEditUser()" ( click ) = "edit()" > Edit </ button >
Always validate permissions on the backend, never trust client-side role checks: @ PreAuthorize ( "hasRole('ADMIN')" )
public void deleteUser ( String id) { ... }
Log all admin actions for security and compliance: logger . info ( "Admin {} deleted user {}" , adminId, userId);
Consider implementing role hierarchy where ADMIN inherits USER permissions automatically.
Manual Database Update
Currently, users are promoted to admin via direct database modification:
-- Update user to admin
UPDATE User SET is_admin = true WHERE dni = '12345678A' ;
-- Add ROLE_ADMIN to user's roles
-- (Implementation depends on your ElementCollection storage)
Consider implementing an API endpoint for admin promotion:
@ PutMapping ( "/users/{id}/promote" )
@ PreAuthorize ( "hasRole('ADMIN')" )
public ResponseEntity < UserDTO > promoteToAdmin (@ PathVariable String id) {
UserDTO user = userService . getUserById (id);
user . setAdmin ( true );
user . getRoles (). add ( "ROLE_ADMIN" );
UserDTO updated = userService . updateUser (id, user);
return ResponseEntity . ok (updated);
}
Admin promotion should be strictly controlled and logged. Consider implementing approval workflows or requiring multiple admin approvals for sensitive operations.
Security Considerations
Trippins uses stateless JWT authentication: . sessionManagement (session -> session
. sessionCreationPolicy ( SessionCreationPolicy . STATELESS )
)
CSRF is disabled for stateless API: . csrf (csrf -> csrf . disable ())
Note : Re-enable CSRF if you add session-based authentication.
All passwords are encrypted with BCrypt: @ Bean
public PasswordEncoder passwordEncoder () {
return new BCryptPasswordEncoder ();
}
Always use HTTPS in production to protect JWT tokens during transmission.
Troubleshooting
403 Forbidden on Admin Endpoint
Verify user has ROLE_ADMIN in their roles array
Check JWT token contains correct roles
Ensure token is being sent in Authorization header
Verify Spring Security configuration allows admin access
User Can't Access Protected Resource
Confirm user is logged in (isLoggedIn() returns true)
Check JWT token is stored in localStorage
Verify token hasn’t expired
Ensure route guard is properly configured
Roles Not Persisting After Login
Check if storeRoles() is being called after login
Verify localStorage is not being cleared
Ensure roles are included in login response
Check browser’s localStorage in DevTools
Authentication Learn how to log in and register
Making Reservations Requires registered user role
Writing Reviews Available to authenticated users
Browsing Housing Public access with enhanced features for users