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
- java
- mysql
- org.h2.jdbc.JdbcSQLSyntaxErrorException
- 자바스프링
- unmappable character for encoding MS949
- JSESSIONID
- jwt
- TIL
- 엔터키 이벤트
- .decode('utf-8')
- 항해99
- 에러해결법
- java.sql.SQLException
- 알고리즘
- 인프런
- MS949
- 인텔리제이
- API
- HTML
- ServerSelectionTimeoutError
- 프로그래머스
- 독서
- 스파르타코딩클럽
- 객체지향
- 스프링시큐리티
- WIL
- PUT과 PATCH
- Code
- 김영한
- 자바
Archives
- Today
- Total
고을마을 : 나의 코딩 이야기
항해99 8주차 WIL[일반 로그인, 회원가입 완료] 본문
2022.6.26 항해 8주차.
// 일반 회원가입
@Transactional
public TokenDto register(SignupRequestDto requestDto) {
// 회원 아이디 중복 확인
String username = requestDto.getUsername();
if (userRepository.existsByUsername(username)) {
throw new CustomException(ErrorCode.SIGNUP_MEMBERID_DUPLICATE_CHECK);
}
// 닉네임 중복 확인
String nickname = requestDto.getNickname();
if (userRepository.existsByNickname(nickname)) {
throw new CustomException(ErrorCode.SIGNUP_NICKNAME_DUPLICATE_CHECK);
}
// 회원 비밀번호 암호화
String password = passwordEncoder.encode(requestDto.getPassword());
User user = userRepository.save(
User.builder()
.username(requestDto.getUsername())
.password(password)
.nickname(requestDto.getNickname())
.build()
);
List<Stack> stack = stackRepository.saveAll(tostackByUserId(requestDto.getStacks(),user));
user.updateStack(stack);
TokenDto tokenDto = jwtTokenProvider.createToken(user);
RefreshToken refreshToken = new RefreshToken(user.getUsername(), tokenDto.getRefreshToken());
refreshTokenRepository.save(refreshToken);
return tokenDto;
}
// 로그인
@Transactional
public Map<String, Object> login(LoginDto loginDto) {
UserValidator.validateUsernameEmpty(loginDto);
UserValidator.validatePasswordEmpty(loginDto);
User user = userRepository.findByUsername(loginDto.getUsername()).orElseThrow(
() -> new CustomException(ErrorCode.LOGIN_NOT_FOUNT_MEMBERID)
);
if (!passwordEncoder.matches(loginDto.getPassword(), user.getPassword())) {
throw new CustomException(ErrorCode.LOGIN_PASSWORD_NOT_MATCH);
}
Long userId = user.getId();
TokenDto tokenDto = jwtTokenProvider.createToken(user);
RefreshToken refreshToken = new RefreshToken(loginDto.getUsername(), tokenDto.getRefreshToken());
refreshTokenRepository.save(refreshToken);
Map<String, Object> data = new HashMap<>();
data.put("userId", userId);
data.put("token", tokenDto);
return data;
}
// 로그아웃
@Transactional
public void deleteRefreshToken(TokenRequestDto tokenRequestDto) {
User user = userRepository.findById(tokenRequestDto.getUserId()).orElseThrow(
() -> new CustomException(ErrorCode.NOT_FOUND_USER_INFO)
);
String username = user.getUsername();
RefreshToken refreshToken = refreshTokenRepository.findByRefreshKey(username).orElseThrow(
() -> new CustomException(ErrorCode.REFRESH_TOKEN_NOT_FOUND)
);
refreshTokenRepository.deleteById(refreshToken.getRefreshKey());
}
// reissue(Token 재발급)
@Transactional
public TokenDto reissue(TokenRequestDto tokenRequestDto) {
log.info("Refresh Token : " + tokenRequestDto.getRefreshToken());
UserValidator.validateRefreshTokenReissue(tokenRequestDto);
// RefreshToken 만료됐을 경우
if (jwtTokenProvider.validateToken(tokenRequestDto.getRefreshToken()) != JwtReturn.SUCCESS) {
throw new CustomException(ErrorCode.REFRESH_TOKEN_EXPIRED);
}
User user = userRepository.findById(tokenRequestDto.getUserId()).orElseThrow(
() -> new CustomException(ErrorCode.NOT_FOUND_USER_INFO)
);
// RefreshToken DB에 없을 경우
RefreshToken refreshToken = refreshTokenRepository.findByRefreshKey(user.getUsername()).orElseThrow(
() -> new CustomException(ErrorCode.REFRESH_TOKEN_NOT_FOUND)
);
// RefreshToken 일치하지 않는 경우
if (!refreshToken.getRefreshValue().equals(tokenRequestDto.getRefreshToken())) {
throw new CustomException(ErrorCode.REFRESH_TOKEN_NOT_MATCH);
}
// Access Token, Refresh Token 재발급
TokenDto tokenDto = jwtTokenProvider.createToken(user);
RefreshToken updateRefreshToken = refreshToken.updateValue(tokenDto.getRefreshToken());
refreshTokenRepository.save(updateRefreshToken);
return tokenDto;
}
// public List<Stack> tostack(List<StackDto> stackDtoList) {
// List<Stack> stacks = new ArrayList<>();
// for(StackDto stackdto : stackDtoList){
// stacks.add(new Stack(stackdto));
// }
// return stacks;
// }
private List<Stack> tostackByUserId(List<StackDto> requestDto, User user) {
List<Stack> stackList = new ArrayList<>();
for(StackDto stackdto : requestDto){
stackList.add(new Stack(stackdto, user));
}
return stackList;
}
}
@RequiredArgsConstructor
@RestController
public class UserController {
private final UserService userService;
private final UserRepository userRepository;
// 회원가입 API
@PostMapping("/user/signup")
public ResponseEntity<Object> registerUser(@RequestBody SignupRequestDto requestDto) {
TokenDto tokenDto = userService.register(requestDto);
return new ResponseEntity<>(new StatusResponseDto("회원가입 완료했습니다.", ""), HttpStatus.OK);
}
// 닉네임 중복검사 API
@PostMapping("/user/nickname")
public ResponseEntity<Object> nicknameCheck(@RequestBody SignupRequestDto requestDto){
// UserValidator.validateInputNickname(requestDto);
if(userRepository.existsByNickname(requestDto.getNickname())) {
return new ResponseEntity<>(new ExceptionResponse(ErrorCode.SIGNUP_NICKNAME_DUPLICATE), HttpStatus.BAD_REQUEST);
} else {
return new ResponseEntity<>(new StatusResponseDto("사용가능한 닉네임입니다.", ""), HttpStatus.OK);
}
}
// 로그인 API
@PostMapping("/user/login")
public ResponseEntity<Object> login(@RequestBody LoginDto loginDto) {
Map<String, Object> data = userService.login(loginDto);
return new ResponseEntity<>(new StatusResponseDto("로그인에 성공하셨습니다", data), HttpStatus.OK);
}
// 로그아웃 API
@PostMapping("/user/logout")
public ResponseEntity<Object> logout(@RequestBody TokenRequestDto tokenRequestDto) {
userService.deleteRefreshToken(tokenRequestDto);
return new ResponseEntity<>(new StatusResponseDto("로그아웃 성공", ""), HttpStatus.OK);
}
// 토큰 재발행 API
@PostMapping("/user/reissue")
public ResponseEntity<Object> reissue(@RequestBody TokenRequestDto tokenRequestDto) {
TokenDto tokenDto = userService.reissue(tokenRequestDto);
return new ResponseEntity<>(new StatusResponseDto("토큰 재발급 성공", tokenDto), HttpStatus.OK);
}
// 유저정보
@GetMapping("/user/userinfo")
@ResponseBody
public UserInfo Session(){
// public com.project.dogfaw.user.model.User Session(){
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
UserDetailsImpl principal = (UserDetailsImpl) authentication.getPrincipal();
String username = principal.getUser().getUsername();
com.project.dogfaw.user.model.User user = userRepository.findByUsername(username).orElseThrow(
() -> new UsernameNotFoundException("존재하지 않는 유저입니다")
);
return new UserInfo(user.getUsername(), user.getNickname());
// return user;
}
}
package com.project.dogfaw.user.repository;
import com.project.dogfaw.user.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserRepository extends JpaRepository<User, Long> {
// 이메일 중복 확인
boolean existsByUsername(String memberId);
// 닉네임 중복 확인
boolean existsByNickname(String nickname);
// 로그인
Optional<User> findByUsername(String username);
Optional<User> findByNickname(String nickname);
// Optional<User> findByKakaoId(Long kakaoId);
}
package com.project.dogfaw.user.repository;
import com.project.dogfaw.user.model.Stack;
import org.springframework.data.jpa.repository.JpaRepository;
public interface StackRepository extends JpaRepository<Stack, Long> {
}
package com.project.dogfaw.user.repository;
import com.project.dogfaw.user.model.RefreshToken;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface RefreshTokenRepository extends JpaRepository<RefreshToken, String> {
Optional<RefreshToken> findByRefreshKey(String refreshKey);
}
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Builder
@Entity(name = "Users")
@DynamicUpdate // null 값인 field 를 DB에서 설정된 default을 줌
public class User {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
private Long id;
@Column(nullable = false, unique = true)
private String username;
@Column(nullable = false)
@JsonIgnore
private String password;
@Column(nullable = false, unique = true)
private String nickname;
@Column
private String profileImg;
// @Column
// private String stack;
@OneToMany
@JoinColumn(name = "stack_id")
private List<Stack> stacks = new ArrayList<>();
public void updateStack(List<Stack> stack) {
this.stacks = stack;
}
// @Enumerated(EnumType.STRING)
// private Role role;
// private String List<bookMark>;
//
// private String List<userApplication>
}
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Builder
@Entity
@DynamicUpdate // null 값인 field 를 DB에서 설정된 default을 줌
public class Stack {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Id
private Long id;
@Column
private String stack;
private Long userId;
public Stack(StackDto stackdto) {
this.stack = stackdto.getStack();
}
public Stack(StackDto stackdto, User user) {
this.stack = stackdto.getStack();
this.userId = user.getId();
}
}
@NoArgsConstructor
@Getter
@Entity
public class RefreshToken {
@Id
private String refreshKey;
private String refreshValue;
public RefreshToken(String refreshKey, String refreshValue) {
this.refreshKey = refreshKey;
this.refreshValue = refreshValue;
}
public RefreshToken updateValue(String token) {
this.refreshValue = token;
return this;
}
}
package com.project.dogfaw.user.dto;
import lombok.Builder;
import lombok.Getter;
@Getter
@Builder
public class UserResponseDto {
private Long userId;
}
package com.project.dogfaw.user.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
@Getter
@Builder
@AllArgsConstructor
public class UserInfo {
private String username;
private String nickname;
}
package com.project.dogfaw.user.dto;
import lombok.Getter;
@Getter
public class StackDto {
private String stack;
}
package com.project.dogfaw.user.dto;
import lombok.Getter;
import java.util.ArrayList;
import java.util.List;
@Getter
public class SignupRequestDto {
private Long userId;
private String username;
private String password;
private String nickname;
private List<StackDto> stacks = new ArrayList<>();
}
package com.project.dogfaw.user.dto;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
public class SignOutDto {
private String nickname;
}
package com.project.dogfaw.user.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@Getter
@NoArgsConstructor
@AllArgsConstructor
public class LoginDto {
private String username;
private String password;
public UsernamePasswordAuthenticationToken toAuthentication() {
return new UsernamePasswordAuthenticationToken(username, password);
}
}
package com.project.dogfaw.security;
import com.project.dogfaw.security.jwt.JwtAuthenticationFilter;
import com.project.dogfaw.security.jwt.JwtTokenProvider;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
@RequiredArgsConstructor
@Configuration
@EnableWebSecurity // 스프링 Security 지원을 가능하게 함
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
private final JwtTokenProvider jwtTokenProvider;
@Bean
public BCryptPasswordEncoder encodePassword() {
return new BCryptPasswordEncoder();
}
@Override
public void configure(WebSecurity web) {
// h2-console 사용에 대한 허용 (CSRF, FrameOptions 무시)
web
.ignoring()
.antMatchers("/h2-console/**");
// .antMatchers("/v2/api-docs","/v3/api-docs", "/swagger-resources/**", "**/swagger-resources/**", "/swagger-ui.html", "/webjars/**", "/swagger/**","/swagger-ui","/swagger-ui/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().configurationSource(corsConfigurationSource());
http.csrf().disable().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.headers().frameOptions().disable();
http.authorizeRequests();
// 회원 관리 처리 API (POST /user/**) 에 대해 CSRF 무시
http.authorizeRequests()
// login 없이 허용
.antMatchers("/user/signup").permitAll()
.antMatchers("/user/nickname").permitAll()
.antMatchers("/user/login").permitAll()
.antMatchers("/user/logout").permitAll()
.antMatchers("/user/reissue").permitAll()
.antMatchers(HttpMethod.GET, "/api/post/**").permitAll()
// .antMatchers("/api/posts").permitAll()
// .antMatchers("/api/preview").permitAll()
// .antMatchers("/post/filter/**").permitAll()
// .antMatchers("/webSocket/**").permitAll()
// .antMatchers("/search/**").permitAll()
// .antMatchers("/subscribe/**").permitAll()
// .antMatchers("/v2/api-docs","/v3/api-docs", "/swagger-resources/**", "**/swagger-resources/**", "/swagger-ui.html", "/webjars/**", "/swagger*/**","/swagger-ui","/swagger-ui/**").permitAll()
//추가 - 메인 페이지 접근 허용
.antMatchers("/").permitAll()
// 그 외 어떤 요청이든 '인증'과정 필요
.anyRequest().authenticated()
.and()
.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider),
UsernamePasswordAuthenticationFilter.class);
}
//"http://localhost:3000","http://localhost:8080"
//"https://amplify.d3ifjxscizr42x.amplifyapp.com",
//"https://everymohum.shop","https://everymohum.com"
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowCredentials(true) ;
configuration.addAllowedOriginPattern("*");
configuration.addAllowedOrigin("http://localhost:3000"); // local 테스트 시
// configuration.addAllowedOrigin("https://amplify.d3ifjxscizr42x.amplifyapp.com"); // 배포 시
// configuration.addAllowedOrigin("https://www.everymohum.com");
configuration.addAllowedMethod("*");
configuration.addAllowedHeader("*");
configuration.addExposedHeader("Authorization");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
package com.project.dogfaw.security;
import com.project.dogfaw.user.model.User;
import com.project.dogfaw.user.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserRepository userRepository;
@Autowired
public UserDetailsServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
public UserDetailsImpl loadUserByUsername(String userPk) throws UsernameNotFoundException {
User user = userRepository.findById(Long.parseLong(userPk))
.orElseThrow(() -> new UsernameNotFoundException(userPk + "은 존재하지 않는 아이디입니다."));
return new UserDetailsImpl(user);
}
}
package com.project.dogfaw.security;
import com.project.dogfaw.user.model.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.GrantedAuthority;
import java.util.Collection;
import java.util.Collections;
public class UserDetailsImpl implements UserDetails {
private final User user;
public UserDetailsImpl(User user) {
this.user = user;
}
public User getUser() {
return user;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.emptyList();
}
@Override
public String getPassword() {
return null;
}
@Override
public String getUsername() {
return null;
}
@Override
public boolean isAccountNonExpired() {
return false;
}
@Override
public boolean isAccountNonLocked() {
return false;
}
@Override
public boolean isCredentialsNonExpired() {
return false;
}
@Override
public boolean isEnabled() {
return false;
}
}
package com.project.dogfaw.security.jwt;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
public class TokenRequestDto {
private String accessToken;
private String refreshToken;
private Long userId;
}
package com.project.dogfaw.security.jwt;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
@Builder
@AllArgsConstructor
public class TokenDto {
private String accessToken;
private String refreshToken;
private Long accessTokenExpiresIn;
}
package com.project.dogfaw.security.jwt;
import com.project.dogfaw.common.exception.CustomException;
import com.project.dogfaw.common.exception.ErrorCode;
import com.project.dogfaw.user.model.User;
import io.jsonwebtoken.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@RequiredArgsConstructor
@Component
public class JwtTokenProvider {
@Value("${jwt.secret-key}")
private String secretKey;
// Access Token 유효기간 - 하루
private static final Long accessTokenValidTime = 24 * 60 * 60 * 1000L;
// Refresh Token 유효기간 - 7일
private static final Long refreshTokenValidTime = 7 * 24 * 60 * 60 * 1000L;
private final UserDetailsService userDetailsService;
@PostConstruct
protected void init() {
secretKey = Base64.getEncoder().encodeToString(secretKey.getBytes());
}
// 토큰 생성
public TokenDto createToken(User user) {
Map<String, Object> headers = new HashMap<>();
headers.put("typ", "JWT");
Claims claims = Jwts.claims().setSubject(String.valueOf(user.getId()));
claims.put("username", user.getUsername());
claims.put("nickname", user.getNickname());
claims.put("Stack", user.getStacks());
// claims.put("profileImg", user.getProfileImg());
Date now = new Date();
String accessToken = Jwts.builder()
.setHeader(headers)
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(new Date(now.getTime() + accessTokenValidTime))
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
String refreshToken = Jwts.builder()
.setIssuedAt(now)
.setExpiration(new Date(now.getTime() + refreshTokenValidTime))
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
return TokenDto.builder()
.accessToken(accessToken)
.accessTokenExpiresIn(accessTokenValidTime)
.refreshToken(refreshToken)
.build();
}
// 토큰에서 회원 정보 추출
public String getUserPk(String token) {
return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token).getBody().getSubject();
}
// JWT 토큰에서 인증 정보 조회
public Authentication getAuthentication(String token) {
UserDetails userDetails = userDetailsService.loadUserByUsername(this.getUserPk(token));
return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
}
public String resolveToken(HttpServletRequest request) {
return request.getHeader("Authorization");
}
// 토큰의 유효성 + 만료일자 확인
public JwtReturn validateToken(String jwtToken) {
System.out.println(jwtToken);
try {
Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwtToken);
if (claims.getBody().getExpiration().after(new Date())) {
return JwtReturn.SUCCESS;
} else {
return JwtReturn.FAIL;
}
} catch (ExpiredJwtException e) {
log.info("만료된 JWT 토큰입니다");
return JwtReturn.EXPIRED;
} catch (UnsupportedJwtException e) {
log.info("지원되지 않는 JWT 토큰입니다");
throw new CustomException(ErrorCode.JWT_TOKEN_NOT_SUPPORTED);
} catch (IllegalArgumentException e) {
log.info("JWT 토큰이 잘못되었습니다");
throw new CustomException(ErrorCode.JWT_TOKEN_WRONG_FORM);
} catch (MalformedJwtException e) {
log.info("잘못된 JWT 서명입니다");
throw new CustomException(ErrorCode.JWT_TOKEN_WRONG_SIGNATURE);
} catch (Exception e) {
log.info(e.getMessage());
}
return JwtReturn.FAIL;
}
public String getAccessTokenPayload(String accessToken) {
return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(accessToken)
.getBody().getSubject();
}
public Long getUserIdFromToken(String token) {
Claims claims = getAllClaims(token);
return Long.valueOf(String.valueOf(claims.getSubject()));
}
private Claims getAllClaims(String token) {
return Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token)
.getBody();
}
}
package com.project.dogfaw.security.jwt;
public enum JwtReturn {
SUCCESS, EXPIRED, FAIL
}
package com.project.dogfaw.security.jwt;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtTokenProvider jwtTokenProvider;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
String token = jwtTokenProvider.resolveToken(request);
if (token != null && !token.isEmpty()) {
token = token.replaceAll("Bearer", "");
}
if (token != null && jwtTokenProvider.validateToken(token) == JwtReturn.EXPIRED) {
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);//401
return;
}
if (token != null && jwtTokenProvider.validateToken(token) == JwtReturn.FAIL) {
response.setStatus(HttpServletResponse.SC_FORBIDDEN); //403
return;
}
if (token != null && jwtTokenProvider.validateToken(token) == JwtReturn.SUCCESS) {
Authentication authentication = jwtTokenProvider.getAuthentication(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(request, response);
}
}
package com.project.dogfaw.common.validator;
import com.project.dogfaw.common.exception.CustomException;
import com.project.dogfaw.common.exception.ErrorCode;
import com.project.dogfaw.security.jwt.TokenRequestDto;
import com.project.dogfaw.user.dto.LoginDto;
import com.project.dogfaw.user.dto.SignupRequestDto;
import java.util.regex.Pattern;
public class UserValidator {
public static void validateInputNickname(SignupRequestDto requestDto) {
String nickname = requestDto.getNickname();
String patternNickname = "^[A-Za-z0-9가-힣]{2,6}$";
// 닉네임 설정 유효성 검사
if (nickname == null || !Pattern.matches(patternNickname, nickname)) {
throw new CustomException(ErrorCode.SIGNUP_NICKNAME_WRONG_INPUT);
}
}
public static void validateInputStack(SignupRequestDto requestDto) {
if (requestDto.getStacks().size()==0) {
throw new CustomException(ErrorCode.SIGNUP_MAJOR_WRONG_INPUT);
}
}
public static void validateUsernameEmpty(LoginDto loginDto) {
String username = loginDto.getUsername();
if (username.isEmpty()) {
throw new CustomException(ErrorCode.LOGIN_MEMBERID_EMPTY);
}
}
public static void validatePasswordEmpty(LoginDto loginDto) {
String password = loginDto.getPassword();
if (password.isEmpty()) {
throw new CustomException(ErrorCode.LOGIN_PASSWORD_EMPTY);
}
}
public static void validateRefreshTokenReissue(TokenRequestDto tokenRequestDto) {
String accessToken = tokenRequestDto.getAccessToken();
String refreshToken = tokenRequestDto.getRefreshToken();
Long userId = tokenRequestDto.getUserId();
if (accessToken == null || refreshToken == null || userId == null) {
throw new CustomException(ErrorCode.REFRESH_TOKEN_REISSUE_WRONG_INPUT);
}
}
}
package com.project.dogfaw.common.exception;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@AllArgsConstructor
public class StatusResponseDto {
private String msg;
private Object data;
}
package com.project.dogfaw.common.exception;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.springframework.http.HttpStatus;
@Getter
@Setter
@NoArgsConstructor
public class ExceptionResponse {
private HttpStatus status;
private String errorCode;
private String errorMessage;
public ExceptionResponse(ErrorCode errorCode) {
this.status = errorCode.getStatus();
this.errorCode = errorCode.getErrorCode();
this.errorMessage = errorCode.getErrorMessage();
}
}
package com.project.dogfaw.common.exception;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
@Getter
@RequiredArgsConstructor
public enum ErrorCode {
OK(HttpStatus.OK, "200", "true"),
//문자열 체크
NOT_VALIDCONTENT(HttpStatus.BAD_REQUEST,"400","유효하지 않는 내용입니다."),
NOT_VALIDURL(HttpStatus.BAD_REQUEST,"400","요효하지 않는 URL 입니다."),
// 회원가입
SIGNUP_MEMBERID_WRONG_INPUT(HttpStatus.BAD_REQUEST, "400", "아이디 형식을 맞춰주세요"),
SIGNUP_PASSWORD_WRONG_INPUT(HttpStatus.BAD_REQUEST, "400", "비밀번호 형식을 맞춰주세요"),
SIGNUP_PWCHECK_WRONG_INPUT(HttpStatus.BAD_REQUEST, "400", "비밀번호가 일치하지 않습니다"),
SIGNUP_NICKNAME_WRONG_INPUT(HttpStatus.BAD_REQUEST, "400", "닉네임 형식을 맞춰주세요"),
SIGNUP_MEMBERID_DUPLICATE_CHECK(HttpStatus.BAD_REQUEST, "400", "아이디 중복확인을 해주세요"),
SIGNUP_NICKNAME_DUPLICATE_CHECK(HttpStatus.BAD_REQUEST, "400", "닉네임 중복확인을 해주세요"),
SIGNUP_MAJOR_WRONG_INPUT(HttpStatus.BAD_REQUEST, "400", "분야를 선택해주세요"),
SIGNUP_USERID_NOT_FOUND(HttpStatus.NOT_FOUND, "404", "userId가 존재하지 않습니다"),
SIGNUP_MEMBERID_DUPLICATE(HttpStatus.BAD_REQUEST, "400", "해당 아이디가 이미 존재합니다"),
SIGNUP_MEMBERID_CORRECT(HttpStatus.OK, "200", "사용할 수 있는 아이디입니다"),
SIGNUP_NICKNAME_DUPLICATE(HttpStatus.BAD_REQUEST, "400", "해당 닉네임이 이미 존재합니다"),
SIGNUP_NICKNAME_CORRECT(HttpStatus.OK, "200", "사용할 수 있는 닉네임입니다"),
// Token
JWT_TOKEN_WRONG_SIGNATURE(HttpStatus.UNAUTHORIZED, "401", "잘못된 JWT 서명입니다"),
JWT_TOKEN_NOT_SUPPORTED(HttpStatus.UNAUTHORIZED, "401", "지원되지 않는 JWT 토큰입니다."),
JWT_TOKEN_WRONG_FORM(HttpStatus.UNAUTHORIZED, "401", "JWT 토큰이 잘못되었습니다."),
REFRESH_TOKEN_EXPIRED(HttpStatus.UNAUTHORIZED, "401", "로그인이 만료되었습니다. 재로그인 하세요."),
REFRESH_TOKEN_NOT_FOUND(HttpStatus.NOT_FOUND, "404", "Refresh Token이 존재하지 않습니다. 로그인 해주세요"),
REFRESH_TOKEN_NOT_MATCH(HttpStatus.UNAUTHORIZED, "401", "Refresh Token이 일치하지 않습니다"),
REFRESH_TOKEN_REISSUE_WRONG_INPUT(HttpStatus.BAD_REQUEST, "400", "userId, accessToken, refreshToken을 입력해주세요"),
// 로그인
LOGIN_NOT_FOUNT_MEMBERID(HttpStatus.NOT_FOUND, "404", "해당 아이디를 찾을 수 없습니다"),
LOGIN_MEMBERID_EMPTY(HttpStatus.BAD_REQUEST, "400", "아이디를 입력해주세요"),
LOGIN_PASSWORD_EMPTY(HttpStatus.BAD_REQUEST, "400", "비밀번호를 입력해주세요"),
LOGIN_PASSWORD_NOT_MATCH(HttpStatus.BAD_REQUEST, "400", "비밀번호가 틀렸습니다. 다시 입력해주세요"),
// 회원 탈퇴
NOT_MATCH_USER_INFO(HttpStatus.BAD_REQUEST, "400", "유저 정보가 일치하지 않습니다"),
//기타
NOT_FOUND_AUTHORIZATION_IN_SECURITY_CONTEXT(HttpStatus.INTERNAL_SERVER_ERROR, "998", "Security Context에 인증 정보가 없습니다."),
NOT_FOUND_USER_INFO(HttpStatus.NOT_FOUND, "404", "해당 유저가 존재하지 않습니다"),
// 이미지
WRONG_INPUT_IMAGE(HttpStatus.BAD_REQUEST, "400", "이미지는 반드시 있어야 합니다"),
IMAGE_UPLOAD_ERROR(HttpStatus.BAD_REQUEST, "400", "이미지 업로드에 실패했습니다"),
WRONG_IMAGE_FORMAT(HttpStatus.BAD_REQUEST, "400", "지원하지 않는 파일 형식입니다"),
// Post
POST_NOT_FOUND(HttpStatus.NOT_FOUND, "404", "해당 게시물을 찾을 수 없습니다"),
POST_UPDATE_WRONG_ACCESS(HttpStatus.BAD_REQUEST, "400", "본인의 게시물만 수정할 수 있습니다"),
POST_DELETE_WRONG_ACCESS(HttpStatus.BAD_REQUEST, "400", "본인의 게시물만 삭제할 수 있습니다"),
POST_WRONG_INPUT(HttpStatus.BAD_REQUEST, "400", "비어있는 항목을 채워주세요"),
POST_MAJOR_WRONG_INPUT(HttpStatus.BAD_REQUEST, "400", "모집 분야를 선택해주세요"),
POST_TITLE_INPUT_LENGTH_ERROR(HttpStatus.BAD_REQUEST, "400", "제목을 공백 포함 20자 이내로 작성해주세요"),
POST_CONTENT_INPUT_LENGTH_ERROR(HttpStatus.BAD_REQUEST, "400", "내용을 공백 포함 250자 이내로 작성해주세요"),
// comment
COMMENT_WRONG_INPUT(HttpStatus.BAD_REQUEST, "400", "댓글을 입력해주세요"),
COMMENT_NOT_FOUND(HttpStatus.NOT_FOUND, "404", "해당 댓글을 찾을 수 없습니다"),
COMMENT_UPDATE_WRONG_ACCESS(HttpStatus.BAD_REQUEST, "400", "본인의 댓글만 수정할 수 있습니다"),
COMMENT_DELETE_WRONG_ACCESS(HttpStatus.BAD_REQUEST, "400", "본인의 댓글만 삭제할 수 있습니다"),
USER_UPDATE_WRONG_ACCESS(HttpStatus.BAD_REQUEST, "400", "본인이 아니면 수정할 수 없습니다"),
// apply
APPLY_WRONG_ERROR(HttpStatus.BAD_REQUEST, "400", "본인의 프로젝트에 지원 신청 할 수 없습니다"),
ALREADY_STARTED_ERROR(HttpStatus.BAD_REQUEST, "400", "모집중인 프로젝트가 아닙니다"),
ALREADY_APPLY_POST_ERROR(HttpStatus.BAD_REQUEST,"400", "이미 지원한 프로젝트입니다"),
APPLY_MAJOR_WRONG_INPUT(HttpStatus.BAD_REQUEST,"400", "지원할 분야를 선택해주세요"),
APPLY_MAJOR_NOT_EXIST(HttpStatus.NOT_FOUND, "404","해당 분야는 모집하지 않습니다"),
APPLY_PEOPLE_SET_CLOSED(HttpStatus.BAD_REQUEST, "400", "해당 분야의 정원이 다 찼습니다"),
APPLY_NOT_FOUND(HttpStatus.BAD_REQUEST,"404", "해당 지원 정보를 찾을 수 없습니다"),
APPLY_OVER_NO_AUTHORITY(HttpStatus.FORBIDDEN,"403", "권한이 없습니다"),
APPLY_MESSAGE_INPUT_LENGTH_ERROR(HttpStatus.BAD_REQUEST, "400", "지원 메시지는 20자 이내로 작성해주세요"),
EXCEED_APPLY_USER_NUMBER(HttpStatus.INTERNAL_SERVER_ERROR,"500","전공 모집인원이 초과되었습니다."),
NO_DIFFERENCE_STATUS(HttpStatus.FORBIDDEN,"403", "Status 변경 사항이 없습니다"),
// mail
EMAIL_WRONG_PATTERN(HttpStatus.BAD_REQUEST, "400", "이메일 형식을 맞춰주세요"),
//Room
ALREADY_EXISTS_CHAT_ROOM(HttpStatus.BAD_REQUEST,"400","채팅방이 이미 존재합니다."),
NOT_EXIST_ROOM(HttpStatus.NOT_FOUND,"404","채팅방이 존재하지 않습니다."),
//sse
NOT_EXIST_NOTIFICATION(HttpStatus.NOT_FOUND,"404","존재하지 않는 알림입니다.");
private final HttpStatus status;
private final String errorCode;
private final String errorMessage;
}
package com.project.dogfaw.common.exception;
import lombok.Getter;
@Getter
public class CustomException extends RuntimeException {
private final ErrorCode errorCode;
public CustomException(ErrorCode errorCode) {
super(errorCode.getErrorMessage());
this.errorCode = errorCode;
}
}
'항해99 7기 > WIL(Weekly I Learned' 카테고리의 다른 글
항해99 10주차 WIL[무한스크롤] (0) | 2022.07.17 |
---|---|
항해99 9주차 WIL[카카오 OAuth 로그인 완료, github actions를 활용한 CI/CD 구현] (0) | 2022.07.11 |
항해99 7주차 WIL[JWT] (0) | 2022.06.26 |
항해99 7기 6주차 WIL[첫 협업] (0) | 2022.06.19 |
항해99 7기 5주차 WIL[cors] (0) | 2022.06.13 |