-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b20be7d
commit d94f748
Showing
13 changed files
with
378 additions
and
104 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
82 changes: 14 additions & 68 deletions
82
src/main/java/com/meetup/teame/backend/domain/auth/config/SecurityConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,85 +1,31 @@ | ||
package com.meetup.teame.backend.domain.auth.config; | ||
|
||
import com.meetup.teame.backend.domain.auth.jwt.JWTFilter; | ||
import com.meetup.teame.backend.domain.auth.jwt.JWTUtil; | ||
import com.meetup.teame.backend.domain.auth.oauth.handler.CustomSuccessHandler; | ||
import com.meetup.teame.backend.domain.auth.oauth.service.CustomOAuth2UserService; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.security.config.annotation.web.builders.HttpSecurity; | ||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; | ||
import org.springframework.security.config.http.SessionCreationPolicy; | ||
import org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter; | ||
import org.springframework.security.web.SecurityFilterChain; | ||
import org.springframework.web.cors.CorsConfiguration; | ||
import org.springframework.web.cors.CorsConfigurationSource; | ||
|
||
import java.util.List; | ||
|
||
@RequiredArgsConstructor | ||
@Configuration | ||
@EnableWebSecurity | ||
public class SecurityConfig { | ||
|
||
private final CustomOAuth2UserService customOAuth2UserService; | ||
private final CustomSuccessHandler customSuccessHandler; | ||
private final JWTUtil jwtUtil; | ||
|
||
@Bean | ||
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { | ||
|
||
http | ||
.cors(corsCustomizer -> corsCustomizer.configurationSource(new CorsConfigurationSource() { | ||
|
||
@Override | ||
public CorsConfiguration getCorsConfiguration(HttpServletRequest request) { | ||
|
||
CorsConfiguration configuration = new CorsConfiguration(); | ||
|
||
configuration.setAllowedOrigins(List.of("http://localhost:3000", "https://api.yeongjin.site", "https://ddoba.vercel.app")); | ||
configuration.setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "OPTIONS")); // Include OPTIONS method | ||
configuration.setAllowCredentials(true); | ||
configuration.setAllowedHeaders(List.of("*")); | ||
configuration.setMaxAge(3600L); | ||
|
||
configuration.setExposedHeaders(List.of("Set-Cookie", "Authorization")); // Expose Set-Cookie and Authorization headers | ||
|
||
return configuration; | ||
} | ||
})); | ||
|
||
// From 로그인 방식 disable | ||
http | ||
.formLogin((auth) -> auth.disable()); | ||
|
||
// HTTP Basic 인증 방식 disable | ||
http | ||
.httpBasic((auth) -> auth.disable()); | ||
|
||
// JWTFilter 추가 | ||
http | ||
.addFilterAfter(new JWTFilter(jwtUtil), OAuth2LoginAuthenticationFilter.class); | ||
|
||
// oauth2 | ||
http | ||
.oauth2Login((oauth2) -> oauth2 | ||
.userInfoEndpoint((userInfoEndpointConfig) -> userInfoEndpointConfig | ||
.userService(customOAuth2UserService)) | ||
.successHandler(customSuccessHandler) | ||
); | ||
|
||
// 경로별 인가 작업 | ||
http | ||
.authorizeHttpRequests((auth) -> auth | ||
.anyRequest().permitAll()); | ||
|
||
// 세션 설정 : STATELESS | ||
http | ||
.sessionManagement((session) -> session | ||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); | ||
|
||
.csrf(c -> c.disable()) | ||
.authorizeHttpRequests(c -> c | ||
.anyRequest().permitAll()) | ||
.cors(c -> c.configurationSource(request -> { | ||
CorsConfiguration config = new CorsConfiguration(); | ||
config.setAllowedOrigins(List.of("http://localhost:3000")); | ||
config.setAllowedMethods(List.of("*")); | ||
config.setAllowCredentials(true); | ||
config.setAllowedHeaders(List.of("*")); | ||
config.setMaxAge(3600L); | ||
return config; | ||
})) | ||
.headers(c -> c.frameOptions(c2 -> c2.disable())); | ||
return http.build(); | ||
} | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
src/main/java/com/meetup/teame/backend/domain/auth/jwt/JwtProperties.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.meetup.teame.backend.domain.auth.jwt; | ||
|
||
import lombok.Getter; | ||
import lombok.Setter; | ||
import org.springframework.boot.context.properties.ConfigurationProperties; | ||
import org.springframework.stereotype.Component; | ||
|
||
@Setter | ||
@Getter | ||
@Component | ||
@ConfigurationProperties("jwt") | ||
public class JwtProperties { | ||
private String issuer; | ||
private String secretKey; | ||
} |
77 changes: 77 additions & 0 deletions
77
src/main/java/com/meetup/teame/backend/domain/auth/jwt/JwtProvider.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package com.meetup.teame.backend.domain.auth.jwt; | ||
|
||
import com.meetup.teame.backend.domain.user.entity.User; | ||
import io.jsonwebtoken.Claims; | ||
import io.jsonwebtoken.Header; | ||
import io.jsonwebtoken.Jwts; | ||
import io.jsonwebtoken.SignatureAlgorithm; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | ||
import org.springframework.security.core.Authentication; | ||
import org.springframework.security.core.authority.SimpleGrantedAuthority; | ||
import org.springframework.stereotype.Service; | ||
|
||
import java.time.Duration; | ||
import java.util.Collections; | ||
import java.util.Date; | ||
import java.util.Set; | ||
|
||
@RequiredArgsConstructor | ||
@Service | ||
public class JwtProvider { | ||
|
||
private final JwtProperties jwtProperties; | ||
|
||
public String generateToken(User user, Duration expiredAt) { | ||
Date now = new Date(); | ||
return makeToken(new Date(now.getTime() + expiredAt.toMillis()), user); | ||
} | ||
|
||
//Jwt 토큰 생성 메서드 | ||
private String makeToken(Date expiry, User user) { | ||
Date now = new Date(); | ||
|
||
return Jwts.builder() | ||
.setHeaderParam(Header.TYPE, Header.JWT_TYPE) //헤더 | ||
.setIssuer(jwtProperties.getIssuer()) //내용 | ||
.setIssuedAt(now) | ||
.setExpiration(expiry) | ||
.setSubject(user.getEmail()) | ||
.claim("id",user.getId()) | ||
.signWith(SignatureAlgorithm.HS256, jwtProperties.getSecretKey()) //서명 | ||
.compact(); | ||
} | ||
|
||
//JWT 토큰 유효성 검증 메서드 | ||
public boolean validToken(String token) { | ||
try { | ||
Jwts.parser() | ||
.setSigningKey(jwtProperties.getSecretKey()) //시크릿 키로 복호화 | ||
.parseClaimsJws(token); | ||
return true; | ||
} catch (Exception e) { //복호화 중 에러 시 유효하지 않은 토큰 | ||
return false; | ||
} | ||
} | ||
|
||
//토큰 기반으로 인증 정보 가져오는 메서드 | ||
public Authentication getAuthentication(String token) { | ||
Claims claims = getClaims(token); | ||
Set<SimpleGrantedAuthority> authorities = Collections.singleton(new SimpleGrantedAuthority("ROLE_USER")); | ||
|
||
return new UsernamePasswordAuthenticationToken(new org.springframework.security.core.userdetails.User(claims.getSubject() | ||
, "", authorities), token, authorities); | ||
} | ||
|
||
public Long getUserId(String token) { | ||
Claims claims = getClaims(token); | ||
return claims.get("id", Long.class); | ||
} | ||
|
||
private Claims getClaims(String token) { | ||
return Jwts.parser() //클레임 조회 | ||
.setSigningKey(jwtProperties.getSecretKey()) | ||
.parseClaimsJws(token) | ||
.getBody(); | ||
} | ||
} |
62 changes: 62 additions & 0 deletions
62
src/main/java/com/meetup/teame/backend/domain/auth/oauth/controller/KakaoController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package com.meetup.teame.backend.domain.auth.oauth.controller; | ||
|
||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.meetup.teame.backend.domain.auth.oauth.dto.CreateOauthUserRequest; | ||
import com.meetup.teame.backend.domain.auth.oauth.dto.CreateUserRequest; | ||
import com.meetup.teame.backend.domain.auth.oauth.service.KakaoService; | ||
import com.meetup.teame.backend.domain.user.entity.Gender; | ||
import com.meetup.teame.backend.domain.user.entity.User; | ||
import com.meetup.teame.backend.domain.user.service.UserService; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.*; | ||
import org.springframework.web.bind.annotation.*; | ||
import java.util.Optional; | ||
|
||
|
||
@RequiredArgsConstructor | ||
@RestController | ||
@RequestMapping("/api") | ||
public class KakaoController { | ||
|
||
private final UserService userService; | ||
private final KakaoService kakaoService; | ||
|
||
@GetMapping("/login/kakao") | ||
public ResponseEntity<Object> kakaoLogin(@RequestParam String code) throws JsonProcessingException { | ||
String kakaoAccessToken = kakaoService.getKakaoAccessToken(code); //인가코드로 카카오 엑세스 토큰 받아오기 | ||
CreateOauthUserRequest request = kakaoService.getKakaoInfo(kakaoAccessToken); //엑세스 토큰으로 카카오 사용자 정보 받아오기 | ||
if(userExists(request.getEmail())) { //이미 가입된 회원 | ||
Optional<User> userOptional = userService.findByEmail(request.getEmail()); | ||
User user = userOptional.get(); | ||
HttpHeaders headers = kakaoService.getLoginHeader(user); | ||
|
||
return ResponseEntity.ok().headers(headers).body("login"); | ||
//로그인 처리하기 | ||
} else { //신규 회원 | ||
return ResponseEntity.ok(request); | ||
} | ||
} | ||
|
||
@PostMapping("/signup") | ||
public ResponseEntity<Object> signup(@RequestBody CreateUserRequest request) { //이미 있는 회원인지 확인해야됨 | ||
User user = User.builder() | ||
.name(request.getName()) | ||
.email(request.getEmail()) | ||
.gender(Gender.valueOf(request.getGender().toUpperCase())) | ||
.location(request.getLocation()) | ||
.build(); | ||
Long userId = userService.save(user); | ||
HttpHeaders headers = kakaoService.getLoginHeader(userService.findById(userId)); | ||
return ResponseEntity.ok().headers(headers).body("OK"); | ||
} | ||
|
||
private boolean userExists(String email) { | ||
Optional<User> userOptional = userService.findByEmail(email); | ||
if(userOptional.isPresent()) { | ||
return true; | ||
} | ||
else { | ||
return false; | ||
} | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
src/main/java/com/meetup/teame/backend/domain/auth/oauth/dto/CreateOauthUserRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.meetup.teame.backend.domain.auth.oauth.dto; | ||
|
||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import lombok.Setter; | ||
|
||
@AllArgsConstructor | ||
@NoArgsConstructor | ||
@Getter | ||
@Setter | ||
public class CreateOauthUserRequest { | ||
private String email; // 선택 동의 | ||
private String gender; // 필수 동의 | ||
private String nickname; // 필수 동의 | ||
private String name; // 필수 동의 | ||
private String birthYear; // 필수 동의 | ||
private String profileImage; // 선택 동의 | ||
} |
32 changes: 32 additions & 0 deletions
32
src/main/java/com/meetup/teame/backend/domain/auth/oauth/dto/CreateUserRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
package com.meetup.teame.backend.domain.auth.oauth.dto; | ||
|
||
import com.meetup.teame.backend.domain.user.entity.Gender; | ||
import jakarta.persistence.EnumType; | ||
import jakarta.persistence.Enumerated; | ||
import lombok.AllArgsConstructor; | ||
import lombok.Getter; | ||
import lombok.NoArgsConstructor; | ||
import org.hibernate.annotations.Comment; | ||
|
||
@AllArgsConstructor | ||
@NoArgsConstructor | ||
@Getter | ||
public class CreateUserRequest { | ||
|
||
@Comment("사용자 이름") | ||
private String name; | ||
|
||
@Comment("사용자 이미지") | ||
private String imageUrl; | ||
|
||
@Enumerated(EnumType.STRING) | ||
private Gender gender; | ||
|
||
private String location; | ||
|
||
//test | ||
private String birthyear; | ||
|
||
|
||
private String email; | ||
} |
Oops, something went wrong.