Security 적용

최종윤·2023년 1월 27일
0

스프링

목록 보기
4/6

https://www.baeldung.com/spring-security-login 참고

프로젝트 진행시 생기는 궁금증을 알아보기 쉽게 메모해놔야겠다.
다른 것 공부하다가 다시 하려니까 다시 알아봐야하네..
목차 작성하고 이유와 무엇 설명

OAuth

카카오 로그인을 구현하면서 카카오 문서와 구글링을 통해 자료를 탐색했는데, 카카오 문서에서 REST API 구현방법을 확인하여 구현하는 과정에서 로그인이 이루어지는 과정은 다음과 같다는 것을 학습했다.

클라이언트에서 카카오 서버의 URL로 인가 코드 요청 ->
카카오 서버로부터 인가 코드를 받는다 ->
코드를 가지고 토큰 요청 ->
토큰을 받는다. ->
토큰을 가지고 카카오 서버에서 사용자 정보 불러오기(email, nickname등) ->
여기까지 OAuth의
불러온 정보를 가지고 회원가입한다. or 토큰을 반환(로그인 처리) ->

OAuth없이 Security로 구현

OAuth를 사용하는 것과 그냥 Security의 로그인 동작과정 차이는 어떻게 다를까? Coupang은 소셜로그인을 사용하지않고 자체 로그인을 사용하더라

  1. Security의존성을 추가한다
    설정을 따로 하지 않은 경우
    /login URL로 요청하면 자동으로 구현된 화면을 보여준다.

❓인증과 인가는 무엇인가?
인증은 어떤 사용자가 사용중인지 확인하는 행위
인가는 요청한 사용자가 권한을 갖고있는지 확인하는 행위

InMemoryUserDetailsManager

이 클래스를 통해 모든 영속성 메커니즘이 구현되지 않았을 때 빠른 prototyping에 유용합니다.
이 Bean 클래스를 등록하고 안에 UserDetails 객체를 생성해놓아 임의로 User를 생성할 수 있습니다.
@Bean
public InMemoryUserDetailsManager UserDetailsService(){
UserDetails user1 = User.withUsername("user1").password(passwordEncoder.encode("user1Pass")).roles("USER").build();
}

PasswordEncoder

password Encoder를 정의해야하는데 Configuration class에 Bean class로 등록하면 됩니다.BcryptPasswordEncoder를 사용가능합니다.
@Bean
public PasswordEncoder encoder(){
return new BcryptPasswordEncoder();
}

request 권한 검증 설정

특정 범위 권한에서 적용하는 것을 먼저 적용하고,
general한 권한에 적용할 권한 검증 방식을 나중에 적용합니다.

anonymous가 login 접근가능하게 해서 user가 authenticated될수 있게한다. login다음 authenticated

http.csrf().disable(). csrf를 disable하고
authorizeRequest() request 권한을 확인한다
.antMatchers("/admin/*") 경로는 다음과 같다.
.hasRole("ADMIN") 앞의 경로가 해당 권한을 갖으면 응답,아님 거절
.antMatchers("/anonymous
")
.anonymous() anonoymous?요청은 익명이면 응답 아님 거절?
.antMatchers("/login")
.permitall() login과 그 하위 경로는 permitall
.anyReqeust() 다른 모든 Request들이
.authenticated() 인증상태여야 응답 아니면 거절

http.formLogin() 설정

Spring Login form은 username, password, submit button을 갖는다.

SecurityFilterChain에서 login form에 대해 적용할 Security는 다음과 같다.
요청 URL .loginProcessingURL("").
Spring이 인증처리를 위해 POST요청을 보내는 URL입니다.
default URL값은 /login입니다.
❓요청 보내면 응답으로 뭐가 오는 거지?
❗로그인 성공하면 web 앱의 root로 redirect됩니다.
root경로를 override하기 위해 defaultSuccessUrl()메서드를 사용하면 됩니다.
❗로그인 실패하면 /login?error 경로를 기본 값으로 Spring Security가 자동 생성한 Login Failure Page로 redirect됩니다.
http.formLogin().failureUrl()을 사용해 redirect url을 ovveride할 수 있습니다.

화면(html),
성공했을 때 이동할 URL, 실패했을 때 이동할 URL을 설정할 수 있다.

설정하고 http.build()를 return하면 security가 적용된다.
적용된다는것은? 인증되지 않은 사용자의 요청을 거절할 수 있다.
원래 받아야할 화면을 응답하지 않고, 403에러를 응답으로 보낸다.

httpBasic()

SecurityFilterChain에 Basic Authentication을 추가하기 위해
사용합니다
http.authorizeRequests().
httpBasic().authenticationEntryPoint(authenticationEntryPoint);

인증 과정

요청 - 인증 요청 - 인증 - 성공

ID/PW등 인증정보(credentials)를 보내지 않고 요청을 보내면 서버는 401에러 unauthorized 응답을 WWW-Authenticate 헤더와 함께 응답합니다.
(InMemoryManager에서 정의한 User의 name/pw)ID/PW를 같이 요청하면 응답을 받는데 성공합니다.
❓AuthenticationManagerBuilder 나 manager bean class를 등록하지 않고 권한이 정의된 user를 생성하려면 어떻게 해야할까?
수동으로 말고 데이터베이서에 저장한 유저를 인증에 사용하려면?

basic authentication 기본인증 은 무엇일까?

http공부하면서 인증방식중에 하나인 것으로 봤던 기억이 나는 것 같다.
기본 인증은 ID/PW가 평문Plain Text로 네트워크를 통해 전달되기 때문에
안전하지 않습니다.
기본인증 방식은 간편하지만 https/TLS등 같은 다른 방법과 같이 쓰이지 않으면 보안에 취약합니다. 민감한 정보를 보호하는데 단독으로 사용되어서는 안 됩니다.

realm

서버가 사용자에게 인증을 요청할 때 realm지시자가 적힌 WWW-Authenticate 헤더를 전송합니다.
웹 서버는 보안문서를 realm(보안영역)그룹으로 나눕니다.
realm은 각 realm마다 다른 권한을 요구합니다.
realm에 따라 웹 서버에 요청할 수 있는 한계점이 다릅니다.
WWW-Authenticate: Basic realm: "Control"
Control에 해당하는 정보만 열람 가능합니다.

EntryPoint?

기본값으로 BasicAuthenticationEntryPoint는 401 UnAuthorized error를 한 페이지로 응답합니다. 이런 error를 HTML로 표현하는 것은 브라우저에서는 잘 렌더링되지만 ,
REST API로 구현해야하는 경우 (JSON 형태로 데이터 응답을 전달해야 하는 경우 ) 다른 방식으로 응답해야합니다.
namespace는 이 요구사항을 위해 유연한 대응을 제공합니다.
이를 해결하기 위해 EntryPoint를 override합니다.

BasicAuthenticationEntryPoint class를 extends하는 클래스를 생성하고 @Component를 붙여 bean class로 등록하도록 합니다.

@Override
commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx){
response.addHeader("WWW-Authenticate","Realm:"+

OAuth Client vs 직접 구현

Security에 OAuth Client 의존성을 사용하면
Controller와 Service코드를 작성하지 않고,
제공하는 만들어진 클래스를 사용하여 인가코드를 받고 토큰 요청하고 사용자 정보 불러오는 과정까지 자동으로 구현이 가능한 듯 하다.

이 불러온 정보를 통해 회원가입 여부를 확인하고
로그인을 합니다.

    // 일치하는 snsId가 없을 시 회원가입(해당 snsId로 kakaologin을 했을때 null반환하면 회원가입)


    // 동의항목 끝나고 인가코드전달하고난 후 =>  바로 정보 불러오기 =>
//      !!!  토큰을 가지고 회원가입 화면 띄우기 전에
//         가입된 member를 snsId로 조회하여  가입여부를 확인 후 전달하여 회원가입 화면을 띄울지 바로 넘어갈지

    // 없다면 false을 전달하고 있으면 정보 전달하여 정보와 입력한 것으로 회원가입 요청보내달라하기
    // 아닌가 redirect url로 인가코드 보내고 난다음 프론트는 무슨 화면으로 있는 거지 ? 보낸 다음 회원가입 화면을 띄우는건가?
    // 일치하는 snsId가 있으면 멤버객체에 담음
    //토큰도 전달해야지 signup 다시 요처할떄 토큰 받아서 정보 저장할듯한데 .. 회원원정보 불러올떄  토큰 쓰니까
    //토큰 저장해야하나? 저장할떄만 씀?

    //1. 회원가입과 로그인을 나눈다.
    // 회원가입
    // 회원가입 누르면 카카오 로그인해서 받은 토큰으로 사용자 정보 불러오기 이미 가입했는지 확인해 중복가입 막기
    // 회원가입 했으면 토큰 반환(로그인 성공), 안 했으면 사용자 정보 반환, 똑같네? 안했는지 어떻게 알아?
    //사용자 정보를 보내줘서 다시 같이 나한테 보내줘야 코드랑 토큰은 쓰고 없어져버리니까 다시 쓰지

    // 클라이언트는  사용자 정보와 닉네임,추가정보를 가지고 다시 요청
    // 닉네임과 추가정보 가지고 요청오면  회원가입한다(DB에 저장) 그리고 토큰을 반환(로그인 성공)


    // 로그인
    // 로그인을 누르면 토큰으로 사용자정보 불러오고 DB에 있는지 확인하고
    // 없으면 로그인Exception 처리한다. 있으면 로그인 성공 토큰 반환

    // 그냥 정보는 나중에 입력하면 안 되나?
    
profile
https://github.com/jyzayu

0개의 댓글