저는 졸업프로젝트에서 깃허브를 이용해 소셜로그인을 진행하는데요. 오늘은 그 과정에 대해서 살펴보겠습니다.
초기 설정 과정
먼저, 브라우저 창에 www.github.com/settings 를 입력해줍니다.
GitHub: Let’s build from here
GitHub is where over 100 million developers shape the future of software, together. Contribute to the open source community, manage your Git repositories, review code like a pro, track bugs and fea...
github.com
그리고 왼쪽에서 OAuth Apps 를 누르고 오른쪽 위에 있는 New OAuth App 을 눌러줍니다.
위에서부터 차례대로 applicaion 이름, 홈페이지 url, callbackURL 을 입력해줍니다.
프론트와 아직 연동전이고, 벡엔드 상에서만 테스트 진행할 예정이어서 일단은 홈페이지와 콜벡 url 모두 벡엔드상 주소로 입력해줍니다!
이 부분은 후에 프론트와 연동되면 프론트 주소로 변경됩니다.
모든 정보를 입력해주고 나면 위와 같이 Client ID 와 Client secrets 를 발급받습니다. 클라이언트 아이디는 그대로 사용하면 되고, 시크릿키는 generate a new client secret 눌러서 발급받아 사용하면 됩니다.
❗️주의할 점은 시크릿은 한번 발급하고나면 admin 이더라도 다시 볼 수 없고 재발급받아 사용해야하므로 꼭! 다른 곳에 저장해두고 사용하셔야합니다! 물론.. 매번 재발급받으면 되긴합니다.. 바꿔야할 것들이 많아져서 귀찮긴 하지만..
여기까지 하면 일단 깃허브 소셜로그인을 위한 작업은 끝났습니다!!
이제는 소셜로그인의 동작과정에 대해서 살펴보겠습니다.
동작과정
일반적인 소셜로그인의 동작과정은
1. 프론트에서 깃허브로 인가코드 요청 보내기
2. 깃허브에서 프론트한테 인가코드 보내주기
3. 프론트가 벡엔드에게 인가코드 보내주기
4. 벡엔드가 인가코드로 깃허브에 엑세스토큰 요청하기
5. 깃허브가 벡엔드에게 엑세스코드 발급해주기
6. 벡엔드가 엑세스토큰으로 깃허브에 사용자 정보 요청하기
7. 깃허브가 사용자 정보 제공하기
8. 벡엔드가 프론트엔드에게 보내주기
이렇게 이루어집니다.
여기서 벡엔드인 제가 할 일은 4~8 부분입니다! 하지만 아직 프론트와 합치지 않았기 때문에 제대로 제 코드가 동작하는지 확인하기 위해서는 1~3 부분은 간단하게 해보도록 하겠습니다.
실제 코드
@GetMapping("/oauth2/redirect")
public BaseResponse<LoginResponse> githubLogin(@RequestParam String code) {
log.info("[MemberController.githubLogin]");
return new BaseResponse<>(loginService.githubLogin(code));
}
프론트엔드에게 정보를 제공해야하므로 GET 메소드로, "/oauth2/redirect" 라는 요청 주소로 컨트롤러를 작성하였습니다.
예를들어, /oauth2/redirect?code=kfjsidjlcskdj 라는 요청이 오면 뒤에 code 부분이 loginService 의 githubLogin 으로 전달됩니다.
public LoginResponse githubLogin(String code){
log.info("[LoginService.githubLogin]");
String accessToken = getAccessToken(code);
String githubId = getUserInfo(accessToken);
boolean memberStatus = checkMember(githubId);
return new LoginResponse(memberStatus,githubId);
}
먼저, 엑세스토큰을 요청하고 그 엑세스토큰으로 사용자 id 를 요청받습니다.
저는 소셜로그인을 이용한 서비스를 만들고 있기 때문에 해당 깃허브 아이디가 내 서비스의 회원가입이 되어있는 사람인가? 즉, 나의 서비스 데이터 베이스에 들어있는 사람인가? 를 확인하고 없다면 회원가입을 유도하기 위해 checkMember 라는 메소드도 포함되어 있습니다.
private String getAccessToken(String code) {
log.info("[LoginService.githubLogin.getAccessToken]");
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("https://github.com/login/oauth/access_token")
.queryParam("client_id", clientId)
.queryParam("client_secret", clientSecret)
.queryParam("code", code);
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
HttpEntity<?> entity = new HttpEntity<>(headers);
ResponseEntity<String> response = restTemplate.exchange(
builder.toUriString(),
HttpMethod.POST,
entity,
String.class
);
log.info(response.getBody());
JSONObject jsonObject = new JSONObject(response.getBody());
return jsonObject.getString("access_token"); // access_token 값만 반환
}
깃허브에서 엑세스토큰을 받을 수 있는 주소를 제공하고 있습니다!
여기에서 확인 가능합니다. client id 와 client secret, 파라미터로 받은 코드를 포함하여 요청을 보내면 엑세스토큰을 얻을 수 있습니다.
private String getUserInfo(String accessToken) {
log.info("[LoginService.githubLogin.getUserInfo]");
String userInfoUri = "https://api.github.com/user";
HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", "token " + accessToken);
HttpEntity<?> entity = new HttpEntity<>(headers);
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.exchange(
userInfoUri,
HttpMethod.GET,
entity,
String.class
);
JSONObject jsonObject = new JSONObject(response.getBody());
return jsonObject.getString("login");
}
이제는 엑세스코드까지는 받았고 엑세스코드로 실제 사용자 정보를 요청하는 부분입니다.
이것도 깃허브에서 제공하는 주소가 있습니다! userInfoUri 에 나와있는 주소로 엑세스토큰을 포함하여 보내면 사용자 정보를 얻어볼 수 있습니다.
위의 공식문서에 들어가시면 추가적인 정보를 더 요청할 수 있는 파라미터들을 제공하고 있습니다. 예를 들어서 이메일 정보까지 받고 싶다! 하면
https://github.com/login/oauth/authorize?client_id=클라이언트아이디&scope=user:email
이렇게 요청을 하시면 됩니다!!
private boolean checkMember(String githubId){
log.info("[LoginService.githubLogin.checkMember]");
boolean memberStatus = memberRepository.existsByGithubIdAndStatus(githubId, BaseStatus.ACTIVE);
return memberStatus;
}
마지막은 저의 데이터베이스에서 멤버인지 아닌지를 확인하기 위해 레포지토리에서 JPA 를 이용한 메소드를 작성하였습니다. 단순히 boolean 값을 반환해줍니다.
위와 같은 것들을 모두 작성하면
{
// 깃허브 회원이면서 linkode 회원인 경우
"code" : 1000,
"message" : "요청에 성공하였습니다.",
"result" : {
"githubId" : "linkode24",
"memberStatus" : true,
"accessToken" : "wijfksldfijc",
"refreshToken" : "iwjdfksldcsldcj"
}
}
다음과 같은 json 예시로 받아볼 수 있습니다!!
아직 레디스에 저장하는 부분은 작성되어있지 않습니다..!
끝!
'프로젝트' 카테고리의 다른 글
WebRTC offer 와 answer 가 뭐지 (0) | 2024.08.23 |
---|---|
Mediasoup 초기 시작 세팅하기 (0) | 2024.08.22 |
서버 배포 후 카카오 로그인 먹통현상.. (0) | 2024.08.01 |
소셜로그인에서 레디스(Redis) 적용하기 (0) | 2024.07.11 |
IntelliJ 랑 AWS RDS 연동하는법 (0) | 2024.05.09 |