-
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.
Merge pull request #8 from AI-SIP/develop
구글 로그인 JWT 토큰 기능 추가
- Loading branch information
Showing
26 changed files
with
408 additions
and
322 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
33 changes: 33 additions & 0 deletions
33
src/main/java/com/aisip/OnO/backend/Auth/GoogleTokenVerifier.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,33 @@ | ||
package com.aisip.OnO.backend.Auth; | ||
|
||
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken; | ||
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier; | ||
import com.google.api.client.http.javanet.NetHttpTransport; | ||
import com.google.api.client.json.jackson2.JacksonFactory; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.io.IOException; | ||
import java.security.GeneralSecurityException; | ||
import java.util.Collections; | ||
|
||
@Component | ||
public class GoogleTokenVerifier { | ||
|
||
@Value("${spring.security.oauth2.client.registration.google.client-id}") | ||
private String clientId; // static 제거 | ||
|
||
public GoogleIdToken.Payload verifyToken(String idTokenString) throws GeneralSecurityException, IOException { | ||
|
||
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(new NetHttpTransport(), new JacksonFactory()) | ||
.setAudience(Collections.singletonList(clientId)) | ||
.build(); | ||
|
||
GoogleIdToken idToken = verifier.verify(idTokenString); | ||
if (idToken != null) { | ||
return idToken.getPayload(); | ||
} else { | ||
throw new GeneralSecurityException("Invalid ID token."); | ||
} | ||
} | ||
} |
53 changes: 53 additions & 0 deletions
53
src/main/java/com/aisip/OnO/backend/Auth/JwtTokenFilter.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,53 @@ | ||
package com.aisip.OnO.backend.Auth; | ||
|
||
import com.auth0.jwt.JWT; | ||
import com.auth0.jwt.JWTVerifier; | ||
import com.auth0.jwt.algorithms.Algorithm; | ||
import com.auth0.jwt.exceptions.JWTVerificationException; | ||
import com.auth0.jwt.interfaces.DecodedJWT; | ||
import jakarta.servlet.FilterChain; | ||
import jakarta.servlet.ServletException; | ||
import jakarta.servlet.http.HttpServletRequest; | ||
import jakarta.servlet.http.HttpServletResponse; | ||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; | ||
import org.springframework.security.core.context.SecurityContextHolder; | ||
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; | ||
import org.springframework.web.filter.OncePerRequestFilter; | ||
|
||
import java.io.IOException; | ||
import java.util.Collections; | ||
|
||
public class JwtTokenFilter extends OncePerRequestFilter { | ||
|
||
private final String secret; | ||
|
||
public JwtTokenFilter(String secret) { | ||
this.secret = secret; | ||
} | ||
|
||
@Override | ||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { | ||
String authHeader = request.getHeader("Authorization"); | ||
if (authHeader != null && authHeader.startsWith("Bearer ")) { | ||
String token = authHeader.substring(7); | ||
try { | ||
Algorithm algorithm = Algorithm.HMAC512(secret); | ||
JWTVerifier verifier = JWT.require(algorithm).build(); | ||
DecodedJWT decodedJWT = verifier.verify(token); | ||
|
||
String username = decodedJWT.getSubject(); | ||
Long userId = decodedJWT.getClaim("userId").asLong(); | ||
|
||
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userId, null, Collections.emptyList()); | ||
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); | ||
|
||
SecurityContextHolder.getContext().setAuthentication(authentication); | ||
} catch (JWTVerificationException e) { | ||
// JWT Verification failed | ||
SecurityContextHolder.clearContext(); | ||
} | ||
} | ||
|
||
filterChain.doFilter(request, response); | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
src/main/java/com/aisip/OnO/backend/Auth/JwtTokenProvider.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,35 @@ | ||
package com.aisip.OnO.backend.Auth; | ||
|
||
import com.auth0.jwt.JWT; | ||
import com.auth0.jwt.algorithms.Algorithm; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.stereotype.Component; | ||
|
||
import java.util.Date; | ||
|
||
@Component | ||
public class JwtTokenProvider { | ||
|
||
@Value("${spring.jwt.secret}") | ||
private String secret; | ||
|
||
@Value("${spring.jwt.expiration}") | ||
private long expirationTime; | ||
|
||
public String createToken(Long userId, String email) { | ||
return JWT.create() | ||
.withSubject(email) | ||
.withClaim("userId", userId) | ||
.withIssuedAt(new Date()) | ||
.withExpiresAt(new Date(System.currentTimeMillis() + expirationTime)) | ||
.sign(Algorithm.HMAC512(secret.getBytes())); | ||
} | ||
|
||
public Long getUserIdFromToken(String token) { | ||
return JWT.decode(token).getClaim("userId").asLong(); | ||
} | ||
|
||
public String getEmailFromToken(String token) { | ||
return JWT.decode(token).getSubject(); | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
src/main/java/com/aisip/OnO/backend/Auth/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 |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package com.aisip.OnO.backend.Auth; | ||
|
||
import org.springframework.beans.factory.annotation.Value; | ||
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.web.SecurityFilterChain; | ||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; | ||
|
||
@Configuration | ||
@EnableWebSecurity | ||
public class SecurityConfig { | ||
|
||
@Value("${spring.jwt.secret}") | ||
private String secret; | ||
|
||
@Bean | ||
public JwtTokenFilter jwtTokenFilter() { | ||
return new JwtTokenFilter(secret); | ||
} | ||
|
||
@Bean | ||
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { | ||
http.csrf().disable() | ||
.authorizeHttpRequests(authorizeRequests -> | ||
authorizeRequests | ||
.requestMatchers("/api/auth/**").permitAll() | ||
.anyRequest().authenticated() | ||
) | ||
.sessionManagement(sessionManagement -> | ||
sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS) | ||
) | ||
.addFilterBefore(jwtTokenFilter(), UsernamePasswordAuthenticationFilter.class); | ||
|
||
return http.build(); | ||
} | ||
} |
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
27 changes: 0 additions & 27 deletions
27
src/main/java/com/aisip/OnO/backend/Dto/User/UserRegisterDto.java
This file was deleted.
Oops, something went wrong.
95 changes: 95 additions & 0 deletions
95
src/main/java/com/aisip/OnO/backend/controller/AuthController.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,95 @@ | ||
package com.aisip.OnO.backend.controller; | ||
|
||
import com.aisip.OnO.backend.service.AuthService; | ||
import com.aisip.OnO.backend.Auth.GoogleTokenVerifier; | ||
import com.aisip.OnO.backend.Auth.JwtTokenProvider; | ||
import com.aisip.OnO.backend.entity.User; | ||
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken; | ||
import com.google.common.io.BaseEncoding; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
import java.io.IOException; | ||
import java.security.GeneralSecurityException; | ||
|
||
@RestController | ||
@RequestMapping("/api/auth") | ||
public class AuthController { | ||
|
||
@Autowired | ||
private GoogleTokenVerifier googleTokenVerifier; | ||
|
||
@Autowired | ||
private AuthService authService; | ||
|
||
@Autowired | ||
private JwtTokenProvider jwtTokenProvider; | ||
|
||
@PostMapping("/google") | ||
public ResponseEntity<?> googleLogin(@RequestBody TokenRequest tokenRequest) { | ||
try { | ||
GoogleIdToken.Payload payload = googleTokenVerifier.verifyToken(tokenRequest.getIdToken()); | ||
User user = authService.registerOrLoginUser(payload.getEmail(), (String) payload.get("name")); | ||
String token = jwtTokenProvider.createToken(user.getUserId(), user.getEmail()); | ||
return ResponseEntity.ok(new AuthResponse(token)); | ||
} catch (IllegalArgumentException e) { | ||
e.printStackTrace(); | ||
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ErrorResponse("Invalid ID token format")); | ||
} catch (BaseEncoding.DecodingException e) { | ||
e.printStackTrace(); | ||
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ErrorResponse("ID token decoding error")); | ||
} catch (GeneralSecurityException | IOException e) { | ||
e.printStackTrace(); | ||
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(new ErrorResponse("Invalid Google token")); | ||
} catch (Exception e) { | ||
e.printStackTrace(); | ||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new ErrorResponse("Internal server error")); | ||
} | ||
} | ||
|
||
public static class TokenRequest { | ||
private String idToken; | ||
|
||
public String getIdToken() { | ||
return idToken; | ||
} | ||
|
||
public void setIdToken(String idToken) { | ||
this.idToken = idToken; | ||
} | ||
} | ||
|
||
public static class AuthResponse { | ||
private String token; | ||
|
||
public AuthResponse(String token) { | ||
this.token = token; | ||
} | ||
|
||
public String getToken() { | ||
return token; | ||
} | ||
|
||
public void setToken(String token) { | ||
this.token = token; | ||
} | ||
} | ||
|
||
public static class ErrorResponse { | ||
private String error; | ||
|
||
public ErrorResponse(String error) { | ||
this.error = error; | ||
} | ||
|
||
public String getError() { | ||
return error; | ||
} | ||
|
||
public void setError(String error) { | ||
this.error = error; | ||
} | ||
} | ||
} |
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
Oops, something went wrong.