Skip to content

Commit

Permalink
google login jwt complete
Browse files Browse the repository at this point in the history
  • Loading branch information
KiSeungMin committed Jul 24, 2024
1 parent 6bdda1b commit 7f1f67e
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 37 deletions.
2 changes: 2 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ dependencies {
implementation 'com.auth0:java-jwt:4.4.0'
implementation group: 'com.google.auth', name: 'google-auth-library-oauth2-http', version: '1.23.0'
implementation group: 'com.google.http-client', name: 'google-http-client-jackson2', version: '1.44.2'
implementation group: 'org.springframework.security', name: 'spring-security-core', version: '6.3.1'
implementation 'org.springframework.boot:spring-boot-starter-security'
// Hibernate Core
implementation 'org.hibernate:hibernate-core:6.5.2.Final'
compileOnly 'org.projectlombok:lombok'
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/aisip/OnO/backend/Auth/AuthController.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ public class AuthController {
@PostMapping("/google")
public ResponseEntity<?> googleLogin(@RequestBody TokenRequest tokenRequest) {
try {
GoogleIdToken.Payload payload = googleTokenVerifier.verifyGoogleToken(tokenRequest.getIdToken());
UserEntity user = authService.registerOrLoginUser(payload);
String token = jwtTokenProvider.createToken(user.getUserId(), user.getEmail());
GoogleIdToken.Payload payload = googleTokenVerifier.verifyToken(tokenRequest.getIdToken());
UserEntity userEntity = authService.registerOrLoginUser(payload.getEmail(), (String) payload.get("name"));
String token = jwtTokenProvider.createToken(userEntity.getUserId(), userEntity.getEmail());
return ResponseEntity.ok(new AuthResponse(token));
} catch (IllegalArgumentException e) {
e.printStackTrace();
Expand Down
12 changes: 5 additions & 7 deletions src/main/java/com/aisip/OnO/backend/Auth/AuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,18 @@ public class AuthService {
@Autowired
private UserEntityRepository userEntityRepository;

public UserEntity registerOrLoginUser(GoogleIdToken.Payload payload) {
String userId = payload.getSubject();
String email = payload.getEmail();
String name = (String) payload.get("name");

public UserEntity registerOrLoginUser(String email, String name) {
UserEntity userEntity = userEntityRepository.findByEmail(email);
if (userEntity == null) {
userEntity = new UserEntity();
userEntity.setUserId(userId);
userEntity.setEmail(email);
userEntity.setName(name);
userEntityRepository.save(userEntity);
}

return userEntity;
}

public UserEntity getUserById(Long userId) {
return userEntityRepository.findById(userId).orElse(null);
}
}
43 changes: 43 additions & 0 deletions src/main/java/com/aisip/OnO/backend/Auth/AuthUserController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package com.aisip.OnO.backend.Auth;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/user")
public class AuthUserController {

@Autowired
private AuthService authService;

@GetMapping("/info")
public ResponseEntity<?> getUserInfo(Authentication authentication) {
Long userId = (Long) authentication.getPrincipal();
UserEntity userEntity = authService.getUserById(userId);
if (userEntity != null) {
return ResponseEntity.ok(userEntity);
} else {
return ResponseEntity.status(404).body(new ErrorResponse("User not found"));
}
}

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;
}
}
}
17 changes: 7 additions & 10 deletions src/main/java/com/aisip/OnO/backend/Auth/GoogleTokenVerifier.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,21 @@
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.Service;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Collections;

@Service
@Component
public class GoogleTokenVerifier {

private static String clientId;

@Value("${spring.security.oauth2.client.registration.google.client-id}")
public void setClientId(String clientId) {
GoogleTokenVerifier.clientId = clientId;
}
private String clientId; // static 제거

public GoogleIdToken.Payload verifyToken(String idTokenString) throws GeneralSecurityException, IOException {

public static GoogleIdToken.Payload verifyGoogleToken(String idTokenString) throws GeneralSecurityException, IOException {
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(new NetHttpTransport(), JacksonFactory.getDefaultInstance())
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(new NetHttpTransport(), new JacksonFactory())
.setAudience(Collections.singletonList(clientId))
.build();

Expand All @@ -33,4 +30,4 @@ public static GoogleIdToken.Payload verifyGoogleToken(String idTokenString) thro
throw new GeneralSecurityException("Invalid ID token.");
}
}
}
}
53 changes: 53 additions & 0 deletions src/main/java/com/aisip/OnO/backend/Auth/JwtTokenFilter.java
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);
}
}
34 changes: 19 additions & 15 deletions src/main/java/com/aisip/OnO/backend/Auth/JwtTokenProvider.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,33 @@
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Component;

import java.util.Date;

@Service
@Component
public class JwtTokenProvider {

private static String SECRET_KEY;

@Value("${spring.security.oauth2.client.registration.google.client-secret}")
public void setSecretKey(String SECRET_KEY) {
JwtTokenProvider.SECRET_KEY = SECRET_KEY;
}
@Value("${spring.jwt.secret}")
private String secret;

@Value("${spring.jwt.expiration}")
private long expirationTime;

private static final long EXPIRATION_TIME = 86400000; // 1 day

public String createToken(String userId, String email) {
public String createToken(Long userId, String email) {
return JWT.create()
.withSubject(userId)
.withClaim("email", email)
.withSubject(email)
.withClaim("userId", userId)
.withIssuedAt(new Date())
.withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.sign(Algorithm.HMAC512(SECRET_KEY.getBytes()));
.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 src/main/java/com/aisip/OnO/backend/Auth/SecurityConfig.java
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();
}
}
5 changes: 4 additions & 1 deletion src/main/java/com/aisip/OnO/backend/Auth/UserEntity.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.aisip.OnO.backend.Auth;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import lombok.Getter;
import lombok.Setter;
Expand All @@ -10,7 +12,8 @@
@Entity
public class UserEntity {
@Id
private String userId;
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long userId;
private String email;
private String name;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,6 @@

import org.springframework.data.jpa.repository.JpaRepository;

public interface UserEntityRepository extends JpaRepository<UserEntity, String> {
public interface UserEntityRepository extends JpaRepository<UserEntity, Long> {
UserEntity findByEmail(String email);
}

0 comments on commit 7f1f67e

Please sign in to comment.