ewhk9887/korean_code_reviews_from_github huggingface dataset:
@@ -0,0 +1,88 @@
+import styled from "styled-components";
+
+export const ReviewSectionName = styled.h2`
+
+`;
+
+export const ReviewFormArea = styled.div`
+    position: absolute;
+    width: 918px;
+    height: 240px;
+    padding: 14px 23px;
+    background-color: #00462A;
+    border-radius: 20px;
+    flex-direction: column;
+    gap: 15px;
+`;
+
+export const Conditions = styled.div`
+    display: flex;
+    flex-direction: row;
+    align-items: center;
+    gap: 15px;
+`;
+
+export const IfReward = styled.label`
+    display: flex;
+    align-items: center;
+    gap: 4px;
+    flex-direction: row-reverse;
+    color: #FFFFFF;
+    font-size: 14px;
+`;
+
+export const Checkbox = styled.input`
+    width: 16px;
+    height: 16px;
+    cursor: pointer;
+    border-radius: 20px;
+`;
+
+export const Number = styled.input`
+    margin-left: 20px;
+    border-radius: 20px;
+    padding: 8px;
+    border: none;
+    width: 100px;
+`;
+
+export const DropDown = styled.select`
+    border-radius: 20px;
+    padding: 8px;
+    border: none;
+    width: 100px;
+    cursor: pointer;
+    appearance: none;
+
+    option{
+        font-size: 14px;
+        color: #333333; 
+    }
+`;
+
+export const ReviewContent = styled.div`  
+    margin-top: 15px;
+    width: 884px;
+    height: 99px;
+
+    textarea {
+        width: 100%;
+        height: 100%;
+        resize: none;
+        overflow: auto;
+        border-radius: 18px;
+        padding: 12px 17px;
+        border: none;
+        font-size: 14px;
+    }
+`;
+
+export const Button = styled.button`
+    margin-top: 40px;
+    outline: none;
+    border: none;
+    width: 923px;
+    height: 50px;
+    background-color: #F0F7F4;
+    border-radius: 20px;
+`;
\ No newline at end of file

리뷰: styled-component 깔끔하게 잘 쓰신 것 같아요! 수고 많으셨습니다~
@@ -0,0 +1,40 @@
+package nextstep.security.authentication;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import nextstep.security.core.Authentication;
+import nextstep.security.core.context.SecurityContextHolder;
+import nextstep.security.exception.AuthenticationException;
+import nextstep.security.web.authentication.AuthenticationConverter;
+import nextstep.security.web.authentication.BasicAuthenticationConverter;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+public class BasicAuthenticationFilter extends OncePerRequestFilter {
+
+    private final AuthenticationManager authenticationManager;
+    private final AuthenticationConverter authenticationConverter = new BasicAuthenticationConverter();
+
+    public BasicAuthenticationFilter(AuthenticationManager authenticationManager) {
+        this.authenticationManager = authenticationManager;
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
+            throws IOException, ServletException {
+        try {
+            Authentication authRequest = authenticationConverter.convert(request);
+
+            if (authRequest != null) {
+                Authentication authResult = authenticationManager.authenticate(authRequest);
+                SecurityContextHolder.getContext().setAuthentication(authResult);
+            }
+
+            filterChain.doFilter(request, response);
+        } catch (AuthenticationException e) {
+            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        }
+    }
+}

리뷰: BasicAuthenticationFilter 필터를 생성할 때 UserDetailsService 대신 AuthenticationManager를 주입 받으면 어떨까요?
@@ -0,0 +1,35 @@
+package nextstep.security.authentication;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Map;
+import nextstep.security.core.Authentication;
+import nextstep.security.exception.AuthenticationException;
+import nextstep.security.exception.AuthenticationServiceException;
+import nextstep.security.web.authentication.AbstractAuthenticationProcessingFilter;
+
+public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
+    private static final String DEFAULT_REQUEST_URI = "/login";
+
+    public UsernamePasswordAuthenticationFilter(AuthenticationManager authenticationManager) {
+        super(DEFAULT_REQUEST_URI, authenticationManager);
+    }
+
+    @Override
+    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
+            throws AuthenticationException, IOException, ServletException {
+        if (!"POST".equalsIgnoreCase(request.getMethod())) {
+            throw new AuthenticationServiceException();
+        }
+        Map<String, String[]> parameterMap = request.getParameterMap();
+        String username = parameterMap.get("username")[0];
+        String password = parameterMap.get("password")[0];
+
+        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
+                username, password, false);
+
+        return this.getAuthenticationManager().authenticate(authRequest);
+    }
+}

리뷰: 여기도 마찬가지로 UserDetailsService 대신 AuthenticationManager를 주입 받으면 어떨까요?
@@ -0,0 +1,40 @@
+package nextstep.security.authentication;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import nextstep.security.core.Authentication;
+import nextstep.security.core.context.SecurityContextHolder;
+import nextstep.security.exception.AuthenticationException;
+import nextstep.security.web.authentication.AuthenticationConverter;
+import nextstep.security.web.authentication.BasicAuthenticationConverter;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+public class BasicAuthenticationFilter extends OncePerRequestFilter {
+
+    private final AuthenticationManager authenticationManager;
+    private final AuthenticationConverter authenticationConverter = new BasicAuthenticationConverter();
+
+    public BasicAuthenticationFilter(AuthenticationManager authenticationManager) {
+        this.authenticationManager = authenticationManager;
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
+            throws IOException, ServletException {
+        try {
+            Authentication authRequest = authenticationConverter.convert(request);
+
+            if (authRequest != null) {
+                Authentication authResult = authenticationManager.authenticate(authRequest);
+                SecurityContextHolder.getContext().setAuthentication(authResult);
+            }
+
+            filterChain.doFilter(request, response);
+        } catch (AuthenticationException e) {
+            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        }
+    }
+}

리뷰: Authentication 생성의 책임을 별도의 클래스로 분리해보면 어떨까요?
@@ -0,0 +1,40 @@
+package nextstep.security.authentication;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import nextstep.security.core.Authentication;
+import nextstep.security.core.context.SecurityContextHolder;
+import nextstep.security.exception.AuthenticationException;
+import nextstep.security.web.authentication.AuthenticationConverter;
+import nextstep.security.web.authentication.BasicAuthenticationConverter;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+public class BasicAuthenticationFilter extends OncePerRequestFilter {
+
+    private final AuthenticationManager authenticationManager;
+    private final AuthenticationConverter authenticationConverter = new BasicAuthenticationConverter();
+
+    public BasicAuthenticationFilter(AuthenticationManager authenticationManager) {
+        this.authenticationManager = authenticationManager;
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
+            throws IOException, ServletException {
+        try {
+            Authentication authRequest = authenticationConverter.convert(request);
+
+            if (authRequest != null) {
+                Authentication authResult = authenticationManager.authenticate(authRequest);
+                SecurityContextHolder.getContext().setAuthentication(authResult);
+            }
+
+            filterChain.doFilter(request, response);
+        } catch (AuthenticationException e) {
+            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        }
+    }
+}

리뷰: convert 메서드는 Token으로 변환해주는 역할만 하면 어떨까요?
@@ -0,0 +1,35 @@
+package nextstep.security.authentication;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Map;
+import nextstep.security.core.Authentication;
+import nextstep.security.exception.AuthenticationException;
+import nextstep.security.exception.AuthenticationServiceException;
+import nextstep.security.web.authentication.AbstractAuthenticationProcessingFilter;
+
+public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
+    private static final String DEFAULT_REQUEST_URI = "/login";
+
+    public UsernamePasswordAuthenticationFilter(AuthenticationManager authenticationManager) {
+        super(DEFAULT_REQUEST_URI, authenticationManager);
+    }
+
+    @Override
+    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
+            throws AuthenticationException, IOException, ServletException {
+        if (!"POST".equalsIgnoreCase(request.getMethod())) {
+            throw new AuthenticationServiceException();
+        }
+        Map<String, String[]> parameterMap = request.getParameterMap();
+        String username = parameterMap.get("username")[0];
+        String password = parameterMap.get("password")[0];
+
+        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
+                username, password, false);
+
+        return this.getAuthenticationManager().authenticate(authRequest);
+    }
+}

리뷰: 시큐리티의 실제 코드를 살펴보면 인증 필터에서 중복되는 부분을 AbstractAuthenticationProcessingFilter로 분리되어있습니다! UsernamePasswordAuthenticationFilter에서 해당 부분을 분리해보는 시도를 해보시면 어떨까요?
필수 요구사항은 아니지만 빠르게 미션을 잘 해주셨고 선택 요구사항으로 3주차 미션 수행에 도움이 될 것 같아서 제안드려요~
@@ -0,0 +1,40 @@
+package nextstep.security.authentication;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import nextstep.security.core.Authentication;
+import nextstep.security.core.context.SecurityContextHolder;
+import nextstep.security.exception.AuthenticationException;
+import nextstep.security.web.authentication.AuthenticationConverter;
+import nextstep.security.web.authentication.BasicAuthenticationConverter;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+public class BasicAuthenticationFilter extends OncePerRequestFilter {
+
+    private final AuthenticationManager authenticationManager;
+    private final AuthenticationConverter authenticationConverter = new BasicAuthenticationConverter();
+
+    public BasicAuthenticationFilter(AuthenticationManager authenticationManager) {
+        this.authenticationManager = authenticationManager;
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
+            throws IOException, ServletException {
+        try {
+            Authentication authRequest = authenticationConverter.convert(request);
+
+            if (authRequest != null) {
+                Authentication authResult = authenticationManager.authenticate(authRequest);
+                SecurityContextHolder.getContext().setAuthentication(authResult);
+            }
+
+            filterChain.doFilter(request, response);
+        } catch (AuthenticationException e) {
+            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        }
+    }
+}

리뷰: 기존 구조에서 계속 발전시켜 나가다 보니 미처 신경쓰지 못한것 같습니다 😂
구체가 아닌 추상에 의존해야 한다는걸 상기시켜주셔서 감사합니다 👍
@@ -0,0 +1,35 @@
+package nextstep.security.authentication;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Map;
+import nextstep.security.core.Authentication;
+import nextstep.security.exception.AuthenticationException;
+import nextstep.security.exception.AuthenticationServiceException;
+import nextstep.security.web.authentication.AbstractAuthenticationProcessingFilter;
+
+public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
+    private static final String DEFAULT_REQUEST_URI = "/login";
+
+    public UsernamePasswordAuthenticationFilter(AuthenticationManager authenticationManager) {
+        super(DEFAULT_REQUEST_URI, authenticationManager);
+    }
+
+    @Override
+    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
+            throws AuthenticationException, IOException, ServletException {
+        if (!"POST".equalsIgnoreCase(request.getMethod())) {
+            throw new AuthenticationServiceException();
+        }
+        Map<String, String[]> parameterMap = request.getParameterMap();
+        String username = parameterMap.get("username")[0];
+        String password = parameterMap.get("password")[0];
+
+        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
+                username, password, false);
+
+        return this.getAuthenticationManager().authenticate(authRequest);
+    }
+}

리뷰: 마찬가지로 [fa5f619](https://github.com/next-step/spring-security-authentication/pull/33/commits/fa5f61942bfba0e2f794bb43c5b86af416c679b8) 커밋으로 반영했습니다!
@@ -0,0 +1,40 @@
+package nextstep.security.authentication;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import nextstep.security.core.Authentication;
+import nextstep.security.core.context.SecurityContextHolder;
+import nextstep.security.exception.AuthenticationException;
+import nextstep.security.web.authentication.AuthenticationConverter;
+import nextstep.security.web.authentication.BasicAuthenticationConverter;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+public class BasicAuthenticationFilter extends OncePerRequestFilter {
+
+    private final AuthenticationManager authenticationManager;
+    private final AuthenticationConverter authenticationConverter = new BasicAuthenticationConverter();
+
+    public BasicAuthenticationFilter(AuthenticationManager authenticationManager) {
+        this.authenticationManager = authenticationManager;
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
+            throws IOException, ServletException {
+        try {
+            Authentication authRequest = authenticationConverter.convert(request);
+
+            if (authRequest != null) {
+                Authentication authResult = authenticationManager.authenticate(authRequest);
+                SecurityContextHolder.getContext().setAuthentication(authResult);
+            }
+
+            filterChain.doFilter(request, response);
+        } catch (AuthenticationException e) {
+            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        }
+    }
+}

리뷰: [81fa490](https://github.com/next-step/spring-security-authentication/pull/33/commits/81fa490d0c5ef702821a1b226a17c3363bb5131a)로 반영했습니다!
@@ -0,0 +1,40 @@
+package nextstep.security.authentication;
+
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import nextstep.security.core.Authentication;
+import nextstep.security.core.context.SecurityContextHolder;
+import nextstep.security.exception.AuthenticationException;
+import nextstep.security.web.authentication.AuthenticationConverter;
+import nextstep.security.web.authentication.BasicAuthenticationConverter;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+public class BasicAuthenticationFilter extends OncePerRequestFilter {
+
+    private final AuthenticationManager authenticationManager;
+    private final AuthenticationConverter authenticationConverter = new BasicAuthenticationConverter();
+
+    public BasicAuthenticationFilter(AuthenticationManager authenticationManager) {
+        this.authenticationManager = authenticationManager;
+    }
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
+            throws IOException, ServletException {
+        try {
+            Authentication authRequest = authenticationConverter.convert(request);
+
+            if (authRequest != null) {
+                Authentication authResult = authenticationManager.authenticate(authRequest);
+                SecurityContextHolder.getContext().setAuthentication(authResult);
+            }
+
+            filterChain.doFilter(request, response);
+        } catch (AuthenticationException e) {
+            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
+        }
+    }
+}

리뷰: DRY 위반도 겸하고 있었네요! 
클래스 분리하고 보니 기존 메서드에 책임이 과도했고, 필요치 않은 더블체크가 들어갔다는게 바로 확인되어서 좋았습니다!
@@ -0,0 +1,35 @@
+package nextstep.security.authentication;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Map;
+import nextstep.security.core.Authentication;
+import nextstep.security.exception.AuthenticationException;
+import nextstep.security.exception.AuthenticationServiceException;
+import nextstep.security.web.authentication.AbstractAuthenticationProcessingFilter;
+
+public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
+    private static final String DEFAULT_REQUEST_URI = "/login";
+
+    public UsernamePasswordAuthenticationFilter(AuthenticationManager authenticationManager) {
+        super(DEFAULT_REQUEST_URI, authenticationManager);
+    }
+
+    @Override
+    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
+            throws AuthenticationException, IOException, ServletException {
+        if (!"POST".equalsIgnoreCase(request.getMethod())) {
+            throw new AuthenticationServiceException();
+        }
+        Map<String, String[]> parameterMap = request.getParameterMap();
+        String username = parameterMap.get("username")[0];
+        String password = parameterMap.get("password")[0];
+
+        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
+                username, password, false);
+
+        return this.getAuthenticationManager().authenticate(authRequest);
+    }
+}

리뷰: [dbde31c](https://github.com/next-step/spring-security-authentication/pull/33/commits/dbde31cb10aee34fe4e1c767064389589b2fa2ba)로 시도해 보았습니다!

실제 코드를 분석하면서 흥미로웠던점은
SecurityContextRepository.saveContext() 호출을
SecurityContextHolderFilter가 아닌 AbstractAuthenticationProcessingFilter에서 해주고 있다는 점이었는데요.

![image](https://github.com/user-attachments/assets/7fac5996-fe6a-443b-a8d0-1b06fb11d3c5)

그렇게 되면 위에 그림상 3번 플로우는 안맞는거 아닌가? 이해를 돕기 위한 그림일까? 이런 저런 생각들을 하면서  되게 재미있게 본 것 같습니다 ㅎㅎㅎ..
제가 잘못 이해한거라면 짚어주시면 감사하겠습니다!

또한 AbstractAuthenticationProcessingFilter 구현하면서
RequestMatcher이나, strategy 디자인 패턴으로 구현해야 하는 부분은
현 시점에서는 오버엔지니어링이라고 판단해 넣지 않았습니다! 
아마 이런 부분까지는 바라지 않으셨을..것 같아서요! 😂
@@ -0,0 +1,35 @@
+package nextstep.security.authentication;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Map;
+import nextstep.security.core.Authentication;
+import nextstep.security.exception.AuthenticationException;
+import nextstep.security.exception.AuthenticationServiceException;
+import nextstep.security.web.authentication.AbstractAuthenticationProcessingFilter;
+
+public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
+    private static final String DEFAULT_REQUEST_URI = "/login";
+
+    public UsernamePasswordAuthenticationFilter(AuthenticationManager authenticationManager) {
+        super(DEFAULT_REQUEST_URI, authenticationManager);
+    }
+
+    @Override
+    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
+            throws AuthenticationException, IOException, ServletException {
+        if (!"POST".equalsIgnoreCase(request.getMethod())) {
+            throw new AuthenticationServiceException();
+        }
+        Map<String, String[]> parameterMap = request.getParameterMap();
+        String username = parameterMap.get("username")[0];
+        String password = parameterMap.get("password")[0];
+
+        UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
+                username, password, false);
+
+        return this.getAuthenticationManager().authenticate(authRequest);
+    }
+}

리뷰: 우선 준형님께서 코드로 확인한 부분이 맞습니다!
제가 강의에서 SecurityContextPersistenceFilter와 SecurityContextHolderFilter는 같고 버전의 차이라고만 말씀드렸는데
같은 역할을 한다는 관점에서 같다고 말씀드렸고 사실 다르게 동작하는 부분이 있습니다.

[SecurityContextPersistenceFilter](https://docs.spring.io/spring-security/reference/servlet/authentication/persistence.html#securitycontextpersistencefilter)의 설명에 보면 repository에 저장하는 부분까지 포함이지만 [SecurityContextHolderFilter](https://docs.spring.io/spring-security/reference/servlet/authentication/persistence.html#securitycontextholderfilter)의 설명을 보면 저장하는 부분을 포함하고 있지 않습니다.