mysql 에서는 아주 간편하게 limit 함수를 이용해서 몇개의 데이터만 가지고 왓엇는데, rownum 이라는 함수를 사용해서인지 이유는 아직 모르겟다... 아직 더 자세히 공부를 하지는 못햇다.
하지만, 일단 원하는 rownum의 범위로 검색
반응형
SELECT
*
FROM(
SELECT
sub.*,
ROWNUM AS "OFFSET"
FROM
(SELECT
WORKER_NAME AS "workerName",
WORKER_TEL AS "workerTel",
TIMELINE AS "timeline",
COMUTE_TYPE AS "commuteType",
TO_CHAR(TIMELINE, 'YYYY-MM-DD') AS "dateInfo"
FROM
ATTENDANCE_INFO
WHERE IS_STATISTICS = 0
GROUP BY TO_CHAR(TIMELINE, 'YYYY-MM-DD'), WORKER_NAME, WORKER_TEL, TIMELINE, COMUTE_TYPE
ORDER BY WORKER_NAME, TO_CHAR(TIMELINE, 'YYYY-MM-DD')
) sub)
WHERE ROWNUM <= 80
AND OFFSET >= 30;
여기서
ROWNUM을 OFFSET으로 ALIAS 로 지정해두고, WHERE 절에 사용된 ROWNUM 은 sub 에서 select된 ROWNUM 이 아닌, 맨 마지막에 SELECT * 에서 선택되어지는 ROW들의 NUM 이라고 생각하면 된다.
그리고 그 안에서의 ROWNUM 은 OFFSET으로 지정된거다. 그래서 OFFSET이라는 변수에 저런식으로 지정해주면 된다!
SELECT
sub.*,
ROWNUM AS cntnt
FROM
(SELECT
WORKER_NAME AS "workerName",
WORKER_TEL AS "workerTel",
TIMELINE AS "timeline",
COMUTE_TYPE AS "commuteType",
TO_CHAR(TIMELINE, 'YYYY-MM-DD') AS "dateInfo"
FROM
ATTENDANCE_INFO
WHERE IS_STATISTICS = 0
GROUP BY TO_CHAR(TIMELINE, 'YYYY-MM-DD'), WORKER_NAME, WORKER_TEL, TIMELINE, COMUTE_TYPE
ORDER BY WORKER_NAME, TO_CHAR(TIMELINE, 'YYYY-MM-DD')
) sub
ROWNUM이라는 컬럼을 사용하면, 순번이 row의 번호가 붙어서 나오게된다.
GROUP BY 를 활용해서 조건으로 그룹지어 조회할 수 있다. 여기서 포인트는, 만약 SUM 이런걸 원한다면 select 에 컬럼명으로 sum(원하는 합산의 컬럼명) 으로 적고 group by 조건에는 넣어주지않아도된다. 하지만 다른 표시하고싶은 컬럼들은 모두 group by 에 넣어줘야한다. (이게 mysql 과 다른점이다.)
dependencies {
implementation 'io.jsonwebtoken:jjwt-api:0.11.5'
runtimeOnly 'io.jsonwebtoken:jjwt-impl:0.11.5',
// Uncomment the next line if you want to use RSASSA-PSS (PS256, PS384, PS512) algorithms:
//'org.bouncycastle:bcprov-jdk15on:1.70',
'io.jsonwebtoken:jjwt-jackson:0.11.5' // or 'io.jsonwebtoken:jjwt-gson:0.11.5' for gson
}
여기서 잠깐! JJWT Dependencies 에 대해 초큼 알아보자
dependency의 선언을 보면, 한개만 compile-time dependency 이고, 나머지는 runtime으로 선언되어있다.
이것은, JJWT는 오직 설계한 application에 명시되어있는 APIs 에 의존하도록 설계가 되어있고, 경고 없이 변경될 수 있는 기타 모든 내부 구현 세부 정보는 runtime전용 종속성으로 분류되기 때문입니다. 이건, 만약 안정적인 JJWT사용이나 업데이트를 위해서는 매우 중요하다!
만약, jjwt-impl.jar 를 추가해서 사용한다면, jjwt에 업데이트가 있거나 수정사항이 있을 경우에 자동으로 compativility 되지 않을 거라는 경고도 되어있다. 그래서 jjwt-impl.jar 를 compile scope (implementation)에 넣지 말고 runtime scope에 넣으라고 되어있다.
반응형
2. Token 생성해보기
import java.util.Date;
import java.util.UUID;
import io.jsonwebtoken.Jwts;
public class JwtUtils {
public static String createJWT() {
Date now = new Date();
Date expiredAt = new Date(now.getTime() + 10 * 60 * 1000); // 유효시간 10분
String jwtToken = Jwts.builder()
.claim("name", "minah")
.claim("email", "mapark@abc.co.kr")
.setSubject("user")
.setId(UUID.randomUUID().toString())
.setIssuedAt(now)
.setExpiration(expiredAt)
.compact();
return jwtToken;
}
}
해석해보면,
name 에 minah를, email 에 mapark@abc.co.kr 을 각각 넣어둔것. user이라는 subject로
token의 유효시간은 10분으로해서 compact 를 해둠.
그래서 로그를 찍어보니,
이렇게 잘 찍혓다. 그러면 이제 이걸 다시 재해석... 해야지?
3. Token 재해석하여 보낸 데이터 확인
재해석을 하는 과정에서,Jwts 의 parserBuilder() 를 이용하는데, 이제 어떠한 키를 가지고 해석해내지 않으면 할 수 없다고 에러가 떳다. 그래서 key 를 지정해서 jwt 를 생성하고, 그 key 를 가지고 재해석하는 과정을 넣었다.
수정한 메서드
import java.security.Key;
import java.util.Date;
import java.util.UUID;
import javax.crypto.SecretKey;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
public class JwtUtils {
static Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
public static String createJWT() {
Date now = new Date();
Date expiredAt = new Date(now.getTime() + 10 * 60 * 1000); // 유효시간 10분
String jwtToken = Jwts.builder()
.claim("name", "minah")
.claim("email", "mapark@abcd.co.kr")
.setSubject("user")
.setId(UUID.randomUUID().toString())
.setIssuedAt(now)
.setExpiration(expiredAt)
// 지정한 key 로 sign 하겟다라는 설정
.signWith(key)
.compact();
return jwtToken;
}
public static Jws<Claims> parseJwt(String jwtString){
Jws<Claims> jwt = Jwts.parserBuilder()
.setSigningKey(key)
.build()
.parseClaimsJws(jwtString);
return jwt;
}
}
그래서 다시 확인해봤다.
parse jwtTest에, 내가 넣어두었던 name, email, sub 모두가 나왔다.
다음 글에서는 vue.js에서 로그인해서 token을 header로 보내는 과정을 구현해보겠다.
JWT를 구현하기 위해 JWT 공식사이트(https://jwt.io/libraries?language=Java)에 들어가서 확인하는 중에, 발견한 것이 Java에서 사용할 경우, 여러가지의 라이브러리가 있었는데, 내가 알아본 예제들은 대부분, io.jsonwebtoken 을 사용했거나, ,com.auth0을 사용했다. 그래서 그 둘의 차이를 알아봤다.
반응형
Auth0 이란?
이름에서도 알 수 있다시피, authentication과 authorization에 관한 application 이다.
어떤 경우에 Auth0을 사용할 수 있냐 :
- JavaScript 로 front-end app을 만들고, API의 access를 안전하게 하고 싶다면 사용 가능하다. - SAML로 접근, 권한 설정을하는 web app을 만든다. SAML (Security Assertion Markup Language) 프로토콜은 open-standard, xml-based 프레임워크 에서의 authentication 과 authorization을 비밀번호 없이 관리할 수 있다. Auth0은 SAML 을 서포트해준다. - 사용자가 비밀번호가 아닌 이메일이나 SMS 로 보내진 one-time codes로 로그인하게 하고 싶다.
여기서, Auth0을 검색할때마다 OAuth도 같이 나오는데, 차이가 뭔지 보면,
OAuth 2.0: 모든 소프트웨어(windwos, mobile 또는 web)의 인증을 위한 기준 또는 프로토콜 Auth0: OAuth 2.0 프로토콜을 사용, 구현하는 소프트웨어 상품
즉, Auth는 OAuth 의 구현체 라고 나는 이해했다.
그래서, 알아본 OAuth
OAuth 란, - google, github, 카카오톡 등 서비스에 인증을 맡기고, 접근 권한 관리만을 수행하는 인증방식
BackEnd : JWT 를 위한 Spring Security , Spring Mysql, Mybatis FrontEnd: Vuex, vee-validate
1. JWT (JSON Web Token) 란?
현재, JWT는 인증과 정보 교환에 매우 자주 사용된다. Session (Session-based Authentication)을 새로 생성하는 것 대신에, Server 가 데이터를 JSON Web Token 으로 encoding 해준 후에 Client 에게 보내준다 (3). 그러면 Client 는 JWT를 저장하고, Client 가 요청하는 모든 Request의 루트, 리소스를 보호하기 위해 JWT가 부착(4)되어있어야한다. (보통은 header에 붙어있다) 그 요청을 받은 Server는 그 JWT를 평가(5)한 후에 Response를 리턴(6)해줄 것이다.
이렇게 input 박스에 v-validate="'required|email'" 을 넣어주고, name값에 email 유효성을 봐주고 만약, 그 email 유효성에 어긋난다면, 이메일 주소를 맞게 입력해달라는 메시지를 <span> 태그에 넣어줄 것이다.
나는 span 에 class값을 주어서 빨간색으로 보이게 설정해뒀다. 그런데, 영어로 되어있으니, 한글로 바꿔보자!
vee-validate에 설정되어잇는 error message를 customize할 수 있는데, 유효성에 대한 데이터만 따로 빼고 싶어서, utils라는 폴더를 생성해 veevalidateUtils.js 파일을 따로 빼두어 main.js 에 추가해줬다.
main.js
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store";
import VeeValidate from "vee-validate";
import '@/utils/veevalidateUtils'
Vue.use(VeeValidate);
Vue.prototype.$axios = axios;
Vue.config.productionTip = false;
new Vue({
router,
store,
render: (h) => h(App),
}).$mount("#app");
여기서, 아까 말한 이메일 형식에 어긋났을때의 메시지를 수정해 줄 것이다.
veevalidateUtils.js
import {Validator} from 'vee-validate';
import {email} from 'vee-validate/dist/rules.esm' // 기본적으로 제공되는 규칙을 모아둔 파일
// 존재하는 rule의 메세지를 바꾸기위해
Validator.extend('email', {
...email,
getMessage: '이메일 형식이 아닙니다.',
})
// 새로운 rule 추가