Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
Tags
- aws #아키텍트 #과정 #vpc #인프라 구축 #amazon sns #server #less #architecture
- 스파르타코딩클럽 #부트캠프 #IT #백엔드 #머신러닝 #딥러닝 #AI #서버 #자동화 #SQL #기본문법 #데이터베이스 #DBMS #Oracle #MongoDB #아키텍쳐 #DB
- aws #아키텍트 #과정 #vpc #인프라 구축 #alb #load balancer #t.g #target #group #haproxy #high ability #db #replica #region
- 스파르타코딩클럽 #부트캠프 #IT #백엔드 #머신러닝 #AI #서버 #자동화 #SQL #기본문법 #데이터베이스 #웹개발
- aws #아키텍트 #과정 #vpc #인프라 구축 #s3 #bucket #객체 스토리지 #objects storage #events #upload #알림
- aws #아키텍트 #과정 #vpc #인프라 구축 #sqs #message #queue #sns구독
- 공간복잡도 #공간자원 #캐시메모리 #SRAM #DRAM #시간복잡도
- aws #아키텍트 #과정 #vpc #인프라 구축 #auto scailling #lauch template #ec2 instace #private #subnet
- aws #아키텍트 #과정 #vpc #인프라 구축 #haproxy #round robin #process #high ability #auto scailling #app server #launch template
- aws #아키텍트 #과정 #vpc #인프라 구축 #db #장애조치 #reand only #replica #events
- 스파르타코딩클럽 #부트캠프 #IT #백엔드 #머신러닝 #딥러닝 #AI #서버 #자동화 #SQL #기본문법 #데이터베이스
- aws #아키텍트 #과정 #vpc #인프라 구축 #haproxy #고가용성 #테스트 #alb #application #load balancer #application
- aws #아키텍트 #과정 #vpc #인프라 구축 #aurora #database #rds #rdbs #load #balancer #web #page #haproxy
- aws #아키텍트 #과정 #vpc #인프라 구축 #s3 #bucket #객체 #스토리지 #isci #이미지 #업로드
- 스파르타코딩클럽 #부트캠프 #IT #백엔드 #머신러닝 #AI #서버 #자동화 #SQL #기본문법 #데이터베이스
- aws #아키텍트 #과정 #vpc #인프라 구축 #second nat #gateway #routing table #route53 #고가용성 #private subnet #
- aws #아키텍트 #과정 #vpc #인프라 구축 #ec2 #instance #launch #template #생성 #ami #amazone #machine #image
- aws #아키텍트 #과정 #vpc #인프라 구축 #rds #endpoint #cloudwatch #monitoring
- aws #아키텍트 #과정 #vpc #인프라 구축 #php #alb #application #load #balancer #security #group #igw #ec2 #vpc #virtual #private #cloud
- 비트 #바이트 #이진수
- aws #아키텍트 #과정 #vpc #인프라 구축
- 프로세스 #CPU #시공유 #커널
- 쓰레드 #쓰레드풀 #프로세스
- 스파르타코딩클럽 #부트캠프 #IT #백엔드 #머신러닝 #AI #서버 #자동화 #SQL #KDT #기본문법 #데이터베이스 #Computer #Science #CPU #메모리
- aws #아키텍트 #과정 #vpc #인프라 구축 #t.g #target group #alb #application #load #balancer #web #server
- 스파르타코딩클럽 #부트캠프 #IT #백엔드 #OSI #ISO #AI #서버 #자동화 #SQL #기본문법 #데이터베이스 #DBMS #Oracle #MongoDB #아키텍쳐 #DB
- aws #아키텍트 #과정 #vpc #인프라 구축 #rds #replica #복제본 #aurora #database #고가용성
- 썸네일 #이미지
- 업로드 #lambda #함수 #모바일 이미지 #썸네일 이미지
- aws #아키텍트 #과정 #vpc #인프라 구축 #sqs #trigger #python3.9 #패키지 #
Archives
- Today
- Total
요리사에서 IT개발자로
Spring Boot PostMan사용, JWT 인증,인가 (로그인, 로그아웃, 회원탈퇴) 본문
application.yml
spring:
datasource:
username: root
url: jdbc:mysql://localhost:3306/newsfeed
password: gudtjr03!
application:
name: NewSfeed
jpa:
properties:
hibernate:
format_sql: 'true'
use_sql_comments: 'true'
show_sql: 'true'
hibernate:
ddl-auto: update
jwt:
secret:
key: 7Iqk7YyM66W07YOA7L2U65Sp7YG065+9U3ByaW5n6rCV7J2Y7Yqc7YSw7LWc7JuQ67mI7J6F64uI64ukLg==
build.gradle
compileOnly group: 'io.jsonwebtoken', name: 'jjwt-api', version: '0.11.5'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-impl', version: '0.11.5'
runtimeOnly group: 'io.jsonwebtoken', name: 'jjwt-jackson', version: '0.11.5'
User
@Entity
@Getter
@Setter
@NoArgsConstructor
@Table(name = "users")
public class User extends TimeStamped {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String username;
private String password;
private String name;
@Email
private String email;
private String introduce;
private UserRoleEnum role;
private String token;
private LocalDateTime lastLogin;
public User(String username, String password, String name, String email, String introduce, UserRoleEnum role, String token) {
this.username = username;
this.password = password;
this.name = name;
this.email = email;
this.introduce = introduce;
this.role = role;
this.token = token;
this.lastLogin = LocalDateTime.now();
}
JwtAuthenricationFilter
@Slf4j(topic = "로그인 및 JWT 생성")
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final JwtUtil jwtUtil;
private final UserRepository userRepository;
public JwtAuthenticationFilter(JwtUtil jwtUtil, UserRepository userRepository) {
this.jwtUtil = jwtUtil;
this.userRepository = userRepository;
setFilterProcessesUrl("/api/user/login");
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
try {
JoinRequestDto requestDto = new ObjectMapper().readValue(request.getInputStream(), JoinRequestDto.class);
return getAuthenticationManager().authenticate(
new UsernamePasswordAuthenticationToken(
requestDto.getUsername(),
requestDto.getPassword(),
null
)
);
} catch (IOException e) {
log.error(e.getMessage());
throw new RuntimeException(e.getMessage());
}
}
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) {
String username = ((UserDetailsImpl) authResult.getPrincipal()).getUsername();
UserRoleEnum role = ((UserDetailsImpl) authResult.getPrincipal()).getUser().getRole();
String token = jwtUtil.createToken(username, role);
response.addHeader(JwtUtil.AUTHORIZATION_HEADER, token);
Optional<User> user = Optional.ofNullable(userRepository.findByUsername(username).orElseThrow(() ->
new IllegalArgumentException("해당 사용자는 존재하지 않습니다")));
user.get().setToken(token);
userRepository.save(user.get());
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) {
response.setStatus(401);
}
}
JwtAuthorizationFilter
@Slf4j(topic = "JWT 검증 및 인가")
@RequiredArgsConstructor
public class JwtAuthorizationFilter extends OncePerRequestFilter {
private final JwtUtil jwtUtil;
private final UserDetailsServiceImpl userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) throws ServletException, IOException {
String tokenValue = jwtUtil.getJwtFromHeader(req);
if (StringUtils.hasText(tokenValue)) {
if (!jwtUtil.validateToken(tokenValue)) {
log.error("Token Error");
return;
}
Claims info = jwtUtil.getUserInfoFromToken(tokenValue);
try {
setAuthentication(info.getSubject());
} catch (Exception e) {
log.error(e.getMessage());
return;
}
}
filterChain.doFilter(req, res);
}
// 인증 처리
public void setAuthentication(String username) {
SecurityContext context = SecurityContextHolder.createEmptyContext();
Authentication authentication = createAuthentication(username);
context.setAuthentication(authentication);
SecurityContextHolder.setContext(context);
}
// 인증 객체 생성
private Authentication createAuthentication(String username) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
}
}
UserDetailsImpl
public class UserDetailsImpl implements UserDetails {
private final User user;
public UserDetailsImpl(User user) {
this.user = user;
}
public User getUser() {
return user;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
public String getEmail() {
return user.getEmail();
}
public String getIntroduce(){
return user.getIntroduce();
}
public String getToken() {
return user.getToken();
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
UserRoleEnum role = user.getRole();
String authority = role.getAuthority();
SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(authority);
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(simpleGrantedAuthority);
return authorities;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
UserDetailsServiceImpl
@Service
@RequiredArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserRepository userRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("Not Found " + username));
return new UserDetailsImpl(user);
}
}
UserRepository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
Optional<User> findByEmail(String email);
}
UserController
@Slf4j
@Controller
@RequiredArgsConstructor
@RequestMapping("/api/user")
public class UserController {
private final UserService userService;
//회원가입
@PostMapping("/signup")
public ResponseEntity<User> signup(SignupRequestDto requestDto) {
userService.signup(requestDto);
return ResponseEntity.ok().build();
}
// 회원 관련 정보 받기
@GetMapping("/user-info")
@ResponseBody
public Optional<User> getUserInfo(@AuthenticationPrincipal UserDetailsImpl userDetails) {
return userService.getUserInfo(userDetails);
}
//회원 소개 수정
@PutMapping("/user-info")
@ResponseBody
public UserInfoResponseDto updateUserInfo(@RequestBody UpdateInfoRequestDto requestDto, @AuthenticationPrincipal UserDetailsImpl userDetails) {
return userService.updateUserInfo(requestDto, userDetails);
}
//회원탈퇴
@PutMapping("/withdrawal")
@ResponseBody
public void withdrawal(@RequestBody JoinRequestDto requestDto,@AuthenticationPrincipal UserDetailsImpl userDetails) {
userService.withdrawal(requestDto, userDetails);
}
//로그아웃
@DeleteMapping("/logout")
@ResponseBody
public void logout(@RequestBody JoinRequestDto requestDto, @AuthenticationPrincipal UserDetailsImpl userDetails) {
userService.logout(requestDto, userDetails);
}
}
WebSecurityConfig
@Configuration
@EnableWebSecurity // Spring Security 지원을 가능하게 함
@RequiredArgsConstructor
public class WebSecurityConfig {
private final JwtUtil jwtUtil;
private final UserDetailsServiceImpl userDetailsService;
private final AuthenticationConfiguration authenticationConfiguration;
private final UserRepository userRepository;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
return configuration.getAuthenticationManager();
}
@Bean
public JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {
JwtAuthenticationFilter filter = new JwtAuthenticationFilter(jwtUtil, userRepository);
filter.setAuthenticationManager(authenticationManager(authenticationConfiguration));
return filter;
}
@Bean
public JwtAuthorizationFilter jwtAuthorizationFilter() {
return new JwtAuthorizationFilter(jwtUtil, userDetailsService);
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// CSRF 설정
http.csrf((csrf) -> csrf.disable());
// 기본 설정인 Session 방식은 사용하지 않고 JWT 방식을 사용하기 위한 설정
http.sessionManagement((sessionManagement) ->
sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
);
http.authorizeHttpRequests((authorizeHttpRequests) ->
authorizeHttpRequests
.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll() // resources 접근 허용 설정
.requestMatchers("/").permitAll() // 메인 페이지 요청 허가
.requestMatchers("/api/user/**").permitAll() // '/api/user/'로 시작하는 요청 모두 접근 허가
.requestMatchers("/api/newsfeeds/**").permitAll()
.anyRequest().authenticated() // 그 외 모든 요청 인증처리
);
http.logout(logout ->
logout
.logoutRequestMatcher(new AntPathRequestMatcher("/api/logout"))
.logoutSuccessUrl("/"));
// 필터 관리
http.addFilterBefore(jwtAuthorizationFilter(), JwtAuthenticationFilter.class);
http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
회원가입
form-data 형식으로 가능하며
http template은 따로 만들지 않았다.
로그인
데이터베이스는 MySQL Driver를 사용하여 DB에 저장되고
Login같은 경우 Controller에서 따로 지정해주지 않고
JwtAuthenricationFilter에서 수행되게 함
또한 token 같은 경우 DB에도 저장될 수 있게
아래와 같이 로직을 작성하여 DB에 저장되는 것을 확인할 수 있다.
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) {
String username = ((UserDetailsImpl) authResult.getPrincipal()).getUsername();
UserRoleEnum role = ((UserDetailsImpl) authResult.getPrincipal()).getUser().getRole();
String token = jwtUtil.createToken(username, role);
response.addHeader(JwtUtil.AUTHORIZATION_HEADER, token);
Optional<User> user = Optional.ofNullable(userRepository.findByUsername(username).orElseThrow(() ->
new IllegalArgumentException("해당 사용자는 존재하지 않습니다")));
user.get().setToken(token);
userRepository.save(user.get());
}
로그아웃
로그아웃을 하게되면 DB에 저장되있던 token과 Access토큰이 비활성화되는 것을 확인할 수 있고
회원탈퇴
회원탈퇴같은 경우 BLACKLIST_CODE
// 회원탈퇴 토큰
private final String BLACKLIST_TOKEN = "AAABnvxRVklrnYxKZ0aHgTBcXukeZygoC";
public enum UserRoleEnum {
USER(Authority.USER), // 사용자 권한
WITHDRAWAL(Authority.WITHDRAWAL); // 관리자 권한
private final String authority;
UserRoleEnum(String authority) {
this.authority = authority;
}
public String getAuthority() {
return this.authority;
}
public static class Authority {
public static final String USER = "ROLE_USER";
public static final String WITHDRAWAL = "ROLE_WITHDRAWAL";
}
}
를 작성하여 코드로도 확인 및
ROLE 상태로도 확인할 수 있으며
똑같은 username으로 재가입을 시도 할 경우 가입이 불가능하게 세팅하였다.
HTTP 템플릿은 따로 만들지 않았고
포스트맨에서 확인이 가능하다.
https://hs-backend.tistory.com/184
https://www.youtube.com/@xxxjjhhh/videos
반응형
'Spring' 카테고리의 다른 글
스프링 시큐리티 내부 구조 Security Filter Chain 등록, 여러개 등록, 특정 요청 허가 (1) | 2024.06.11 |
---|---|
Spring Security 내부 구조 DelegatingFilterProxy와 FilterChainProxy (0) | 2024.06.11 |
Spring Security JWT 인증 방식과 Security 동작원리 (0) | 2024.06.05 |
스파르타 부트캠프 SpringBoot JWT인증, 인가 (0) | 2024.06.05 |
스파르타 부트캠프 SpringBoot @Validation란 (0) | 2024.05.31 |