반응형



LocalDateTime 의 형식 때문에 Gson으로 JSON으로 변경시 아래의 사진 처럼 Data가 Deserialize 하게 나온다.



처음엔 Gson 때문인지 몰랐고 jackson-datatype-jsr310 이거 때문인 줄 알아, 정말 쌩고생을 했음에도 불구하고 안되다가

혹시나 해서 LocalDateTime 형식 때문에 Json으로 변경시 이상하게 되는가 싶어 확인했다가 정말로 Gson때문인 걸 알게되었다.

이유는 아마도 LocalDateTime 형식에서 2019-01-06T00:24:38 가운데 T 때문에 Gson에서 자동으로 위의 사진처럼 date와 time으로

나누어 주는 것 같다.



1. JPA를 사용할 것이고, DB의 날짜 형식은 TimeStamp를 사용한다. 일단 Converter를 만들어야 한다. Spring boot에서의 JPA는 2.1을 사용하기 때문에 JPA 2.1은 Java8에서의 LocalDateTime을 지원하지 않기 때문에 Converter를 만든다. 


Converter를 만드는 법은 아래와 같이 어노테이션을 추가하거나


@SpringBootApplication
@EntityScan(basePackageClasses = {Application.class, Jsr310JpaConverters.class} )
public class Application {

  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }
}


아래와 같이 직접 만든다.


import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;

@Converter(autoApply = true)
public class DateConverter implements AttributeConverter<LocalDateTime, Timestamp> {
	@Override
	public Timestamp convertToDatabaseColumn(LocalDateTime locDateTime) {
		return (locDateTime == null ? null : Timestamp.valueOf(locDateTime));
	}

	@Override
	public LocalDateTime convertToEntityAttribute(Timestamp sqlTimestamp) {
		
		return (sqlTimestamp == null ? null : sqlTimestamp.toLocalDateTime());
	}
}


2. 만들었으면 데이터베이스를 통해 Date를 가져오는 것은 문제 없이 작동된다.

하지만 값을 찍어보면 Deserialize 하게 나온다. Gson을 사용하지 않고 순수하게 값만 가져올 경우는 이제

pom.xml에 아래의 maven을 추가한 뒤


       

			com.fasterxml.jackson.datatype
			jackson-datatype-jsr310
 

application.properties에 아래처럼 추가하면 Deserialize 하게 나오던 값이 serialize 나온다.

spring.jackson.serialization.write-dates-as-timestamps=false

하지만 우리가 할 것은 Gson을 통해 변경하는 것이기 때문에 위와 같이 하여도 아무런 변화를 느끼지 못할 것이다.


3. 이제 Gson을 통해 변경하기 위해 클래스를 생성한다.


import java.lang.reflect.Type;
import java.time.LocalDateTime;

import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

public class GsonConfig implements JsonSerializer<localdatetime>{

	@Override
	public JsonElement serialize(LocalDateTime date, Type type, JsonSerializationContext json) {
		// TODO Auto-generated method stub
		return new JsonPrimitive(date.toString());
	}

}


그리고 이제 Gson을 사용시 아래처럼 사용한다.


Gson gson = new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new GsonConfig()).create();
String jsonString = gson.toJson("변경할 값");

4. 이렇게 하면 2019-01-06T00:24:38 가운데 T 때문에 맨위의 사진처럼  Deserialize 나온 값이

 아래의 사진처럼  Serialize하게 나온다.


반응형
반응형

 

Node.js에서 google oauth 인증하는 방법이다. 

passport를 사용하는 방법이 있지만 passport는 사용해보니 무조건 session을 이용해야 했다.(아닐 수도 있음.)

이 글은 passport를 사용하지 않는 방법이다.

 

1.passport를 사용한 google oauth 인증

2019/03/11 - [Develop/Node.js] - [Node.js] google oatuh passport

 

 

 

프로젝트는 아래의 글을 사용했다. (순수 express 설치하는 글임)

2019/01/06 - [Develop/Node.js] - [Node.js] Express 설치(Windows)

 

1. googleapis 를 설치한다

npm install googleapis --save

2. google cloud console에서 .json파일을 받는다.

 

받은 파일을 아래와 같이 config 폴더에 넣어 google.json으로 변경한다.

 

 

 

3. server.js 파일에 아래와 같이 추가한다.

 

install 한 googleapis를 불러오고 .json 파일에서 client_id와 secret, redirect_uri를 불러온다.

const { google } = require('googleapis'); var googleClient = require('./config/google.json');  const googleConfig = {   clientId: googleClient.web.client_id,   clientSecret: googleClient.web.client_secret,   redirect: googleClient.web.redirect_uris[0] }; 

사용할 scopes를 입력하고, OAuth2.0에 실질적으로 연결할 정보들을 다시 연결한다. 

scope는 아래 API라이브러리에서 본인이 사용하고 싶은 api를 보고 가져오면된다.

여기서는 google api + 를 이용할 예정이다.

 

 

const scopes = [   'https://www.googleapis.com/auth/plus.me' ];   const oauth2Client = new google.auth.OAuth2(   googleConfig.clientId,   googleConfig.clientSecret,   googleConfig.redirect ); 

로그인 url을 받아오기 위한 정보를 입력한다. 

access_type에는 online과 offline이 있는데 offline으로 해야 제일 처음 로그인 했을 때 refresh_token을 받아온다.

(refresh_token은 항상 제일 처음 로그인할 때 가져온다 그러므로 다시 가져오고 싶으면 https://myaccount.google.com/permissions 에서 액세스된 어플리케이션을 해제해야 한다.)

 

scope는 위에 입력한 scope들을 가져온다. 지금처럼 scope하나만 가져올경우 

scope : 'https://www.googleapis.com/auth/plus.me' 바로 적어도 된다. 하지만 여러 scope를 가져올 경우 위에 처럼 배열을 하나 만들어

여러 scope들을 사용할 수 있다.

그리고 google+ api를 사용하기 위해 google+ api에 대한 정보를 입력한다.

const url = oauth2Client.generateAuthUrl({      access_type: 'offline',       scope: scopes });  function getGooglePlusApi(auth) {   return google.plus({ version: 'v1', auth }); } 

실질적으로 로그인해서 정보를 불러올 코드를 작성한다. 

간단하게 리프레시토큰, 액세스토큰, displayName과 id를 얻어와본다.

async function googleLogin(code) {   const { tokens } = await oauth2Client.getToken(code);   oauth2Client.setCredentials(tokens);   oauth2Client.on('tokens', (token) => {     if(tokens.refresh_token){       console.log("리프레시 토큰 :", tokens.refresh_token);     }     console.log("액세스 토큰:", tokens.access_token);   });   const plus = getGooglePlusApi(oauth2Client);   const res = await plus.people.get({ userId: 'me' });   console.log(`Hello ${res.data.displayName}! ${res.data.id}`);   return res.data.displayName; }

4. login할 주소와 로그인이 되었을 경우 실행될 callback 주소를 작성한다.

로그인할 주소는 아까 로그인 할 url 받아올 url변수의 정보를 redirect 시키고

callback 주소는 google.json의 redirect 주소를 적으면 된다.

그리고 로그인이 성공했을 경우 돌아올 redircet주소를 적는다. 

 

app.get('/login', function (req, res) {   res.redirect(url); });  app.get("/auth/google/callback", async function (req, res) {    const displayName = await googleLogin(req.query.code);   console.log(displayName);    res.redirect("http://localhost:3000"); });  

5. 실행한다.

 

 

localhost:3000/login 으로 들어간다.

 

 

 

localhost:3000/login 으로 들어가면 아까 url 을 통해 아래의 사진으로 연결된다.

 

이제 아이디를 쳐서 로그인하면 아까 입력한 scope에 따라 권한을 받게되고 이후 성공하면 redirect 시킨 home으로 돌아온다.

 

 

그리고 console을 확인해보면 현재 액세스토큰과 displayName, id가 나왔다.

리프레시토큰은 전에 로그인을 한번해서(시험 삼아 한번 해봄). 안나왔지만, 제일 처음 로그인을 했다면 리프레시토큰 또한 나올 것이다.

(리프레시토큰은 제일 처음 한번만 발급된다.)

 

 

6. 전체코드

 

 

var express = require('express'); var app = express();  const { google } = require('googleapis'); var googleClient = require('./config/google.json');  const googleConfig = {   clientId: googleClient.web.client_id,   clientSecret: googleClient.web.client_secret,   redirect: googleClient.web.redirect_uris[0] };  const scopes = [   'https://www.googleapis.com/auth/plus.me' ];  const oauth2Client = new google.auth.OAuth2(   googleConfig.clientId,   googleConfig.clientSecret,   googleConfig.redirect );  const url = oauth2Client.generateAuthUrl({    access_type: 'offline',    scope: scopes });  function getGooglePlusApi(auth) {   return google.plus({ version: 'v1', auth }); }  async function googleLogin(code) {   const { tokens } = await oauth2Client.getToken(code);   oauth2Client.setCredentials(tokens);   oauth2Client.on('tokens', (tokens) => {     if(tokens.refresh_token){       console.log("리프레시 토큰 :", tokens.refresh_token);     }     console.log("액세스 토큰:", tokens.access_token);   });   const plus = getGooglePlusApi(oauth2Client);   const res = await plus.people.get({ userId: 'me' });   console.log(`Hello ${res.data.displayName}! ${res.data.id}`);   return res.data.displayName; }  app.get('/login', function (req, res) {   res.redirect(url); });  app.get("/auth/google/callback", async function (req, res) {    const displayName = await googleLogin(req.query.code);   console.log(displayName);    res.redirect("http://localhost:3000"); });    app.get('/', function (req, res) {   res.send('Hello World!');   console.log("로그인 해서 홈으로 돌아옴");  });  app.listen(3000, function () {   console.log('Example app listening on port 3000!'); }); 

 

 

 

참고 : 

 

https://www.npmjs.com/package/googleapis

 

반응형
반응형

 

 

Node.js에서 Jwt token을 생성하고 검증하는 방법이다. Jwt토큰을 이용하면 사용자인증을 처리할 수 있으므로 주로 로그인 인증방식에 사용한다.

 

먼저 프로젝트 생성은 아래글의 프로젝트를 사용하였다.(내용은 길지 않음.)

2019/01/06 - [Develop/Node.js] - [Node.js] Express 설치(Windows)

 

 

1. Node.js에서 jwt를 사용하기 위해 jsonwebtoken을 설치한다

 

npm install jsonwebtoken --save

 

2. 설치하였으면 프로젝트에 require("jsonwebtoken")을 추가한다.

 

 

 

3. jwt.sgin()을 이용하여 생성.

 

 

sign() 이라는 함수를 이용하여 jwt를 생성한다.

Private clain에 key가 test, value가 test인 데이터를 입력하였고

Signature 자리엔 secretKey라는 데이터를 입력하였다.

Public Claim 자리엔 subject(토큰제목)와 expiresIn(만료시간), issuer(발급자) 데이터를 입력하였다.

 

sign() 함수의 default 알고리즘으로 HMAC SHA256 알고리즘을 사용한다.

 

 

4. token 을 불러와서 검증해본다.

 

 

위의 터미널에서 생성된 토큰(eyJh 로 시작)을 복사한 후 https://jwt.io/ 들어가서 아래와 같이 검증해본다.

 

먼저 키 입력자리에 jwt 생성한키 (secretKey) 를 입력한다.

 

 

입력 후 복사한 token을 붙여넣으면 Signature Verified를 볼 수 있으며,

PayLoad 자리에 iat(생성시간), exp(만료시간), iss(발급자), sub(제목)를 볼 수 있다.

 

 

5. 이제 nodejs에서 verify라는 함수를 사용해 검증해본다.

 

 

jwt.verify( 발급받은 token, 생성할때 사용한 비밀키, 옵션(없어도 됨) )을 입력하여  검증하고

검증된다면 PayLoad의 Private Claim 값을 불러올 수 있다. 

 

 

검증에 성공된다면 아래와 같이 위에서 입력한 Private Claim 값인 test를 불러 올 수 있다.

 

 

 

만약 비밀키가 틀리거나, 만료시간이 지날경우 catch단에서 에러를 잡고 에러의 이유를 출력해준다.

 

※ 비밀키는 주로 config 폴더를 만들어서 config.json 파일을 따로 생성하여 그 곳에 집어넣고 생성과 검증할 때 그곳에서 비밀키를 불러와서 사용한다.

git을 사용할 경우 gitignore를 통해 config.json파일을 ignore 시켜준다.

 

아래의 레퍼런스 사이트에 접속하면 함수의 옵션들과 에러가 날 경우 어떤 에러가 발생하는지 확인할 수 있다.

참고 : 

https://github.com/auth0/node-jsonwebtoken

 

반응형

+ Recent posts