🗯️ 문제
User의 권한에는
Role_User
, Role_Business
이렇게 두가지 종류가 있습니다.좀더 명시적으로 권한을 관리하기 위해 enum 타입인 UserType을 생성해 사용자 권한을 관리하도록 코드를 추가했습니다.
public enum UserType { ROLE_USER, ROLE_BUSINESS, ROLE_ADMIN }
그리고 페이지별 접근 권한을 설정하는 부분에서 enum 타입을 활용하도록 작성했습니다.
@Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .addFilter(corsFilter) .httpBasic().disable() .formLogin().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() .addFilter(jwtAuthenticationFilter()) .addFilter(new JwtAuthorizationFilter(authenticationManager(),jwtAuthenticationProvider())) .authorizeRequests() .antMatchers("/api/v1/login").permitAll() .antMatchers("/api/v1/signup/**").permitAll() .antMatchers("/api/v1/favorites/**") .access(MessageFormat.format("hasRole('{0}') or hasRole('{1}')", UserType.ROLE_USER.name(), UserType.ROLE_ADMIN.name())) .anyRequest().permitAll(); }
이렇게 등록할 경우 해당 api 주소에서 정상적으로 인증되지 않고, 403 Forbidden 에러가 발생하게 됩니다.

🔥 해결 방법
enum타입을 antMatchers에서 사용할 경우 인식을 못하는 문제가 있습니다.
enum 타입을 사용하기 위해서는
.antMatchers()
가 아닌 .hasRole()
또는 .hasAnyRole()
메서드를 사용해야 합니다.@Override protected void configure(HttpSecurity http) throws Exception { http .csrf().disable() .addFilter(corsFilter) .httpBasic().disable() .formLogin().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() .addFilter(jwtAuthenticationFilter()) .addFilter(new JwtAuthorizationFilter(authenticationManager(),jwtAuthenticationProvider())) .authorizeRequests() .antMatchers("/api/v1/login").permitAll() .antMatchers("/api/v1/signup/**").permitAll() .antMatchers("/api/v1/favorites/**") .hasAnyRole(UserType.ROLE_USER.name(), UserType.ROLE_BUSINESS.name()) .anyRequest().permitAll(); }
Spring security 문서 설명에 따르면,
hasRole, hasAnyRole과 access는 약간의 차이가 있습니다.
hasRole([role])
: Returnstrue
if the current principal has the specified role. By default if the supplied role does not start with 'ROLE_' it will be added. This can be customized by modifying thedefaultRolePrefix
onDefaultWebSecurityExpressionHandler
.
hasAnyRole([role1,role2])
: Returnstrue
if the current principal has any of the supplied roles (given as a comma-separated list of strings). By default if the supplied role does not start with 'ROLE_' it will be added. This can be customized by modifying thedefaultRolePrefix
onDefaultWebSecurityExpressionHandler
.
access
: Lists the access attributes which will be stored in theFilterInvocationSecurityMetadataSource
for the defined URL pattern/method combination. This should be a comma-separated list of the security configuration attributes (such as role names).
정리하자면,
hasRole()
, hasAnyRole()
은 로그인한 사용자가 특정한 역할을 가지고 있을 경우 true를 반환하고,access()
는 정의된 URL 패턴과 메서드조합에 대해서 FilterInvocationSecurityMetadataSource에 저장되는 접근 특성을 입력합니다.현재는 hasRole()만 사용하지만, 확장성을 고려하면 앞으로 다른 접근특성이 추가될 수 있다는 점을 고려해 access()를 사용하는 것이 통일성 있다고 생각했고, security 권한설정 부분에 한해서 UserType을 사용하지 않도록 했습니다.