
βκ°μ
Spring Security λ₯Ό μ¬μ©νμ¬ JWT ν ν° λ°©μμ μΈμ¦/μΈκ°λ₯Ό ꡬννκ²λλ©΄ μ¬μ©νκ² λλ UserDetatilsService, UserDetails κ° μμ΅λλ€. μ΄ λμ μ¬μ©ν΄ JWT ν ν° λ°©μμΌλ‘ ꡬννκ² λλ©΄ Spring Security κ° λ¬΄μ¨μΌμ νκ³ μ΄λ ν λ¬Έμ κ° λ°μνλμ§ μμ보λλ‘ νκ² μ΅λλ€
π κ°μμ μ± μ
package org.springframework.security.core.userdetails;
import java.io.Serializable;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
public interface UserDetails extends Serializable {
Collection<? extends GrantedAuthority> getAuthorities(); // κΆν
String getPassword(); // λΉλ°λ²νΈ
String getUsername(); // μλ³ μ 보
default boolean isAccountNonExpired() { // κ³μ λ§λ£ μ¬λΆ
return true;
}
default boolean isAccountNonLocked() { // κ³μ μ κΈ μ¬λΆ
return true;
}
default boolean isCredentialsNonExpired() { // λΉλ°λ²νΈ λ§λ£ μ¬λΆ
return true;
}
default boolean isEnabled() { // κ³μ νμ±ν μ¬λΆ
return true;
}
}
UserDeatils μ μν μ Spring Security μμ μ¬μ©μμ μ 보λ₯Ό λνλ΄λλ°μ μ¬μ©λ©λλ€.package org.springframework.security.core.userdetails;
public interface UserDetailsService {
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
}
Spring Security μμ μ¬μ©μ μ 보λ₯Ό λ‘λνλ μΈν°νμ΄μ€μ
λλ€.DB, μΈλΆ μμ€ν
λ±)μμ μ¬μ©μ μ 보λ₯Ό κ°μ Έμ UserDetails κ°μ²΄λ‘ λ³ννμ¬ λ°ννλ μν μ κ°μ§κ³ μμ΅λλ€.νν°λ₯Ό μ μΈνκ³ μμ λμ ꡬννκ² λλ©΄
JWTν ν° μΈμ¦/μΈκ° λ°©μμ μ¬μ©ν μ μκ²λ©λλ€.Spring Securityκ° λ§μ μ± μμ κ°μ§κ³ μΈμ¦/μΈκ°λ₯Ό λμ μννκ²λ©λλ€. νμ§λ§ μ΄ λμ μ΄μ©νκ² λλ©΄ μκΈ°λ λ¬Έμ μ μ΄ μμ΅λλ€. μ΄ λΆλΆμ λ€λ£¨κΈ° μ μ λ€μμ μ€λͺ νκ² λAuthenticationProviderμ± μμ λν΄ λ€λ£¨κ³ λμ΄κ°λλ‘ νκ² μ΅λλ€.
package org.springframework.security.authentication;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
public interface AuthenticationProvider {
Authentication authenticate(Authentication authentication) throws AuthenticationException;
boolean supports(Class<?> authentication);
}
authenticate()UserDetailsServiceλ₯Ό μ΄μ©νμ¬ μΈμ¦ λ‘μ§μ λν λΉμ¦λμ€ λ‘μ§μ ꡬνν μ μμ΅λλ€.supports()Providerκ° νΉμ Authentication νμ
μ μ§μνλμ§ μ¬λΆλ₯Ό νμΈνκ² λ©λλ€.supports λ₯Ό ν΅ν΄ ν΄λΉ AuthenticationProvider κ° μΈμ¦μ μνν΄μΌνλμ§ μ¬λΆλ₯Ό νλ¨νκ² λ©λλ€.
Spring Securityμμμ κ°μ μ± μμ μ΄ν΄λ³΄μμ΅λλ€.Spring Securityλ₯Ό μ΄μ©νκ² λλ©΄ μΈμ¦/μΈκ°λ₯Ό μννκΈ° νΈλ¦¬νκ³ κ°μ²΄μ§ν₯μ μΌλ‘ ꡬ쑰λ₯Ό μ€κ³ν μ μκ²λ©λλ€. λ°λλ‘ λ¨μ λ μ‘΄μ¬ν©λλ€.Spring Securityκ° μ΄λ―Έ λ§μκ²μ ν΄μ£Όκ³ μκΈ°λλ¬Έμ λλ²κΉ μ΄ νλ€λ€λ μ μ΄ μκΈ°κ² λ©λλ€. λν μ¬λ¬κ°μ§ λ¬Έμ μ μ΄ μκΈ°κ² λλλ° μ΄ λΆλΆμ λν΄ νλ² μμ보λλ‘ νκ² μ΅λλ€.
π λ§μ§ μλ μ·
UserDeatilsServiceλ₯Ό μ¬μ©νκ² λλ©΄ μκΈ°λ λ¬Έμ μ μ
λλ€. JWT ν ν°λ°©μμΌλ‘ μΈμ¦μ μνν λ μλ³μ μ 보λ₯Ό ID λλ Email μ μ¬μ©μ ν κ²½μ°λ₯Ό μ΄μΌκΈ°ν΄λ³΄λλ‘ νκ² μ΅λλ€.

첫λ²μ§Έλ‘λ JWT ν ν° μΈμ¦λ°©μμ μ ννμ¬ κ΅¬ννλ κ²½μ° UserDetailsService λ λ‘κ·ΈμΈ μ μ¬μ©νκ² λ©λλ€. νμ§λ§ λ‘κ·ΈμΈ ν λ ID λλ Email μ μ¬μ©νκ² λλ©΄ Naming Miss Match κ° λ°μνκ² λ©λλ€. UserDeatilsService λ username μΌλ‘ μ¬μ©μλ₯Ό μ°Ύλ κ²μ κ΄μ¬μ΄ μμ§λ§ JWT μΈμ¦/μΈκ° λ°©μμ Claim μ 보μ μ’ λ κ΄μ¬μ΄ μμ΅λλ€.
λλ²μ§Έλ‘λ JWT ν ν° μΈμ¦ λ°©μμ μ΄μ©νμ¬ κ΅¬νν κ²½μ° UserDetailsService λ λ‘κ·ΈμΈ μμλ§ μ΄μ©νκ² λ©λλ€. UserDetailsService λ Spring Security μ μ λ°μ μΈ μΈμ¦ κ³Όμ μ μν΄ μ€κ³λμμ§λ§ λ‘κ·ΈμΈ μμλ§ μ΄μ©νλκ²μΌλ‘ μ ννκ² λλ€λ©΄ μ€κ³ μλμ μ΄κΈλκ² λ©λλ€.
π§³ λΆνμν μνλ¬Ό

UserDetailsλ₯Ό μ¬μ©νκ² λλ©΄ ꡬνν΄μΌ νλ λ©μλλ€μ΄ μ¬λ¬κ° μ‘΄μ¬νκ² λ©λλ€. μ΄ λ©μλλ€μ λ¬Έμ μ μ λ€λ€λ³΄λλ‘ νκ² μ΅λλ€.

첫λ²μ§Έλ‘λ getPassword() λ©μλμ
λλ€. JWT ν ν° μΈμ¦λ°©μμλ μ¬μ©νμ§ μλ getPassword() μ
λλ€. ν΄λΉ λ©μλλ₯Ό ꡬνμ κ°μ νλλ‘ νκ³ μμΌλ ꡬννκ² λλ©΄ return κ°μλ null μ λ°ννλλ‘ κ΅¬ννκ² λλ―λ‘ μλ―Έμλ ꡬνμ νκ²λ©λλ€.

λλ²μ§Έ λν μλ―Έμλ ꡬνμ΄ λ μλ μλ λ©μλμ
λλ€. ν΄λΉ λ©μλλ€μ JWT λΆνμν μ μμ΅λλ€.
JWTλ ν ν° μ체μ λ§λ£μκ°κ³Ό κ²μ¦μ μ¬μ©νλλ° UserDetailsλ κ³μ μν μ²΄ν¬ λ©μλλ€μ κ°μ λ‘ κ΅¬νν΄μΌλ λ¬Έμ μ μ μκ³ μμ΅λλ€.
μΆκ°λ‘
SecurityContextμ μ μ₯λλAuthenticationκ°μ²΄μUserDetailsμ λ³΄μ΄ μλͺ μ£ΌκΈ° λΆμΌμΉνλ λ¬Έμ κ° λ°μν μ λ°μν μ μμ΅λλ€. λ‘κ·ΈμΈ νμ λ°μνλ μ¬μ©μ μν λ³νμ λν΄UserDetailsμ μ 보 κ°±μ μ΄ μ΄λ €μμ΄ μκΈΈ μ μμ΅λλ€.UserDeatils,UserDetailsServiceμ λν μ¬λ¬ λ¬Έμ μ μ μ΄ν΄λ³΄μμ΅λλ€. μ΄λ¬ν λ¬Έμ μ μ ν΄κ²°ν΄λ³΄λλ‘ νκ² μ΅λλ€.
π Spring Security λ΄λΆλ‘ λ€μ΄κ°κΈ°
userDetails λ₯Ό μ΄μ©νμ¬ κ΅¬ννκ² λλ©΄ AuthenticationProvider λ Authentication μ΄λΌλ μΈμ¦ κ°μ²΄λ₯Ό λ§λ€μ΄ SecurityContextHolder μ μ μ₯νκ² λ©λλ€. κ·Έλ λ€λ©΄ UserDetails μ μ¬μ©νμ§ μκ³ Authentication μ΄λΌλ μΈν°νμ΄μ€λ₯Ό μ§μ λ§λ€μ΄ SecurityContextHolder μ μ μ₯νκ² λλ©΄ Spring Securityμ μ₯μ μ κ°μ Έκ°λ©΄μ κ°μ²΄μ§ν₯μ μΌλ‘ μ½λλ₯Ό ꡬνν μ μκ² λ©λλ€. νλ¦λλ₯Ό λ¨Όμ μ€λͺ
νκΈ° μ μ κ°μ μ±
μμ κ°κ³ ꡬνν΄μΌνλ νν°μ λν΄μ μ€λͺ
νκ² μ΅λλ€.
package org.springframework.security.web.authentication;
public abstract class AbstractAuthenticationProcessingFilter extends GenericFilterBean implements ApplicationEventPublisherAware, MessageSourceAware {
public abstract Authentication attemptAuthentication
(
HttpServletRequest request,
HttpServletResponse response
) throws AuthenticationException, IOException, ServletException;
}
JWTν ν° μΈμ¦λ°©μμ μ΄μ©ν΄ μΈμ¦ νν°λ₯Ό ꡬνν λ λνμ μΈ νν°κ°UsernamePasswordAuthenticationFilterκ° μμ΅λλ€.UsernamePasswordAuthenticationFilterμ μμ ꡬν체κ°AbstractAuthenticationProcessingFilterμ λλ€. ν΄λΉ νν°λ₯Ό μμλ°μ μ‘°κΈ λCustomνκ² μΈμ¦ νν°λ₯Ό ꡬνν μ μμ΅λλ€. νμ§λ§GenericFilterBeanμ μμλ°κΈ° λλ¬Έμ νλ² μμ²μ μ€λ³΅λλ μΈμ¦μ μνν μ μλ λ¬Έμ μ μ΄ λ°μνλλ°SecurityContextλ₯Ό νμΈνμ¬ μ΄λ―Έ μΈμ¦λ μ¬μ©μμΈμ§ 체ν¬νλ λ°©λ²μ΄ μ‘΄μ¬ν©λλ§ ν΄λΉ μ£Όμ μμ λ²μ΄λ μ£Όμ μ΄κΈ°μ λ€λ£¨μ§ μλλ‘ νκ² μ΅λλ€.
μΈκ° νν°λ OncePerRequestFilter λ₯Ό μ΄μ©νμ¬ κ΅¬ννλ©΄ λ©λλ€. ν΄λΉ νν°λ₯Ό μ΄μ©νμ¬ μΈκ° νλ¦μ
URIλ₯Ό νμΈνμ¬ μΈκ°κ° νμνμ§ μ¬λΆλ₯Ό νμΈ JWT ν ν°μ ν€λ λλ μΏ ν€μμ μ 보 κ°μ Έμ€κΈ° JWT ν ν° μ ν¨μ± κ²μ¬ (JWT Provider μκ² μ±
μ μμ) SecurityContextHolder μ μ μ₯ ν΄λΉ νλ¦λλ‘ μ§ννλ€λ©΄ κ΄μ¬μ¬μ μ± μμ μ κ°μ§κ³ μλ νν°κ° λ κ²μ λλ€.
μ½λμ μΈ λΆλΆμ λ§μ§λ§ λΆλΆμμ λ€λ£¨λλ‘ νκ³ νλ¦λμ λν΄μ μ€μ μ μΌλ‘ μ€λͺ νκ² μ΅λλ€.
π¨ κ·Έλ¦ΌμΌλ‘ μ΄ν΄ν΄λ³΄κΈ°

λ‘κ·ΈμΈ μΈμ¦ νλ¦μ λ€μκ³Ό κ°μ΅λλ€.
ID μ Passwordλ₯Ό μ
λ ₯λ°μμλ AbstractAuthenticationProcessingFilter λ₯Ό ꡬνν LoginAutehnticationFilter λ‘ λμ°©νκ² λ©λλ€.LoginAuthenticationFilter λ Json μ νμ±νμ¬ μΈμ¦λμ§ μμ Authentication μ λ§λ€μ΄ AuthenticationProvider μκ² μΈμ¦μ μμν©λλ€.AuthenticationProvider λ₯Ό ꡬνν LoginAuthenticationProvider λ λΉμ¦λμ€ λ‘μ§μ λ°λΌ μΈμ¦μ μ€μ§ μ μΌλ‘ μννκ² λ©λλ€. μ¬κΈ°μλ DBλ₯Ό ν΅ν΄ μ¬μ©μ μ 보λ₯Ό νμΈνμ¬ μΈμ¦λ Authentication μ λ°κΈν©λλ€.LoginAuthenticationProvider λ‘ λΆν° μΈμ¦λ Authentication μ΄ LoginAuthenticationFilter μ λμ°©νλ©΄ successfulAuthentication μμ ν ν°μ ν€λ λλ μΏ ν€μ λ΄μμ ν΄λΌμ΄μΈνΈμκ² μλ΅νλ©΄λ©λλ€.unsuccessfulAuthentication λ₯Ό ν΅ν΄ μΈμ¦ μ€ν¨μ λν μ 보λ₯Ό ν΄λΌμ΄μΈνΈμκ² μλ΅νλ©΄ λ©λλ€.
JWT ν ν° μΈμ¦ νλ¦μ λ€μκ³Ό κ°μ΅λλ€.
JWT ν ν° μ 보λ₯Ό μμ²λ°κ² λλ©΄ OncePerRequestFilter λ₯Ό ꡬνν JwtAuthorizationFilter μ λμ°©νκ² λ©λλ€.JwtAuthorizationFilter λ JwtTokenμ μΆμΆμ JwtProvider μκ² μμνμ¬ JwtToken μ 보λ₯Ό νμΈν©λλ€.JwtToken μ 보λ₯Ό νμΈνμλ€λ©΄ Authentication μΈμ¦ κ°μ²΄λ₯Ό μμ±ν©λλ€.Authentication κ°μ²΄λ₯Ό SecurityContext μ μ μ₯νμ¬ ν΄λΌμ΄μΈνΈκ° μλΉμ€λ₯Ό μ΄μ©ν μ μλλ‘ ν©λλ€.π§βπ» μ 체μ μΈ μ½λ
@Getter
public class AuthUser {
private final Long id;
private final String email;
private final Collection<? extends GrantedAuthority> authorities;
public AuthUser(Long id, String email, Role role) {
this.id = id;
this.email = email;
this.authorities = List.of(new SimpleGrantedAuthority("ROLE_" + role));
}
public static AuthUser from(User user) {
return new AuthUser(user.getId(), user.getEmail(), user.getRole());
}
}
User μ 보λ₯Ό λ체ν κ°μ²΄μ
λλ€.package com.my.relink.config.security;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;
import java.util.Collections;
public class LoginAuthentication implements Authentication {
private final String email;
private final String password;
private boolean authenticated;
private AuthUser principal;
public LoginAuthentication(String email, String password) { // μΈμ¦ μ
this.email = email;
this.password = password;
this.authenticated = false;
}
public LoginAuthentication(AuthUser authUser) { // μΈμ¦ ν
this.email = authUser.getEmail();
this.password = null;
this.authenticated = true;
this.principal = authUser;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return principal != null ? principal.getAuthorities() : Collections.emptyList();
}
@Override
public Object getCredentials() {
return password;
}
@Override
public Object getDetails() {
return principal;
}
@Override
public Object getPrincipal() {
return authenticated ? principal : email;
}
@Override
public boolean isAuthenticated() {
return authenticated;
}
@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
this.authenticated = isAuthenticated;
}
@Override
public String getName() {
return email;
}
}
Authentication μνλ μΈμ¦ μ /μΈμ¦ ν λ κ°μ§ μνλ₯Ό κ°μ§κ³ μμ΅λλ€.package com.my.relink.config.security;
import com.my.relink.domain.user.User;
import com.my.relink.domain.user.repository.UserRepository;
import com.my.relink.ex.ErrorCode;
import com.my.relink.ex.SecurityFilterChainException;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
public class LoginAuthenticationProvider implements AuthenticationProvider {
private final UserRepository userRepository;
private final PasswordEncoder passwordEncoder;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
LoginAuthentication loginAuthentication = (LoginAuthentication) authentication;
String email = loginAuthentication.getName();
String password = (String) loginAuthentication.getCredentials();
User user = userRepository.findByEmailActiveUser(email)
.orElseThrow(() -> new SecurityFilterChainException(ErrorCode.USER_NOT_FOUND));
if (!passwordEncoder.matches(password, user.getPassword())) {
throw new SecurityFilterChainException(ErrorCode.MISS_MATCHER_PASSWORD);
}
return new LoginAuthentication(AuthUser.from(user));
}
@Override
public boolean supports(Class<?> authentication) {
return LoginAuthentication.class.isAssignableFrom(authentication);
}
}
DB μμ μ¬μ©μ μ 보λ₯Ό κ°μ Έμ μΈμ¦μ μννκ²λ©λλ€.AuthenticationProvider λ μΈμ¦μ΄ μ΄λ»κ² μνλλμ§μ λν μμΈν μ΄μΌκΈ°λ₯Ό μκ³ μμ΅λλ€.package com.my.relink.config.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.my.relink.config.security.dto.req.LoginRepDto;
import com.my.relink.config.security.dto.resp.LoginRespDto;
import com.my.relink.config.security.jwt.JwtProvider;
import com.my.relink.domain.user.User;
import com.my.relink.domain.user.repository.UserRepository;
import com.my.relink.ex.ErrorCode;
import com.my.relink.ex.SecurityFilterChainException;
import com.my.relink.util.api.ApiResult;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class LoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private final ObjectMapper objectMapper;
private final JwtProvider jwtProvider;
private final UserRepository userRepository;
public LoginAuthenticationFilter(AuthenticationManager authenticationManager, ObjectMapper objectMapper, JwtProvider jwtProvider, UserRepository userRepository) {
super(new AntPathRequestMatcher("/auth/login", HttpMethod.POST.name()));
this.setAuthenticationManager(authenticationManager);
this.objectMapper = objectMapper;
this.jwtProvider = jwtProvider;
this.userRepository = userRepository;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
try {
LoginRepDto loginRequest = objectMapper.readValue(request.getInputStream(), LoginRepDto.class);
LoginAuthentication loginAuthentication = new LoginAuthentication(
loginRequest.getEmail(),
loginRequest.getPassword()
);
return this.getAuthenticationManager().authenticate(loginAuthentication);
} catch (IOException ex) {
throw new SecurityFilterChainException(ErrorCode.JSON_PARSE_ERROR, ex);
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
String token = jwtProvider.generateToken(authResult);
User user = userRepository.findByEmail(authResult.getName())
.orElseThrow(() -> new SecurityFilterChainException(ErrorCode.USER_NOT_FOUND));
response.addHeader("Authorization", token);
response.setStatus(HttpStatus.OK.value());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.getWriter().write(objectMapper.writeValueAsString(ApiResult.success(new LoginRespDto(user))));
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
response.getWriter().write(objectMapper.writeValueAsString(ApiResult.error(ErrorCode.INVALID_CREDENTIALS)));
}
}
Authenticationμ λ§λ€μ΄ μΈμ¦μ μμνκ³ μΈμ¦μ΄ μ±κ³΅ λλ μ€ν¨μ λν μ±
μμ κ°μ§κ³ μμ΅λλ€.package com.my.relink.config.security;
import com.my.relink.config.security.jwt.JwtProvider;
import com.my.relink.ex.ErrorCode;
import com.my.relink.ex.SecurityFilterChainException;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.List;
@Component
@RequiredArgsConstructor
public class JwtAuthorizationFilter extends OncePerRequestFilter {
private final JwtProvider jwtProvider;
private final List<String> publicPaths;
private final AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
if (isPublicPath(request.getRequestURI())) {
filterChain.doFilter(request, response);
return;
}
String tokenValue = request.getHeader(JwtProvider.AUTHENTICATION_HEADER_PREFIX);
if (tokenValue == null) {
throw new SecurityFilterChainException(ErrorCode.TOKEN_NOT_FOUND);
}
String token = tokenValue.replace(JwtProvider.TOKEN_PREFIX, "");
jwtProvider.validateToken(token);
AuthUser authUser = jwtProvider.getAuthUserForToken(token);
LoginAuthentication loginAuthentication = new LoginAuthentication(authUser);
SecurityContextHolder.getContext().setAuthentication(loginAuthentication);
filterChain.doFilter(request, response);
}
private boolean isPublicPath(String uri) {
return publicPaths.stream()
.anyMatch(path -> antPathMatcher.match(path, uri));
}
}
SecurityContextHolder μ μ μ₯νλ μ±
μμ κ°μ§κ³ μμ΅λλ€.π νΊμ보기


Spring Security μ ꡬ쑰μ μΈ μ₯μ μ μ΄λ¦΄ μ μμμΌλ©° κ°μ²΄μ§ν₯μ μΌλ‘ μ€κ³ν μ μμμ΅λλ€.Spring Security λ λ§€μ° κ°λ ₯ν νλ μμν¬μ΄λ©° κ°λ°μκ° μΈμ¦/μΈκ° ꡬνμ νΈνκ² ν μ μκ² νλ λ°λ©΄ λͺ¨λ κ²μ Spring Security μ μμ‘΄νκ² λλ©΄ λλ²κΉ
κ³Ό μ¬λ¬ μν€ν
μ³μ μΈ λ¬Έμ μ μ΄ λ°μν μ μμ΅λλ€.