JAN's History

JWT를 구현할 때 권한관리를 하기 위해 Authentication을 return 해야하는 이유 본문

JWT

JWT를 구현할 때 권한관리를 하기 위해 Authentication을 return 해야하는 이유

JANNNNNN 2024. 7. 8. 14:37

JWT를 공부하던 도중 Authentication 객체를 반환하는 이유가 권한 관리를 위해서라는 말이 이해가 가지 않아 정리해보기로 결심!

 

일단 저의 코드 구조를 대략적으로 적어보겠습니다.

User

   @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    private String username;
    private String password;
    private String roles; //USER, ADMIN

    //하나의 유저당 role이 2개 이상일 경우를 대비해서!
    public List<String> getRoleList(){
        if(this.roles.length() > 0){
            return Arrays.asList(this.roles.split(","));
        }
        return new ArrayList<>();
    }

➡️roles가 있으므로, 권한이 필요함!

Security Config

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/public/**").permitAll()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
                .and()
            .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
            .logout()
                .logoutUrl("/logout")
                .permitAll();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }
}

 

  • configure(HttpSecurity http): HTTP 요청에 대한 인가 설정을 구성합니다. 예를 들어, "/admin/**" 경로는 ADMIN 역할을 가진 사용자만 접근할 수 있도록 설정합니다.
  • configure(AuthenticationManagerBuilder auth): 사용자 인증을 설정합니다. userDetailsService를 통해 사용자 정보를 조회하고, passwordEncoder()를 통해 비밀번호를 암호화하여 인증을 수행합니다.

 

 

Controller

@RestController
@RequestMapping("/api")
public class ApiController {

    @GetMapping("/public")
    public String publicEndpoint() {
        return "Public endpoint accessed";
    }

    @GetMapping("/admin")
    public String adminEndpoint() {
        return "Admin endpoint accessed";
    }

    @GetMapping("/user")
    public String userEndpoint() {
        return "User endpoint accessed";
    }
}

➡️/public은 모든 사용자에게 허용되고, /admin은 ADMIN 권한을 가진 사용자에게만 허용됩니다. /user는 인증된 모든 사용자에게 허용됩니다.

동작 방식 요약

  • 사용자가 로그인을 하면 PrincipalDetailsService에서 사용자 정보와 권한을 조회해 UserDetails 객체를 생성합니다
  • Spring Security는 UserDetails 객체를 Authentication 객체에 저장해 Security Context에 저장합니다.
  • HTTP 요청이 들어올 때마다, Authentication 객체를 통해 사용자 권한을 확인하고 접근 제어를 수행합니다 !

Authentication 객체를 통해 사용자 권한을 확인하는 과정

1. 사용자 로그인

  • 사용자가 아이디와 비밀번호로 로그인을 수행합니다.
  • Spring Security는 UsernamePasswordAuthenticationToken을 생성해 사용자의 아이디와 비밀번호를 포함시킨 후 AuthenticationManager를 통해 인증을 시도합니다.
  • AuthenticationManager는 AuthenticationProvider를 사용해 실제 인증을 수행하고, 성공하면 Authentication 객체를 반환합니다.

2. HTTP 요청 처리

  • 사용자가 로그인 후, 다시 HTTP 요청을 보냅니다.
    • 예를 들어 'api/admin' 엔드 포인트에 접근하는 것처럼!
  • Spring Security는 SecurityContext에서 현재 사용자의 Authentication 객체를 가져옵니다.
  • 해당 Authentication 객체를 통해 사용자의 권한을 확인합니다
    • 예를 들어 hasRole("Admin")을 통해!
  • 사용자가 권한을 가지고 있으면 요청을 허용하고 그렇지 않으면 접근을 거부합니다.