Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[임원선]프리코스 제출합니다. #22

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions src/main/java/nextstep/app/SecurityConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package nextstep.app;

import nextstep.app.domain.Member;
import nextstep.app.domain.MemberRepository;
import nextstep.security.authentication.AuthenticationException;
import nextstep.security.authentication.BasicAuthenticationFilter;
import nextstep.security.authentication.UsernamePasswordAuthenticationFilter;
import nextstep.security.userdetails.UserDetails;
import nextstep.security.userdetails.UserDetailsService;
import nextstep.security.config.*;
import nextstep.security.context.SecurityContextHolderFilter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

@Configuration
public class SecurityConfig {

private final MemberRepository memberRepository;
public SecurityConfig(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}

@Bean
public DelegatingFilterProxy delegatingFilterProxy() {
return new DelegatingFilterProxy(filterChainProxy(List.of(securityFilterChain())));
}

@Bean
public FilterChainProxy filterChainProxy(List<SecurityFilterChain> securityFilterChains) {
return new FilterChainProxy(securityFilterChains);
}


@Bean
public SecurityFilterChain securityFilterChain() {
return new DefaultSecurityFilterChain(
List.of(

new SecurityContextHolderFilter(),
new UsernamePasswordAuthenticationFilter(userDetailsService()),
new BasicAuthenticationFilter(userDetailsService())
)
);
}

@Bean
public UserDetailsService userDetailsService() {
return username -> {
Member member = memberRepository.findByEmail(username)
.orElseThrow(() -> new AuthenticationException("존재하지 않는 사용자입니다."));
return new UserDetails() {
@Override
public String getUsername() {
return member.getEmail();
}
@Override
public String getPassword() {
return member.getPassword();
}
};
};
}

}
50 changes: 50 additions & 0 deletions src/main/java/nextstep/app/WebConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package nextstep.app;

import nextstep.app.domain.Member;
import nextstep.app.domain.MemberRepository;
import nextstep.security.authentication.AuthenticationException;
import nextstep.security.authentication.BasicAuthenticationInterceptor;
import nextstep.security.authentication.FormLoginInterceptor;
import nextstep.security.userdetails.UserDetails;
import nextstep.security.userdetails.UserDetailsService;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

//@Configuration
public class WebConfig implements WebMvcConfigurer {

private final MemberRepository memberRepository;

public WebConfig(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}

@Override
public void addInterceptors(InterceptorRegistry registry) {
System.out.println("WebConfig.addInterceptors");
registry.addInterceptor(new FormLoginInterceptor(userDetailsService()))
.addPathPatterns("/login");
registry.addInterceptor(new BasicAuthenticationInterceptor(userDetailsService()))
.addPathPatterns("/members");
}

@Bean
public UserDetailsService userDetailsService() {
return username -> {
Member member = memberRepository.findByEmail(username)
.orElseThrow(() -> new AuthenticationException("존재하지 않는 사용자입니다."));
return new UserDetails() {
@Override
public String getUsername() {
return member.getEmail();
}

@Override
public String getPassword() {
return member.getPassword();
}
};
};
}
}
24 changes: 24 additions & 0 deletions src/main/java/nextstep/app/domain/LoginService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package nextstep.app.domain;

import org.springframework.stereotype.Service;

@Service
public class LoginService {

private final MemberRepository memberRepository;

public LoginService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}

/**
* @return null 로그인 실패
*/
public Member login(String email, String password) {

return memberRepository.findByEmail(email)
.filter(m -> m.getPassword().equals(password))
.orElse(null);
}
}

6 changes: 6 additions & 0 deletions src/main/java/nextstep/app/domain/Member.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,10 @@ public String getName() {
public String getImageUrl() {
return imageUrl;
}

public void checkPassword(String password) {
if (!this.password.equals(password)) {
throw new IllegalArgumentException("비밀번호가 일치하지 않습니다.");
}
}
}
4 changes: 0 additions & 4 deletions src/main/java/nextstep/app/ui/AuthenticationException.java

This file was deleted.

20 changes: 12 additions & 8 deletions src/main/java/nextstep/app/ui/LoginController.java
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package nextstep.app.ui;

import nextstep.app.domain.MemberRepository;
import nextstep.security.authentication.AuthenticationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@RestController
public class LoginController {
public static final String SPRING_SECURITY_CONTEXT_KEY = "SPRING_SECURITY_CONTEXT";
Expand All @@ -20,10 +17,17 @@ public LoginController(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}

@PostMapping("/login")
public ResponseEntity<Void> login(HttpServletRequest request, HttpSession session) {
return ResponseEntity.ok().build();
}
// @PostMapping("/login")
// public ResponseEntity<Void> login(HttpServletRequest request, HttpSession session) {
// Map<String, String[]> parameterMap = request.getParameterMap();
// String username = parameterMap.get("username")[0];
// String password = parameterMap.get("password")[0];
// Member member = memberRepository.findByEmail(username)
// .orElseThrow(AuthenticationException::new);
// member.checkPassword(password);
// session.setAttribute(SPRING_SECURITY_CONTEXT_KEY, member);
// return ResponseEntity.ok().build();
// }

@ExceptionHandler(AuthenticationException.class)
public ResponseEntity<Void> handleAuthenticationException() {
Expand Down
32 changes: 30 additions & 2 deletions src/main/java/nextstep/app/ui/MemberController.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@

import nextstep.app.domain.Member;
import nextstep.app.domain.MemberRepository;
import nextstep.security.authentication.AuthenticationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

@RestController
Expand All @@ -18,9 +22,33 @@ public MemberController(MemberRepository memberRepository) {
}

@GetMapping("/members")
public ResponseEntity<List<Member>> list() {
public ResponseEntity<List<Member>> list(HttpServletRequest request) {
// String authorization = request.getHeader(HttpHeaders.AUTHORIZATION);
// String[] split = authorization.split(" ");
// String type = split[0];
// String credential = split[1];
// if (!"Basic".equalsIgnoreCase(type)) {
// throw new AuthenticationException();
// }
// try {
// String decodedCredential = new String(Base64Utils.decodeFromString(credential));
// String[] emailAndPassword = decodedCredential.split(":");
// String email = emailAndPassword[0];
// String password = emailAndPassword[1];
// Member member = memberRepository.findByEmail(email).orElseThrow(AuthenticationException::new);
// member.checkPassword(password);
// List<Member> members = memberRepository.findAll();
// return ResponseEntity.ok(members);
// } catch (Exception e) {
// throw new AuthenticationException();
// }
List<Member> members = memberRepository.findAll();
return ResponseEntity.ok(members);
}

}
@ExceptionHandler(AuthenticationException.class)
public ResponseEntity<Void> handleAuthenticationException() {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}

}
11 changes: 11 additions & 0 deletions src/main/java/nextstep/security/authentication/Authentication.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package nextstep.security.authentication;

public interface Authentication {

Object getCredentials();

Object getPrincipal();

Object isAuthenticated();

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package nextstep.security.authentication;

public class AuthenticationException extends RuntimeException {

public AuthenticationException() {
super("인증에 실패하였습니다.");
}
public AuthenticationException(String message) {
super(message);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package nextstep.security.authentication;

public interface AuthenticationManager {

Authentication authenticate(Authentication authentication);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package nextstep.security.authentication;

public interface AuthenticationProvider {

Authentication authenticate(Authentication authentication) throws AuthenticationException;

boolean supports(Class<?> authentication);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package nextstep.security.authentication;

import nextstep.security.userdetails.UserDetailsService;
import nextstep.security.context.SecurityContext;
import nextstep.security.context.SecurityContextHolder;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.List;

public class BasicAuthenticationFilter extends OncePerRequestFilter {

public static final String AUTHENTICATION_SCHEME_BASIC = "Basic";

private final AuthenticationManager authenticationManager;

public BasicAuthenticationFilter(UserDetailsService userDetailsService) {
System.out.println("BasicAuthenticationFilter.BasicAuthenticationFilter");
this.authenticationManager = new ProviderManager(List.of(new DaoAuthenticationProvider(userDetailsService)));
}

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
System.out.println("BasicAuthenticationFilter.doFilterInternal");
try {
Authentication authentication = convert(request);
if (authentication == null) {
System.out.println("authentication null");
filterChain.doFilter(request, response);
return;
}
Authentication authenticate = this.authenticationManager.authenticate(authentication);
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authenticate);
SecurityContextHolder.setContext(context);

filterChain.doFilter(request, response);
} catch (Exception e) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
}
}

private Authentication convert(HttpServletRequest request) {
String header = request.getHeader(HttpHeaders.AUTHORIZATION);
if (header == null) {
return null;
}
header = header.trim();
if (!StringUtils.startsWithIgnoreCase(header, AUTHENTICATION_SCHEME_BASIC)) {
return null;
}
if (header.equalsIgnoreCase(AUTHENTICATION_SCHEME_BASIC)) {
throw new AuthenticationException();
}
byte[] base64Token = header.substring(6).getBytes(StandardCharsets.UTF_8);
byte[] decoded = decode(base64Token);
String token = new String(decoded, StandardCharsets.UTF_8);
int delim = token.indexOf(":");
if (delim == -1) {
throw new AuthenticationException();
}
return UsernamePasswordAuthenticationToken
.unauthenticated(token.substring(0, delim), token.substring(delim + 1));
}

private byte[] decode(byte[] base64Token) {
try {
return Base64.getDecoder().decode(base64Token);
} catch (IllegalArgumentException ex) {
throw new AuthenticationException();
}
}

@ExceptionHandler(AuthenticationException.class)
public ResponseEntity<Void> handleAuthenticationException() {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
}
Loading