반응형

에러내용:

31-Mar-2023 12:22:20.414 SEVERE [ajp-nio-0.0.0.0-8009-exec-255] org.apache.catalina.core.StandardWrapperValve.invoke Servlet.service() for servlet [appServlet] in context with path [] threw exception [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
### Error updating database.  Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLNonTransientConnectionException: Could not connect to address=(host=118.67.129.190)(port=3306)(type=master) : Socket fail to connect to host:118.67.129.190, port:3306. connect timed out
### The error may exist in file [/usr/local/tomcat9/webapps/ROOT/WEB-INF/classes/mybatis/AccessHistoryMapper.xml]
### The error may involve com.app.hanbat.accessHistory.AccessHistoryDao.insertAccessHistory
### The error occurred while executing an update
### Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is java.sql.SQLNonTransientConnectionException: Could not connect to address=(host=118.67.129.190)(port=3306)(type=master) : Socket fail to connect to host:118.67.129.190, port:3306. connect timed out] with root cause
        java.net.SocketTimeoutException: connect timed out

 

 

해결>>>>>

commons-dbcp2 라이브러리를 추가하고

mybatis-context 에 validationQuery 를 value="select 1" 로 추가해준다.

기존에는 bean 이

<bean id="dataSource" class="org.springframework.jdbc.datasource.DrivermanagerDataSource"> 로 설정되어있었다. 하지만 spring 에서 제공하는 것이 아닌 apache 에서 제공하는 dbcp2를 이용해서 추가하였다.

build.gradle

compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.13'
implementation group: 'org.apache.commons', name: 'commons-dbcp2', version: '2.9.0'

 

mybatis-context.xml

<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy" />
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />

    <!-- 특정 시간마다 validationQuery를 실행 셋팅 시작 -->
    <property name="validationQuery" value="select 1"/>
</bean>

 

 

 

반응형
반응형

DB정보에 같은 IP주소를 가진 DB서버를 연동하고 war파일을 tomcat서버에 반영했더니, 위와 같은 에러가 발생했다. 접근 권한이 없다는거...

근데 같은  IP인데? 라는 생각에 그냥 접속 할 수 있지 않을까 라고 생각할 수 있지만

나의 경우는, tomcat서버 안에 DB서버가 함께 들어있었다. 같은 DB와 접속서버의 IP주소가 같은데 그 주소를 DB접속 정보에 그대로 넣엇으니, 접속 서버에서 나가서 다시 DB서버로 접속하려고하더라. 그 말은 즉슨, 

같은 서버지만, 외부로 나갔다가 다시 안으로 들어오는 것이기 때문에 결국 보안을 거치는것이엇다. DB서버는 SHOW GRANTS 로 확인해본 결과 내부에서만 접속이 가능하게 지정해뒀다. 그래서 접근 권한 없다고 하는 것이다.

반응형

그래서, war 파일에 있는 DB접속정보를

이렇게 변경해줬다. 즉 localhost 로 인식하도록 바꿔줬더니 연결이 됬다!

반응형
반응형

 

Add External Web Module

Document base에 tomcat의 root에 저장될 경로를 지정하고, web에서 src로 접근하고자하는 경로를 Path 에 적어주면 된다.

 

tomcat의 server.xml 에 Context 태그로 docBase가 알아서 수정이 되어있는걸 볼 수 있다!!!!!!

 

반응형
반응형

폴더 copy 할때의 명령어 cp 를 이용해서

cp copy하고자하는폴더명 새로운폴더명

으로 해주면 되는데, 자꾸 cp: omitting directory ‘copy하고자하는폴더명’ 이런 에러가 생기더라

이건, 자기자신을 재참조(?) 할 때, 사용한단다.

그래서 

cp -r 를 해주면 된다!

반응형
cp -r 복사원하는폴더명 복사될새로운폴더명

 

반응형
반응형

참조 : https://www.bezkoder.com/jwt-json-web-token/

1. Authentication 이란?

어떠한 웹사이트를 사용할 때, 계정을 생성하고, 어떠한 특정한 기능을 사용하기위해 로그인하여 접근해야한다. 그러한 action 을 우리는 Authentication 이라고 부른다.

 

2. Session 기반의 Authentication

그렇다면, 어떻게 계정을 인증(authenticate)  할까?

우선, 과거에 가장 많이 사용한 심플한 방법인 Session-based Authentication 을 살펴보자!!

https://www.bezkoder.com/jwt-json-web-token/

위의 사진을 보면서 설명해보자.

1. 사용자가 website에 로그인 
2. Server는 그 사용자에 대한 Session을 생성하여 저장 (in Memory or Database)
3. Server는 브라우저 Cookie 에 저장할 그 ClientSessionId를 return
Server에 있는 그 Session은 만료시간을 가지고 있음. 그 일정 시간이 지난 후, 그 Session은 만료되고 다른 Session을 생성하여 다시 로그인을 해야함

4. 로그인이 된 사Cookie 와 SessionId 의 HTTP Request는 Server로 감
5. Server는 인증을 위해 이 SessionId 와 저장된 Session을 비교한 후에
6. 적절한 Response를 return 함

 

3. Token-based Authentication이 탄생한 이유?

그런데, 우리는 왜 Token-based Authentication 을 많이 사용하는 걸까?

이유는, 우리는 website만 가지고 있는 것이 아니고, 많은 플랫폼들이 존재하기 때문이다!

가정해보자, 우리가 사용하는 website가 Session으로 잘 작동한다고 하자. 어느날, 우리가 Mobile (Navtive Apps) 에 시스템을 구축해야하고 같은 Database를 최신 Web app에 사용해야한다면 우리는 어떻게 해야할까?

우리는 Native App의 사용자를 Session을 기반으로 하는 Authentication로 인증할 수 없다. 왜냐면, Native App 과 비슷한 아이들은 Cookie가 없기 때문이다!!!!

그러면, 우리는 Native App 을 위한 Backend 프로젝트를 다시 빌드 하거나, Native App을 위한 Authentication module 을 새로 구축해야한다. 그래서 탄생 한 것이 Token-based Authentication!!!

이 방법으로, 사용자의 login 상태가 Server에 의해 JWT(JSON Web Token) 으로 encoding 되어져서 Client로 보내질 수 있다. 그래서 요즘 RESTful API들은 이것을 많이 사용한다. 그러니 이제 JWT 의 원리에 대해서 알아보자!!!

 

4. Token-based Authentication의 원리

아래의 사진과 같이 이해하기 간단하다.

JWT의 작동

Session을 생성하는 것 대신에, Server는 로그인한 사용자의 data로부터 JWT를 생성하고 Client 로 보낸다. 그 Client 는 생성된 JWT를 이제부터 저장하고 되고, 그 Client로 부터 오는 모든 Request는 모두 JWT를 (보통은 header에) 붙여서 온다. 그러면 Server는 JWT를 인증하고 Response를 return 해준다. 

https://www.bezkoder.com/jwt-json-web-token/
Client side에 JWT를 저장하는 방법은, 어떤 플랫폼을 사용하느냐에 따라 다른다.

Browser : Local Storage
IOS : Keychain
Android : SharedPreferences

 

JWT의 생성 방법

JWT 의 중요한 3가지

Header
Payload
Signature

                Header             

Header는 질문에 대답한다. 

우리가 어떻게 JWT를 계산할까?

이제, header의 예제를 살펴보자. JSON 객체는 이렇게 생겼다: 

{ "typ" : "JWT", "alg": "HS256" }

 

typ  -  'type', Token의 종류를 나타낸다. 여기서는 of course JWT
alg  -  'algorithm', Token signature 를 생성하기 위한 hash 알고리즘. 알고리즘은 Secret Key를 사용 여기서는, HMAC-SHA256 을 말한다. 

 

                   Payload                  

Payload는 우리가 대답할 수 있게 도와준다.

우리는 JWT에 무엇을 저장하고 싶지?

이제, payload는 이렇게 생겼다.

{
  "userId": "abcd1234",
  "username": "minah",
  "email": "contact@minah.com",
  // standard fields
  "iss": "park, author of minah.com",
  "iat": 4568874212,
  "exp": 4568874212
}
3가지의 저장하는 사용자 항목들 : userId , username, email
Standard Fields (선택):
iss (Issuer) - JWT 발행한사람
iat (Issued at) - JWT가 발행된 시간
exp (Expiration Time) - JWT의 만료 시간

더 많은 저장할 수 있는 항목들: https://en.wikipedia.org/wiki/JSON_Web_Token#Standard_fields

 

                   Signature                  

위에 정의한 Hash Algorithm 을 사용하는 부분!
const data = Base64UrlEncode(header) + '.' + Base64UrlEncode(payload);
const hashedData = Hash(data, secret);
const signature = Base64UrlEncode(hashedData);

1) Header 와 Payload 를 encode 하고, 그것들을 마침표 ( . ) 로 합친다.

data = '[encdoeHeader].[encodedPayload]'

2) 이제, Header에서 정의한 Hash algorithm 과 secret 문자를 활용해서 데이터의 hash 를 만든다.

3) hash한 결과물은 Signature을 얻기위해 encodeing 한다.

                   Header, Payload, Signature 을 모두 합쳐                   

JWT standard structure 에 Header, Payload, Signature을 모두 합침
const encodedHeader = base64urlEncode(header);
/* Result */
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9"
const encodedPayload = base64urlEncode(payload);
/* Result */
"eyJ1c2VySWQiOiJhYmNkMTIzNDVnaGlqayIsInVzZXJuYW1lIjoiYmV6a29kZXIiLCJlbWFpbCI6ImNvbnRhY3RAYmV6a29kZXIuY29tIn0"
const data = encodedHeader + "." + encodedPayload;
const hashedData = Hash(data, secret);
const signature = base64urlEncode(hashedData);
/* Result */
"crrCKWNGay10ZYbzNG3e0hfLKbL7ktolT7GqjUMwi3k"
// header.payload.signature
const JWT = encodedHeader + "." + encodedPayload + "." + signature;
/* Result */
"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VySWQiOiJhYmNkMTIzNDVnaGlqayIsInVzZXJuYW1lIjoiYmV6a29kZXIiLCJlbWFpbCI6ImNvbnRhY3RAYmV6a29kZXIuY29tIn0.5IN4qmZTS3LEaXCisfJQhrSyhSPXEgM1ux-qXsGKacQ"
반응형

5. JWT는 데이터를 secure 하는 방법

JWT 는 데이터를 암호화하여 보호하거나, 감추지 않는다.

단지, JWT를 생성하는 과정이 데이터를 encode하고 hash 할 뿐 암호화 하지 않는다. 그래서, JWT를 Main-in-the-middle attack으로 훔칠 수도있다. 그렇기 때문에 application 은 HTTPS encryption (암호화) 를 가지고 있어야한다.

 

6. Server가 Client 로 부터 JWT를  확인하는 방법

앞전에, Signature를 생성하는데 Secret 문자를 사용했다. 그 Secret 문자는 모든 application마다 유니크하고 안전한 server side에 보관되어 있어야한다.

Client로 부터 JWT를 받았을 때, Server는 Signature를 받아 그 Signature가 같은 알고리즘Secret문자로 hash 되었는지 확인한다. 

 

중요!!
Server로 Payload를 보낼 때, Payload정보는 숙력된 프로그래머들에 의해서 편집이나 추가가 될 수 있다. 

그러면 어째야하냐구?

Token 을 Client로 보내기전에 저장해야한다. 그럼으로써, 나중에 Client로 부터 보내진 JWT가  valid 하다는걸 보장할 수 있다.

또한, 사용자의 Token을 Server에 저장하는 것 또한 시스템으로부터 Force Logout 기능도 도울 것이다.

 

 

 

 

 

참고 사이트를 내 나름대로 번역해서 적은 것이기 때문에, 영어에 능한 사람은 맨위에 있는 참고사이트를 보는 것을 더욱 추천한다! 역시 영어가 더욱 직설적이고 심플하게 표현되다보니 이해하는게 더 쉽다.

반응형

+ Recent posts