이전 글에서 앱에서 로그인 상태 유지를 위한 방법으로 FlutterSecureStorage
를 사용하였다.
이 방법은 로그인 상태를 유지
한 것이지 클라이언트가 서버에 특정 정보를 요청할 때
적절한 권한을 가진 클라이언트가 요청한 요청인지에 대해서 권한 체크를 할 수가 없다
.
클라이언트가 GET이나 POST 요청한다고 해서 서버는 무작정 해당 정보를 접근할 수 있게하면 안된다.
서버가 인증한 클라이언트일 때
특정 정보에 요청 및 접근 할 수 있게
해야 된다.
일반적으로 로그인 권한을 인증하는 방식에는
세션 로그인
과토큰 로그인
2가지가 있다.
모바일과 웹의 환경이 달라서 로그인을 구현하기 위해서 어떻게 구현하는지 정리 해보았다.
서버에서 세션을 생성
하고클라이언트는 쿠키를 통해 세션을 유지
하는 방식이다.네이티브 앱
에는 세션이 없기 때문에 구현할 수 없다.하이브리드 앱
이라면 웹뷰
를 사용해서 100% 웹 앱 의 형태
를 지녔다면 웹뷰의 세션을 통해
IP 단위로 유지
되기 때문에 와이파이 사용 등 IP 변경이 잦은REST API 호출 시
에는 그 세션 정보가 없다
이러한 이유로 네이티브
와 하이브리드
등의 모바일에서는 세션 로그인
이 권장되지 않거나 불가능하다.
토큰 로그인
의 경우에는 클라이언트에서 서버로 로그인 요청을 하면 회원 정보를 확인한 후 AccessToken
을 발급하고 클라이언트는 서버와 통신 시에 이 토큰과 같이 정보를 담아서 요청하면 된다.AccessToken
을 탈취
당하면 대처법이 없다는 것이다.AccessToken
에 만료 기간을 두고 RefreshToken
을 통해AccessToken
을 탈취 당하더라도, 기간이 만료되면 재사용이 불가능하게 된다.RefreshToken
을 통해서만 갱신할 수 있기 때문에 안전하다.RefreshToken
또한 지속적으로 갱신해서 클라이언트에게 발급한다.JWT는 JSON Web Token의 약자로, 각 객체 사이에서 속성 정보를
JSON 데이터 구조로 표현하고 암호화를 통해 정보를 전달하는 Token을 말한다.
JWT 토큰은 다양한 프로그래밍 언어를 지원해서 Flutter에서도 활용이 가능하다.
JWT 토큰을 받으면 .
을 기준으로 Header
, Payload
, Verify Signature
순서로 들어간다.
(...)
if (user_data.password === body.password) {
const { user_id, phone_number} = user_data;
const PAYLOAD = { type: 'JWT', user_id, phone_number }; // Payload에 담을 값
const SECRET_KEY = secretKey.secretKey; // config에 담은 secret_key 정보
const OPTION = secretKey.options; // 토큰의 option값
const token = jwt.sign(PAYLOAD, SECRET_KEY, OPTION); // jwt.sign으로 3가지 인자를 token 담아 클라이언트에게 넘겨준다.
res.status(200).send({ token });
} else {
res.status(404).send('비밀번호가 일치하지 않습니다.');
}
static final storage = FlutterSecureStorage(); // 토큰 값과 로그인 유지 정보를 저장, SecureStorage 사용
(...)
Response response = await dio.post('api/user/login', data: param);
if (response.statusCode == 200) { // 로그인을 성공하면
String token = response.data['token']; // response의 token키에 담긴 값을 token 변수에 담아서
Map<String, dynamic> payload = Jwt.parseJwt(token); // 토큰 내부의 값을 Map 구조에 담는다
loginID = payload['user_id'];
var val = jsonEncode(Login('$token', '$loginID')); 토큰 값과 로그인 유지 정보를 va변수에 담는다
await storage.write( key: 'login', value: val ); // login key에 SecureStorage에 담는다
return true;
} else {
(...)
}
const authUtil = {
checkToken: async (req, res, next) => {
var token = req.headers.token;
// 토큰이 없을 경우
if (!token)
return res.json(util.fail(CODE.BAD_REQUEST, MSG.EMPTY_TOKEN));
const user = await jwt.verify(token);
// 유효기간 만료된 경우
if (user === TOKEN_EXPIRED)
return res.json(util.fail(CODE.UNAUTHORIZED, MSG.EXPIRED_TOKEN));
// 유효하지 않는 토큰인 경우
if (user === TOKEN_INVALID)
return res.json(util.fail(CODE.UNAUTHORIZED, MSG.INVALID_TOKEN));
// 유효하지 않는 id인 경우
if (user.idx === undefined)
return res.json(util.fail(CODE.UNAUTHORIZED, MSG.INVALID_TOKEN));
req.idx = user.idx;
next();
}
}
안녕하세요, 웹 사이트애서, 트래픽이 몰리거나 과부하가 걸려도, 로그인이 풀리지 않게, 작업이
가능할까요? 비용을 지불하고, 작업을 부탁드리고, 싶습니다... 전화번호는 010 8927 4588이며, 카카오톡 아이디는, kkkkyun입니다. 보신다면, 문자나 카톡 꼭 좀 부탁드리고 싶습니다..!