Bu bo‘limda JWT filter chain setup, Resource Server configuration, OAuth2 login, method-level security, va SecurityContext / authentication propagationni o‘rganamiz.
Spring Security - authentication, authorization va common attacklardan himoya qilish uchun Spring ekotizimidagi asosiy framework hisoblanadi. (Home)
1. Authentication vs Authorization
Spring Security’da ikki asosiy tushuncha bor:
Tushuncha | Ma’nosi | Misol |
|---|---|---|
Authentication | Kimligini aniqlash | "Bu user Ali" |
Authorization | Nima qilishga ruxsati borligini tekshirish | "Ali admin panelga kira oladimi?" |
Oddiy oqim:
1. User login qiladi
2. System userni tekshiradi
3. Token yoki session beradi
4. Keyingi requestlarda user taniladi
5. Role/permission tekshiriladi2. Spring Security qanday ishlaydi?
Spring Security asosan filter chain orqali ishlaydi.
HTTP request kelganda:
Client
↓
Security Filters
↓
ControllerFilterlar quyidagilarni qiladi:
token bor-yo‘qligini tekshiradi;
tokenni validatsiya qiladi;
userni aniqlaydi;
SecurityContextga authentication qo‘yadi;endpointga ruxsat bor-yo‘qligini tekshiradi.
3. SecurityFilterChain
Oldingi Spring Security versiyalarida WebSecurityConfigurerAdapter ishlatilardi. Hozir modern usul - SecurityFilterChain bean yozish.
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http)
throws Exception {
return http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.requestMatchers("/api/admin/**").hasRole("ADMIN")
.anyRequest().authenticated()
)
.build();
}
}Bu yerda:
Qism | Ma’nosi |
|---|---|
| Login/register ochiq |
| Faqat ADMIN |
| Qolgan hammasi login talab qiladi |
4. JWT nima?
JWT - JSON Web Token.
JWT odatda 3 qismdan iborat:
header.payload.signatureMasalan:
xxxxx.yyyyy.zzzzzJWT ichida odatda quyidagi claimlar bo‘ladi:
{
"sub": "user-id",
"username": "ali",
"roles": ["ROLE_USER", "ROLE_ADMIN"],
"iat": 1710000000,
"exp": 1710003600
}Claim | Ma’nosi |
|---|---|
| Token egasi |
| Qachon chiqarilgan |
| Qachon tugaydi |
| Rolelar |
| OAuth2 permissionlar |
5. JWT authentication oqimi
1. User login/password yuboradi
2. Server tekshiradi
3. JWT access token beradi
4. Client tokenni saqlaydi
5. Keyingi requestlarda Authorization headerda yuboradiHeader:
Authorization: Bearer eyJhbGciOiJIUzI1NiJ9...Server har requestda tokenni tekshiradi.
6. JWT bilan stateless security
JWT ko‘pincha stateless API uchun ishlatiladi.
Ya’ni server session saqlamaydi:
Server memoryda user session yo‘q
Har request token orqali tekshiriladiConfig:
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)To‘liq misol:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http)
throws Exception {
return http
.csrf(csrf -> csrf.disable())
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
)
.build();
}7. Custom JWT filter
Custom JWT auth qilishda odatda OncePerRequestFilter yoziladi.
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtService jwtService;
private final UserDetailsService userDetailsService;
public JwtAuthenticationFilter(
JwtService jwtService,
UserDetailsService userDetailsService
) {
this.jwtService = jwtService;
this.userDetailsService = userDetailsService;
}
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain
) throws ServletException, IOException {
String authHeader = request.getHeader("Authorization");
if (authHeader == null || !authHeader.startsWith("Bearer ")) {
filterChain.doFilter(request, response);
return;
}
String token = authHeader.substring(7);
String username = jwtService.extractUsername(token);
if (username != null &&
SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails =
userDetailsService.loadUserByUsername(username);
if (jwtService.isValid(token, userDetails)) {
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(
userDetails,
null,
userDetails.getAuthorities()
);
authentication.setDetails(
new WebAuthenticationDetailsSource()
.buildDetails(request)
);
SecurityContextHolder.getContext()
.setAuthentication(authentication);
}
}
filterChain.doFilter(request, response);
}
}Asosiy ish:
SecurityContextHolder.getContext().setAuthentication(authentication);Shu joydan keyin Spring request egasini authenticated deb biladi.
8. Filterni chain’ga qo‘shish
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final JwtAuthenticationFilter jwtAuthenticationFilter;
public SecurityConfig(JwtAuthenticationFilter jwtAuthenticationFilter) {
this.jwtAuthenticationFilter = jwtAuthenticationFilter;
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http)
throws Exception {
return http
.csrf(csrf -> csrf.disable())
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
)
.authorizeHttpRequests(auth -> auth
.requestMatchers("/api/auth/**").permitAll()
.anyRequest().authenticated()
)
.addFilterBefore(
jwtAuthenticationFilter,
UsernamePasswordAuthenticationFilter.class
)
.build();
}
}Bu nimani bildiradi?
JWT filter UsernamePasswordAuthenticationFilter’dan oldin ishlaydi9. JwtService sodda ko‘rinishi
Real projectda jjwt yoki nimbus-jose-jwt ishlatiladi.
Soddalashtirilgan interface:
public interface JwtService {
String generateToken(UserDetails userDetails);
String extractUsername(String token);
boolean isValid(String token, UserDetails userDetails);
}Token yaratishda odatda quyidagilar qo‘shiladi:
subject
issuedAt
expiration
roles/authorities
signature10. Login endpoint
@RestController
@RequestMapping("/api/auth")
public class AuthController {
private final AuthenticationManager authenticationManager;
private final JwtService jwtService;
public AuthController(
AuthenticationManager authenticationManager,
JwtService jwtService
) {
this.authenticationManager = authenticationManager;
this.jwtService = jwtService;
}
@PostMapping("/login")
public TokenResponse login(@RequestBody LoginRequest request) {
Authentication authentication =
authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
request.username(),
request.password()
)
);
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
String token = jwtService.generateToken(userDetails);
return new TokenResponse(token);
}
}DTO:
public record LoginRequest(
String username,
String password
) {
}public record TokenResponse(
String accessToken
) {
}11. AuthenticationManager
@Bean
public AuthenticationManager authenticationManager(
AuthenticationConfiguration configuration
) throws Exception {
return configuration.getAuthenticationManager();
}Login paytida:
authenticationManager.authenticate(...)Spring userni UserDetailsService va PasswordEncoder orqali tekshiradi.
12. PasswordEncoder
Passwordni plain text saqlash mumkin emas.
Yomon:
password = 123456To‘g‘ri:
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}Register paytida:
String encoded = passwordEncoder.encode(request.password());
user.setPassword(encoded);Login paytida Spring:
raw password + encoded password -> matches()orqali tekshiradi.
13. UserDetailsService
@Service
public class CustomUserDetailsService implements UserDetailsService {
private final UserRepository userRepository;
public CustomUserDetailsService(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetails loadUserByUsername(String username) {
User user = userRepository.findByUsername(username)
.orElseThrow(() ->
new UsernameNotFoundException("User not found"));
return new CustomUserDetails(user);
}
}CustomUserDetails:
public class CustomUserDetails implements UserDetails {
private final User user;
public CustomUserDetails(User user) {
this.user = user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return user.getRoles()
.stream()
.map(role -> new SimpleGrantedAuthority(role.getName()))
.toList();
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
}Role nomi odatda shunday bo‘ladi:
ROLE_USER
ROLE_ADMIN14. Role vs Authority
Spring Security’da role aslida authority’ning maxsus ko‘rinishi.
.hasRole("ADMIN")Spring ichkarida buni shunday tekshiradi:
ROLE_ADMINYa’ni:
.hasRole("ADMIN")quyidagiga o‘xshaydi:
.hasAuthority("ROLE_ADMIN")Agar permission-based model bo‘lsa:
USER_READ
USER_WRITE
ORDER_CANCELunda:
.hasAuthority("ORDER_CANCEL")ishlatish yaxshi.
15. Resource Server nima?
OAuth2 kontekstida Resource Server - himoyalangan API.
Masalan:
Frontend -> Access Token -> Backend APIBackend API tokenni tekshiradi va requestga ruxsat beradi.
Spring Security Resource Server JWT bilan ishlaganda Spring Boot resource server nomidan default SecurityFilterChain va JWT decoder beanlarini auto-config qilishi mumkin. (Home)
16. Resource Server config
Agar tokenni siz emas, tashqi Authorization Server bersa, masalan Keycloak, Auth0, Okta, Google, unda API’ni Resource Server qilasiz.
Dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>Config:
spring:
security:
oauth2:
resourceserver:
jwt:
issuer-uri: http://localhost:8080/realms/my-realmSecurity config:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http)
throws Exception {
return http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/public/**").permitAll()
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(Customizer.withDefaults())
)
.build();
}Bu holda Spring:
Authorization: Bearer <jwt>tokenni o‘zi decode va validate qiladi.
17. Custom JWT filter vs Resource Server
Yondashuv | Qachon ishlatiladi? |
|---|---|
Custom JWT filter | Tokenni o‘zingiz chiqarasiz, oddiy auth system |
OAuth2 Resource Server | Tokenni Authorization Server chiqaradi |
Keycloak/Auth0/Okta bilan | Resource Server yaxshiroq |
Enterprise SSO | OAuth2/OIDC yaxshiroq |
Amaliy tavsiya:
Oddiy internal loyiha -> custom JWT bo‘lishi mumkin
Katta loyiha / SSO / microservices -> OAuth2 Resource Server18. JWT authority mapping
Ba’zi auth serverlar rolelarni boshqa claim ichida yuboradi.
Masalan Keycloak:
{
"realm_access": {
"roles": ["admin", "user"]
}
}Spring default scope yoki scp claimlardan authority yasashi mumkin. Custom claimdan role olish uchun converter kerak.
@Bean
public JwtAuthenticationConverter jwtAuthenticationConverter() {
JwtGrantedAuthoritiesConverter scopesConverter =
new JwtGrantedAuthoritiesConverter();
JwtAuthenticationConverter converter =
new JwtAuthenticationConverter();
converter.setJwtGrantedAuthoritiesConverter(jwt -> {
Collection<GrantedAuthority> authorities =
new ArrayList<>(scopesConverter.convert(jwt));
Map<String, Object> realmAccess =
jwt.getClaimAsMap("realm_access");
if (realmAccess != null) {
List<String> roles =
(List<String>) realmAccess.get("roles");
if (roles != null) {
roles.stream()
.map(role -> "ROLE_" + role.toUpperCase())
.map(SimpleGrantedAuthority::new)
.forEach(authorities::add);
}
}
return authorities;
});
return converter;
}Configga ulash:
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt
.jwtAuthenticationConverter(jwtAuthenticationConverter())
)
)19. OAuth2 nima?
OAuth2 - authorization framework.
Oddiy qilib:
Bir system boshqa system nomidan cheklangan ruxsat bilan resourcega kira oladi.
Masalan:
App -> Google login -> user profile olishOAuth2'da asosiy rollar:
Role | Ma’nosi |
|---|---|
Resource Owner | User |
Client | Sizning application |
Authorization Server | Login/token beruvchi server |
Resource Server | Himoyalangan API |
Access Token | APIga kirish uchun token |
Refresh Token | Access tokenni yangilash uchun token |
20. OAuth2 Login
OAuth2 Login - social login yoki external identity provider orqali login qilish.
Masalan:
Login with Google
Login with GitHub
Login with Facebook
Login with KeycloakSpring Security’da OAuth2 Client uchun spring-boot-starter-oauth2-client starter ishlatiladi. (Home)
Dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>Security config:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http)
throws Exception {
return http
.authorizeHttpRequests(auth -> auth
.requestMatchers("/", "/login").permitAll()
.anyRequest().authenticated()
)
.oauth2Login(Customizer.withDefaults())
.build();
}21. OAuth2 client config
Google misoli:
spring:
security:
oauth2:
client:
registration:
google:
client-id: ${GOOGLE_CLIENT_ID}
client-secret: ${GOOGLE_CLIENT_SECRET}
scope:
- openid
- profile
- emailBu flow:
1. User /oauth2/authorization/google ga boradi
2. Google login oynasi ochiladi
3. User login qiladi
4. Google callback yuboradi
5. Spring Security userni authenticated qiladi22. OAuth2 Login va JWT farqi
Mavzu | OAuth2 Login | JWT API auth |
|---|---|---|
Maqsad | Userni external provider orqali login qilish | API requestni token bilan himoyalash |
Ko‘p ishlatiladi | Web app / social login | REST API / mobile / SPA |
Token kim beradi | Provider | Siz yoki Authorization Server |
Spring config |
|
|
Ko‘p production sistemalarda ikkalasi birga ishlatiladi:
Frontend OAuth2/OIDC orqali login qiladi
Authorization Server access token beradi
Backend Resource Server sifatida tokenni tekshiradi23. OAuth2 Authorization Code flow
Web app uchun eng ko‘p ishlatiladigan flow:
1. User client appga kiradi
2. Client authorization serverga redirect qiladi
3. User login qiladi
4. Authorization server code qaytaradi
5. Client code orqali token oladi
6. Access token bilan APIga murojaat qiladiSoddalashtirilgan:
Browser -> Client -> Authorization Server
Authorization Server -> code -> Client
Client -> token endpoint -> access token
Client -> Resource Server24. Access token vs Refresh token
Token | Vazifasi | Muddat |
|---|---|---|
Access token | APIga kirish | Qisqa |
Refresh token | Yangi access token olish | Uzunroq |
Tavsiya:
Access token qisqa yashasin
Refresh token xavfsiz saqlansin
Refresh token rotation bo‘lsin25. Method-level security
Endpoint darajasida security:
.requestMatchers("/api/admin/**").hasRole("ADMIN")Bu yaxshi, lekin ba’zida yetarli emas.
Masalan:
POST /orders/{id}/cancelBu endpointga kirgan user faqat o‘z orderini cancel qila olishi kerak.
Buni service methodda tekshirish yaxshi.
Spring Security method security @PreAuthorize va @PostAuthorize kabi annotationlarni application contextdagi bean methodlarida aniqlab ishlata oladi. (Home)
Config:
@Configuration
@EnableMethodSecurity
public class MethodSecurityConfig {
}26. @PreAuthorize
@Service
public class OrderService {
@PreAuthorize("hasRole('ADMIN')")
public void deleteOrder(Long orderId) {
// delete
}
}Faqat ADMIN ishlata oladi.
Permission bilan:
@PreAuthorize("hasAuthority('ORDER_CANCEL')")
public void cancelOrder(Long orderId) {
}27. Parameter asosida authorization
@PreAuthorize("#userId == authentication.principal.id")
public UserDto getProfile(Long userId) {
return userRepository.findDtoById(userId);
}Ma’nosi:
Requestdagi userId authenticated user idga teng bo‘lsa ruxsatLekin buni ishlatish uchun principal.id bo‘lishi kerak. CustomUserDetails ichida getId() bo‘lishi kerak.
public class CustomUserDetails implements UserDetails {
private final Long id;
public Long getId() {
return id;
}
}28. Custom authorization bean
Murakkab permissionni SpEL ichiga tiqib tashlash yomon.
Yomon:
@PreAuthorize("hasRole('ADMIN') or (#userId == authentication.principal.id and hasAuthority('USER_READ'))")Yaxshi:
@PreAuthorize("@userSecurity.canReadUser(#userId, authentication)")
public UserDto getUser(Long userId) {
return userRepository.findDtoById(userId);
}Authorization bean:
@Component
public class UserSecurity {
public boolean canReadUser(Long userId, Authentication authentication) {
CustomUserDetails principal =
(CustomUserDetails) authentication.getPrincipal();
boolean isAdmin = authentication.getAuthorities()
.stream()
.anyMatch(a -> a.getAuthority().equals("ROLE_ADMIN"));
return isAdmin || principal.getId().equals(userId);
}
}Bu ancha o‘qiladigan va test qilinadigan kod.
29. @PostAuthorize
@PostAuthorize method ishlagandan keyin tekshiradi.
@PostAuthorize("returnObject.ownerId == authentication.principal.id")
public DocumentDto getDocument(Long id) {
return documentRepository.findDtoById(id);
}Bu yerda avval document olinadi, keyin owner tekshiriladi.
Lekin ehtiyot bo‘ling:
DB query baribir bajariladi;
sensitive data method ichida ishlatilgan bo‘lishi mumkin;
ko‘p holatda
@PreAuthorizeyoki query-level filtering yaxshiroq.
30. @PostFilter va @PreFilter
Collection filterlash:
@PostFilter("filterObject.ownerId == authentication.principal.id")
public List<DocumentDto> getDocuments() {
return documentRepository.findAllDocuments();
}Bu ishlaydi, lekin performance uchun yomon bo‘lishi mumkin, chunki avval hamma document olinadi, keyin filterlanadi.
Yaxshiroq:
public List<DocumentDto> getMyDocuments(Long userId) {
return documentRepository.findAllByOwnerId(userId);
}Securityni DB queryda ham aks ettirish kerak.
31. SecurityContext nima?
SecurityContext - hozirgi requestdagi authentication ma’lumoti saqlanadigan joy.
Authentication authentication =
SecurityContextHolder.getContext().getAuthentication();Unda odatda:
principal
credentials
authorities
authenticated flag
detailsbo‘ladi.
Masalan:
Authentication auth =
SecurityContextHolder.getContext().getAuthentication();
String username = auth.getName();
Collection<? extends GrantedAuthority> authorities =
auth.getAuthorities();32. Controllerda current user olish
Variant 1:
@GetMapping("/me")
public UserDto me(Authentication authentication) {
return userService.getByUsername(authentication.getName());
}Variant 2:
@GetMapping("/me")
public UserDto me(@AuthenticationPrincipal CustomUserDetails userDetails) {
return userService.getById(userDetails.getId());
}Ikkinchisi ko‘pincha qulayroq.
33. Service ichida SecurityContext ishlatish
@Service
public class CurrentUserService {
public Long getCurrentUserId() {
Authentication authentication =
SecurityContextHolder.getContext().getAuthentication();
CustomUserDetails principal =
(CustomUserDetails) authentication.getPrincipal();
return principal.getId();
}
}Keyin:
@Transactional(readOnly = true)
public List<OrderDto> getMyOrders() {
Long userId = currentUserService.getCurrentUserId();
return orderRepository.findAllByUserId(userId);
}Lekin domain logicni SecurityContextga qattiq bog‘lab qo‘ymaslik kerak. Ba’zan userIdni controllerdan servicega aniq parameter qilib berish tozaroq.
34. SecurityContext propagation
Default servlet applicationda SecurityContext odatda request thread bilan bog‘langan.
Muammo:
@Async
public void sendNotification() {
Authentication auth =
SecurityContextHolder.getContext().getAuthentication();
// auth null bo‘lishi mumkin
}Sabab:
@Async boshqa thread ishlatadi
SecurityContext avtomatik o‘tmasligi mumkinYechimlar:
kerakli userIdni async methodga parameter qilib yuborish;
DelegatingSecurityContextAsyncTaskExecutorishlatish;event/message ichida userId saqlash.
Eng yaxshi amaliyot:
@Async
public void sendNotification(Long userId) {
// SecurityContextga suyanmaydi
}35. JWT va refresh token
Access token qisqa yashashi kerak:
5-15 minutRefresh token uzoqroq yashashi mumkin:
7 kun, 30 kun, policyga bog‘liqRefresh endpoint:
POST /api/auth/refreshFlow:
1. Access token tugaydi
2. Client refresh token yuboradi
3. Server refresh tokenni tekshiradi
4. Yangi access token beradiRefresh tokenni DBda saqlash yaxshi:
@Entity
public class RefreshToken {
@Id
private UUID id;
private Long userId;
private String tokenHash;
private Instant expiresAt;
private boolean revoked;
}Muhim: refresh tokenni ham plain text saqlamaslik yaxshi. Hash qilib saqlash xavfsizroq.
36. Logout JWT bilan qanday?
Stateless JWT’da server session yo‘q. Shuning uchun logout murakkabroq.
Variantlar:
Variant | Izoh |
|---|---|
Client tokenni o‘chiradi | Eng oddiy |
Short-lived access token | Xavfni kamaytiradi |
Refresh token revoke | Real logout uchun muhim |
Token blacklist | Zarurat bo‘lsa |
Token version | User password o‘zgarsa eski tokenlarni bekor qilish |
Amaliy yondashuv:
Access token qisqa yashaydi
Refresh token DBda saqlanadi
Logout refresh tokenni revoke qiladi37. CSRF JWT API’da kerakmi?
Agar siz stateless REST API ishlatsangiz va tokenni Authorization: Bearer headerda yuborsangiz, ko‘p holatda CSRF disable qilinadi:
.csrf(csrf -> csrf.disable())Lekin agar token cookie’da saqlansa, CSRF qayta muhim bo‘ladi.
Qoida:
Bearer token headerda -> CSRF odatda kerak emas
Cookie-based auth -> CSRF kerak bo‘lishi mumkin38. CORS
Frontend boshqa domainda bo‘lsa, CORS kerak.
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(List.of("https://example.com"));
config.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE"));
config.setAllowedHeaders(List.of("Authorization", "Content-Type"));
config.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source =
new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return source;
}Security config:
.cors(Customizer.withDefaults())Yomon:
config.setAllowedOrigins(List.of("*"));
config.setAllowCredentials(true);Credential bilan wildcard origin xavfli va ko‘p holatda noto‘g‘ri.
39. Exception handling
JWT invalid bo‘lsa, API chiroyli response qaytarishi kerak.
AuthenticationEntryPoint:
@Component
public class JwtAuthenticationEntryPoint
implements AuthenticationEntryPoint {
@Override
public void commence(
HttpServletRequest request,
HttpServletResponse response,
AuthenticationException authException
) throws IOException {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.setContentType("application/json");
response.getWriter().write("""
{
"error": "UNAUTHORIZED",
"message": "Authentication required"
}
""");
}
}AccessDeniedHandler:
@Component
public class CustomAccessDeniedHandler
implements AccessDeniedHandler {
@Override
public void handle(
HttpServletRequest request,
HttpServletResponse response,
AccessDeniedException accessDeniedException
) throws IOException {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.setContentType("application/json");
response.getWriter().write("""
{
"error": "FORBIDDEN",
"message": "Access denied"
}
""");
}
}Config:
.exceptionHandling(ex -> ex
.authenticationEntryPoint(jwtAuthenticationEntryPoint)
.accessDeniedHandler(customAccessDeniedHandler)
)Farqi:
Status | Qachon |
|---|---|
| Login/token yo‘q yoki invalid |
| Login bor, lekin ruxsat yo‘q |
40. Security best practice
1. Secretni code ichida saqlamang
Yomon:
private static final String SECRET = "my-secret";Yaxshi:
jwt:
secret: ${JWT_SECRET}2. Access tokenni qisqa qiling
5-15 minut3. Refresh tokenni revoke qila oling
Logout, password change, suspicious activity uchun kerak.
4. Role va permissionni ajrating
Role:
ROLE_ADMIN
ROLE_USERPermission:
ORDER_READ
ORDER_CANCEL
USER_BLOCKKatta projectlarda permission-based authorization ancha moslashuvchan.
5. Method-level securityni service layerda ishlating
Controller path security yetarli bo‘lmagan joylarda:
@PreAuthorize("@orderSecurity.canCancel(#orderId, authentication)")6. Token ichiga juda ko‘p data solmang
JWT har requestda yuboriladi. Juda katta token latency va bandwidthni oshiradi.
Token ichida minimal kerakli ma’lumot:
sub
roles/scopes
iat
exp
issuer
audience7. Sensitive endpointlarda audit qiling
Masalan:
user role changed
payment refunded
admin login
password changedBuni event/audit log bilan saqlash yaxshi.
41. Keng tarqalgan xatolar
Xato | Oqibat |
|---|---|
JWT secret code ichida | Secret leak bo‘lsa hamma token buziladi |
Access token juda uzoq | O‘g‘irlangan token uzoq ishlaydi |
Refresh token DBda boshqarilmaydi | Logout/revoke qiyin |
| Role ishlamay qoladi |
| Authorization xato |
Method security yoqilmagan |
|
| Current user null bo‘lishi mumkin |
Cookie authda CSRF disable | CSRF xavfi |
CORS | Security risk |
Tokenni localStorage’da saqlash | XSS bo‘lsa token o‘g‘irlanadi |
42. Interview savollar
Savol 1: Spring Security filter chain qanday ishlaydi?
Javob:
HTTP request controllerga yetib borishidan oldin Spring Security filterlaridan o‘tadi. Filterlar authentication, authorization, CSRF, CORS, session, JWT validation kabi ishlarni bajaradi. JWT filter tokenni tekshiradi va valid bo‘lsa
SecurityContextgaAuthenticationqo‘yadi.
Savol 2: JWT stateless authentication nima?
Javob:
Server session saqlamaydi. Har request
Authorization: Bearer <token>bilan keladi. Server token signature, expiration va claimlarni tekshiradi. Token valid bo‘lsa user authenticated hisoblanadi.
Savol 3: Resource Server nima?
Javob:
Resource Server - himoyalangan API. U access tokenni qabul qiladi, validatsiya qiladi va token claimlari asosida requestga ruxsat beradi. Spring’da bu
oauth2ResourceServer().jwt()orqali sozlanadi.
Savol 4: OAuth2 Login va Resource Server farqi nima?
Javob:
OAuth2 Login userni external provider orqali login qilish uchun ishlatiladi. Resource Server esa allaqachon berilgan access token bilan API requestlarni himoyalaydi.
Savol 5: @PreAuthorize nima uchun kerak?
Javob:
Method-level authorization uchun. Endpoint path darajasidan tashqari, service methodda role, permission yoki object ownership tekshirish imkonini beradi.
Savol 6: SecurityContext nima?
Javob:
Hozirgi requestdagi authentication ma’lumotlarini saqlaydi. Unda principal, authorities va authenticated holat bo‘ladi. Spring authorization qarorlarida shu contextdan foydalanadi.
Savol 7: JWT logout qanday qilinadi?
Javob:
Stateless JWT’da access tokenni server tomondan darhol o‘chirish qiyin. Amaliy yechim: access tokenni qisqa qilish, refresh tokenni DBda saqlash va logoutda refresh tokenni revoke qilish. Zarurat bo‘lsa token blacklist yoki token version ishlatiladi.
43. Qisqa xulosa
Mavzu | Asosiy fikr |
|---|---|
SecurityFilterChain | Security qoidalarining asosiy konfiguratsiyasi |
JWT | Stateless API authentication uchun token |
Custom JWT filter | Tokenni qo‘lda tekshirish usuli |
Resource Server | OAuth2 access tokenni tekshiradigan API |
OAuth2 Login | Google/GitHub/Keycloak kabi provider orqali login |
Method security |
|
SecurityContext | Current authentication saqlanadigan joy |
Refresh token | Access tokenni yangilash uchun |
CSRF/CORS | Frontend/API securityda muhim |
Role/authority | Authorization modelining asosi |
Eng muhim fikr:
Spring Security’da asosiy maqsad faqat login qilish emas. To‘g‘ri filter chain, token lifecycle, role/permission modeli, method-level authorization va token revoke strategiyasi bo‘lmasa, JWT borligi security bor degani emas.