Skip to content

Commit

Permalink
Feat: CHAT-254-BE-카카오-로그인 (#41)
Browse files Browse the repository at this point in the history
* Feat: CHAT-254-BE-카카오-로그인

* Fix: nickname으로 가입/미가입 판별

- Member에 nickname(varchar) 추가
- nickname으로 가입된 사용자인지 판별후
가입 사용자 -> jwt반환
미가입 사용자 -> 회원가입(db에 저장)후 jwt반환

* Fix: findByNickname() 추가
  • Loading branch information
dainshon authored Feb 12, 2024
1 parent 8b95fb2 commit fe3f537
Show file tree
Hide file tree
Showing 7 changed files with 270 additions and 4 deletions.
5 changes: 5 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,16 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.cloud:spring-cloud-starter-aws:2.2.6.RELEASE'
implementation 'org.springframework.boot:spring-boot-starter-websocket'
implementation 'com.google.code.gson:gson:2.8.8'
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
runtimeOnly('mysql:mysql-connector-java:8.0.30')
runtimeOnly('com.h2database:h2')

implementation 'io.jsonwebtoken:jjwt-api:0.12.3'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.12.3'
runtimeOnly 'io.jsonwebtoken:jjwt-jackson:0.12.3'
}

tasks.named('test') {
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/com/kuit/chatdiary/controller/Login/KakaoLogin.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.kuit.chatdiary.controller.Login;

import org.springframework.beans.factory.annotation.Value;

public class KakaoLogin {

@Value("${KAKAO_API_KEY}")
private String kakaoApiKey;

@Value("${KAKAO_REDIRECT_URI}")
private String kakaoRedirectUri;

@Value("${S3_BUCKET}")
private String secretKey;



}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.kuit.chatdiary.controller.Login;

import com.kuit.chatdiary.dto.login.KakaoLoginResponseDTO;
import com.kuit.chatdiary.service.LogInService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.Map;

@Controller
@RequiredArgsConstructor
@Slf4j
public class LogInController {

@Autowired
public LogInService logInService;


@GetMapping("/kakao/callback")
public KakaoLoginResponseDTO login(@RequestParam("code") String code) throws Exception {
//1. 클라이언트에서 로그인 코드를 보내줌 (서버에서 할일 X)
System.out.println("code: "+code);

//2. 토큰 받기
String accessToken = logInService.getAccessToken(code);
System.out.println("accessToken: "+accessToken);

//3. 사용자 정보 받기
Map<String, Object> userInfo = logInService.getUserInfo(accessToken);
String nickname = (String)userInfo.get("nickname");

System.out.println("nickname = " + nickname);
System.out.println("accessToken = " + accessToken);

if(nickname == null){
throw new Exception("인증되지 않은 사용자입니다");
}

String jwt = logInService.generateJwt(nickname, 3600000);
System.out.println("jwt: "+jwt);

Boolean isMember = logInService.isMember(nickname);

//가입된 사용자 -> 바로 로그인
if(isMember){
log.info("가입된 사용자입니다.");
return new KakaoLoginResponseDTO(jwt);
}else{//미가입 사용자 -> 회원가입&로그인
log.info("미가입 사용자입니다.");
logInService.saveMember(nickname);

return new KakaoLoginResponseDTO(jwt);
}


}

}
8 changes: 4 additions & 4 deletions src/main/java/com/kuit/chatdiary/domain/Member.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package com.kuit.chatdiary.domain;

import jakarta.persistence.*;
import lombok.Builder;
import lombok.Cleanup;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.*;
import org.hibernate.annotations.ColumnDefault;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
Expand All @@ -16,13 +13,16 @@

@Entity(name = "member")
@Getter
@Setter
@NoArgsConstructor
@EntityListeners(AuditingEntityListener.class)
public class Member {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY) //auto increment
@Column(name = "user_id")
private Long userId;

private String nickname;

private String email;

private String password;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.kuit.chatdiary.dto.login;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class KakaoLoginResponseDTO {
private String jwt;
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@
import org.springframework.data.jpa.repository.JpaRepository;

public interface MemberRepository extends JpaRepository<Member, Long> {
Member findByNickname(String nickname);
}
166 changes: 166 additions & 0 deletions src/main/java/com/kuit/chatdiary/service/LogInService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
package com.kuit.chatdiary.service;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.kuit.chatdiary.domain.Member;
import com.kuit.chatdiary.repository.MemberRepository;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.crypto.SecretKey;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;

@Slf4j
@Service
public class LogInService {

@Autowired
private final MemberRepository memberRepository;

@Value("${KAKAO_API_KEY}")
private String kakaoApiKey;

@Value("${KAKAO_REDIRECT_URI}")
private String kakaoRedirectUri;

public LogInService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}

// AccessToken 발급하는 메서드
public String getAccessToken(String code) {
log.info("[KakaoService.getAccessToken]");

String accessToken = "";
String reqUrl = "https://kauth.kakao.com/oauth/token";

try{
URL url = new URL(reqUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();

conn.setRequestMethod("POST");
conn.setDoOutput(true);

BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(conn.getOutputStream()));
StringBuilder sb = new StringBuilder();

sb.append("grant_type=authorization_code");
sb.append("&client_id=").append(kakaoApiKey);
sb.append("&redirect_uri=").append(kakaoRedirectUri);
sb.append("&code=").append(code);

bw.write(sb.toString());
bw.flush();

BufferedReader br;
br = new BufferedReader(new InputStreamReader(conn.getInputStream()));

String line = "";
StringBuilder responseSb = new StringBuilder();
while((line = br.readLine()) != null){
responseSb.append(line);
}
String result = responseSb.toString();
System.out.println("responseBody : "+result);

JsonParser parser = new JsonParser();
JsonElement element = parser.parse(result);
accessToken = element.getAsJsonObject().get("access_token").getAsString();

br.close();
bw.close();

}catch (Exception e){
e.printStackTrace();
}
return accessToken;
}

// 사용자 정보 가져오는 메서드
public HashMap<String, Object> getUserInfo(String accessToken) {
HashMap<String, Object> userInfo = new HashMap<>();
String reqUrl = "https://kapi.kakao.com/v2/user/me";
try{
URL url = new URL(reqUrl);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Authorization", "Bearer " + accessToken);

BufferedReader br;
br = new BufferedReader(new InputStreamReader(conn.getInputStream()));

String line = "";
StringBuilder responseSb = new StringBuilder();
while((line = br.readLine()) != null){
responseSb.append(line);
}
String result = responseSb.toString();
JsonParser parser = new JsonParser();
JsonElement element = parser.parse(result);

JsonObject properties = element.getAsJsonObject().get("properties").getAsJsonObject();
String nickname = properties.getAsJsonObject().get("nickname").getAsString();
userInfo.put("nickname", nickname);

br.close();

}catch (Exception e){
e.printStackTrace();
}
return userInfo;
}

// jwt 발급하는 메서드
public String generateJwt(String nickname, long expirationTime){

SecretKey secretKey = Keys.secretKeyFor(SignatureAlgorithm.HS256);
Date expirationDate = new Date(System.currentTimeMillis() + expirationTime);

return Jwts.builder()
.setSubject(nickname)
.setExpiration(expirationDate)
.signWith(secretKey, SignatureAlgorithm.HS256)
.compact();
}

public Boolean isMember(String nickname) {
Member member = memberRepository.findByNickname(nickname);
if(member==null){
return false;
}
return true;
}

public void saveMember(String nickname) {
//이메일, 패스워드는 막넣음
String defaultEmail = nickname+"@"+nickname;
String defaultPassword = nickname+"123";

Member member = new Member();
member.setNickname(nickname);
member.setEmail(defaultEmail);
member.setPassword(defaultPassword);

memberRepository.save(member);

if(member.getUserId() !=null){
log.info("가입 완료!");
}else{
log.info("가입 실패!");
}

}
}

0 comments on commit fe3f537

Please sign in to comment.