<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.5">Jekyll</generator><link href="https://m2316.github.io/feed.xml" rel="self" type="application/atom+xml" /><link href="https://m2316.github.io/" rel="alternate" type="text/html" /><updated>2024-05-20T14:10:50+00:00</updated><id>https://m2316.github.io/feed.xml</id><title type="html">Site Title</title><subtitle>An amazing website.</subtitle><author><name>Your Name</name></author><entry><title type="html">Oauth_구글로_로그인_하기 실습</title><link href="https://m2316.github.io/OAuth_%EA%B5%AC%EA%B8%80%EB%A1%9C_%EB%A1%9C%EA%B7%B8%EC%9D%B8_%ED%95%98%EA%B8%B0-%EC%8B%A4%EC%8A%B5/" rel="alternate" type="text/html" title="Oauth_구글로_로그인_하기 실습" /><published>2024-05-10T00:00:00+00:00</published><updated>2024-05-10T00:00:00+00:00</updated><id>https://m2316.github.io/OAuth_%EA%B5%AC%EA%B8%80%EB%A1%9C_%EB%A1%9C%EA%B7%B8%EC%9D%B8_%ED%95%98%EA%B8%B0%20-%20%EC%8B%A4%EC%8A%B5</id><content type="html" xml:base="https://m2316.github.io/OAuth_%EA%B5%AC%EA%B8%80%EB%A1%9C_%EB%A1%9C%EA%B7%B8%EC%9D%B8_%ED%95%98%EA%B8%B0-%EC%8B%A4%EC%8A%B5/"><![CDATA[<h1 id="구글로-로그인하기">구글로 로그인하기</h1>
<p><br />
<br /><br /><br /><br /></p>

<hr />

<h2 id="1google-api-토큰-발급받기">1.GOOGLE API 토큰 발급받기</h2>

<ol>
  <li><strong>구글 클라우드로 접속해 토큰 발급 신청</strong>
    <ul>
      <li>https://cloud.google.com/ 접속
<br />
<br /><br />
<br /></li>
    </ul>
  </li>
  <li>
    <p><strong>콘솔 클릭</strong>
 <img src="..\images\2024-05-10-OAuth_구글로_로그인_하기 - 실습\google-콘솔-클릭.png" alt="image" />
     <strong>※구글 콘솔 동의 여부 확인창이 나오면 동의 해주고 넘어간다※</strong>
<br />
<br /><br />
<br /></p>
  </li>
  <li>
    <p><strong>새로운 프로젝트 생성</strong>
 <img src="..\images\2024-05-10-OAuth_구글로_로그인_하기 - 실습\콘솔에_프로젝트_생성.png" alt="image" />
 <br />
<br /><br />
<br /></p>
  </li>
  <li><strong>신규로 만든 프로젝트를 선택해 신규 프로젝트로 이동</strong></li>
  <li><strong>좌측 햄버거 메뉴에서 API 및 서비스 -&gt; 사용자 인증 정보 버튼 클릭</strong>
    <ol>
      <li>API 및 서비스가 안보인 다면 솔루션 -&gt;  모든 제품 보기 클릭</li>
    </ol>
  </li>
  <li><strong>좌측 메뉴에서 OAuth 동의 화면 클릭</strong></li>
  <li><strong>User Type을 외부로 선택하고 만들기 클릭</strong></li>
  <li><strong>앱 정보를 등록하고 저장</strong></li>
  <li><strong>범위 추가 또는 삭제를 이용하여 공개 범위 지정 후 업데이트</strong>
    <ol>
      <li>예제에서는 이메일과 openid 2가지선택하면 됨</li>
      <li><img src="..\images\2024-05-10-OAuth_구글로_로그인_하기 - 실습\정보_공개범위_지정.png" alt="image" /></li>
      <li>저장</li>
    </ol>
  </li>
  <li><strong>테스트 사용자 지정은 하지않고 바로 넘어감</strong></li>
  <li><strong>데쉬보드로 돌아가기 클릭</strong></li>
  <li><strong>좌측 메뉴에서 “사용자 인증 정보” 클릭</strong></li>
  <li><strong>상단의 사용자 인증 정보 만들기 &gt; OAuth 클라이언트 ID 클릭</strong></li>
  <li><strong>애플리케이션 유형 선택</strong> =&gt; 웹 애플리케이션</li>
  <li>이름 =&gt; 프로젝트 도메인 네임</li>
  <li>승인된 리디렉션 URI 입력 =&gt; http://localhost:8080/login/oauth2/code/google</li>
  <li>만들기 클릭
<br /><br /><br /><br /><br /><br /><br />
    <h2 id="java-source-code-수정">JAVA Source Code 수정</h2>
    <p><br /><br /><br /><br /></p>
    <h3 id="applicationyml-파일에-아래-내용-추가">application.yml 파일에 아래 내용 추가</h3>
    <div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">spring</span><span class="pi">:</span>
<span class="na">cecurity</span><span class="pi">:</span>
    <span class="na">oauth2</span><span class="pi">:</span>
        <span class="na">client</span><span class="pi">:</span>
            <span class="na">registration</span><span class="pi">:</span>
                <span class="na">google</span><span class="pi">:</span>
                    <span class="na">client-id</span><span class="pi">:</span> <span class="s">&lt;클라이언트ID 발급시 나온 클라이언트 ID&gt;</span>
                    <span class="na">client-secret</span><span class="pi">:</span> <span class="s">&lt;클라이언트 보안 비밀번호&gt;</span>
                    <span class="na">scope</span><span class="pi">:</span>
                        <span class="pi">-</span> <span class="s">email</span>
                        <span class="pi">-</span> <span class="s">profile</span>
</code></pre></div>    </div>
    <h3 id="-인증키는-외부에-공유되지-않도록-주의-">** 인증키는 외부에 공유되지 않도록 주의!!! **</h3>
  </li>
</ol>

<p><br />
<br /></p>
<ol>
  <li>OAuth2 의존성 추가를 위해 Build.gradle 수정
    <pre><code class="language-build.gradle">dependencies {
...생량...
 // OAuth2를 사용하기 위한 스타터 추가
 implementation 'org.springframework.boot:spring-boot-starter-oauth2-client'
}
</code></pre>
  </li>
  <li>쿠리 관리 클래스 구현하기</li>
  <li>util 패키지를 새로 만들고 CokkieUtil.java 파일을 생성</li>
  <li>config 패키지에 oauth 패키지를 만들고 OAuth2UserCustomService.java 파일 생성</li>
  <li>WebSecurityConfig.java 파일 삭제
 ※해당 파일은 기존의 로그인_예제_실습 포스팅을 보시고 따라했으면 파일 삭제 필요함※</li>
  <li>config &gt; oauth 패키지 안에 OAuth2AuthorizationRequestBasedOnCookieRepository.java 파일 생성</li>
  <li>config &gt; oauth 패키지 안에 OAuth2SuccessHandler.java 파일 생성</li>
  <li><a href="https://developers.google.com/identity/branding-guidelines?hl=ko">버튼 이미지 다운로드</a>
링크로 접속하여 구글 로그인 버튼 이미지 파일 다운로드</li>
  <li>파일 안에 png파일 중 마음에 드는 디자인을 선택해 /resources/static/img 디렉터리에 복사하기
    <ol>
      <li>복사 후에 파일명을 google.png로 변경</li>
    </ol>
  </li>
  <li>templates 디렉터리에 oauthLogin.html  생성</li>
  <li>resources/static/js 디렉터리에 token.js 파일 생성</li>
  <li></li>
</ol>]]></content><author><name>Your Name</name></author><summary type="html"><![CDATA[구글로 로그인하기]]></summary></entry><entry><title type="html">Oauth_구글로_로그인_하기 이론</title><link href="https://m2316.github.io/OAuth_%EA%B5%AC%EA%B8%80%EB%A1%9C_%EB%A1%9C%EA%B7%B8%EC%9D%B8_%ED%95%98%EA%B8%B0-%EC%9D%B4%EB%A1%A0/" rel="alternate" type="text/html" title="Oauth_구글로_로그인_하기 이론" /><published>2024-05-10T00:00:00+00:00</published><updated>2024-05-10T00:00:00+00:00</updated><id>https://m2316.github.io/OAuth_%EA%B5%AC%EA%B8%80%EB%A1%9C_%EB%A1%9C%EA%B7%B8%EC%9D%B8_%ED%95%98%EA%B8%B0%20-%20%EC%9D%B4%EB%A1%A0</id><content type="html" xml:base="https://m2316.github.io/OAuth_%EA%B5%AC%EA%B8%80%EB%A1%9C_%EB%A1%9C%EA%B7%B8%EC%9D%B8_%ED%95%98%EA%B8%B0-%EC%9D%B4%EB%A1%A0/"><![CDATA[<h1 id="구글로-로그인하기---권한-부여-코드-승인-타입">구글로 로그인하기 - 권한 부여 코드 승인 타입</h1>
<p><br /><br /><br /><br /><br /></p>
<h2 id="oauth란">OAuth란?</h2>
<hr />
<blockquote>
  <p>제 3의 서비스에 계정 관리를 맡기는 방식을 말한다.
우리가 자주 사용하는 네이버 로그인, 카카오 로그인, 구글 로그인 등을 이용하여 로그인 하는 방식을 말한다.</p>
</blockquote>

<p><br /><br /><br /><br /></p>

<h3 id="관련용어">관련용어</h3>
<p><br /></p>
<blockquote>
  <p>리소스 오너 (Resource Owner) 
인증 서버에 자신의 정보를 사용하도록 허가하는 주체.
서비스를 이용하는 사용자가 해당 됨</p>
</blockquote>

<blockquote>
  <p>리소스 서버 (Resource Server)
리소스 오너의 정보를 가지며, 리소스 오너의 정보를 보호하는 주체.
네이버, 구글, 페이스북이 해당 됨</p>
</blockquote>

<blockquote>
  <p>인증 서버 (Authorization Server)
사용자에게 리소스 오너의 정보에 접근할 수 있는 토큰을 발급하는 역할을 하는 애플리케이션을 의미함</p>
</blockquote>

<blockquote>
  <p>클라이언트 애플리케이션 (Client Application)
인증 서버에게 인증을 받고 리소스 오너의 리소스를 사용하는 주체.
개발자가 만들고 잇는 서비스에 해당 됨</p>
</blockquote>

<h3 id="리소스-오너-정보를-취득하는-방법-4가지">리소스 오너 정보를 취득하는 방법 4가지</h3>

<h4 id="1-권한-부여-코드-승인-타입">1. 권한 부여 코드 승인 타입</h4>
<p><strong>Authorization Code Grant type</strong>
<br />
	OAuth 2.0에서 가장 잘 알려진 인증 방법이다.
	클라이언트가 리소스에 접근하는 데 사용하며, 권한에 접근할 수 있는 코드와 리소스오너에 대한 액세스 토큰을 발급받는 방식이다.
<br /></p>

<h4 id="2-암시적-승인-타입">2. 암시적 승인 타입</h4>
<p><strong>Implicit Grant Type</strong>
<br />
	서버가 없는 자바스크립트 웹 애플리케이션 클라이언트에서 주로 사용하는 방법이다.
	클라이언트가 요청을 보내면 리소스오너의 인증 과정 이외에는 권한 코드 교환 등의 별다른 인증 과정을 거치지 않고 액세스 토큰을 제공 받는 방식이다.</p>

<p><br /></p>
<h4 id="3-리소스-소유자-암호-자격증명-승인-타입">3. 리소스 소유자 암호 자격증명 승인 타입</h4>
<p><strong>Resource Owner Password Credentials</strong>
<br />
	클라이언트의 패스워드를 이용해서 액세스 토큰에 대한 사용자의 자격 증명을 교환하는 방식이다.</p>

<p><br /></p>
<h4 id="4-클라이언트-자격증명-승인-타입">4. 클라이언트 자격증명 승인 타입</h4>
<p><strong>Client Credentials Grant</strong>
<br />
	클라이언트가 컨텍스트 외부에서 액세스 토큰을 얻어 특정 리소스에 접근을 요청할 때 사용하는 방식이다.
<br />
<br />
<br /></p>
<h3 id="권한-부여-코드-승인-타입">권한 부여 코드 승인 타입</h3>
<blockquote>
  <p>Oauth 2.0에서 가장 잘 알려진 인증 방식인 <strong>권한 부여 코드 승인 타입</strong>을 살펴볼 예정이다!</p>
</blockquote>

<h4 id="동작-방법">동작 방법</h4>
<p><img src="..\images\2024-05-10-OAuth_구글로_로그인_하기\OAuth-작동방식.png" alt="image" /></p>

<h4 id="스프링-부트-서버가-권한-서버로-보내는-요청">스프링 부트 서버가 권한 서버로 보내는 요청</h4>
<p>``` API Request
GET https://권한서버uri/authorize?
	client_id=3r3f323&amp;
	redirect_uri=https://localhost/myapp&amp;
	response_type=code&amp;
	scope=profile</p>
<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
- client_id
	인증 서버가 클라이언트에 할당한 고유 식별자.
	OAuth 서비스에 등록할 때 서비스에서 생성하는 값
- redirect_uri
	로그인 성공 시 이동해야 하는 URI
- response_type
	클라이언트가 제공받길 원하는 응답 타입
	인증 코드를 받을 때는 code 값을 포함해야 한다
- scope
	제공받고자 하는 리소스 오너의 정보 목록


#### 추가 설명
**데이터 접근용 권한 부여 **
- 인증 서버에 요청을 처음 보내는 경우 사용자에게 보이는 페이지를 로그인 페이지로 변경하고 사용자의 데이터에 접근 동의를 얻는다.
- 최초 1회만 진행되며 이후에는 인증 서버에서 동의 내용을 정하고 있기 때문에 로그인만 진행함.
- 로그인이 성공되면 권한 부여 서버는 데이터에 접근할 수 있게 인증 및 권한 부여를 수신함.

**인증 코드 제공**
- 사용자가 로그인에 성공하면 권한 요청 시에 파라미터로 보낸 redirect_uri로 리다이렉션되며 이때 파라미터에 인증 코드를 함께 전달 받을 수 있음
	&gt; **EX)**
	 GET : http://localhost:8080/myapp?code=ekw9fk3290wl1 

**액세스 토큰 응답이란?**
- 인증 코드를 받으면 액세스 토큰으로 교환해야 하는데 액세스 토큰은 로그인 세션에 대한 보안 자격을 증명하는 식별 코드를 의미한다.
- 대체로 POST로 요청을 보냄
``` API Request
POST https://권한서버uri/token?
	{
		"client_id" : "3r3f323",
		"client_secret": "aabb11dd44",
		"redirect_uri" : "https://localhost/myapp",
		"grant_type" : "authorization_code",
		"code" : "a23dn231d3i312"
	}
</code></pre></div></div>

<p>“client_secret” = OAuth 서비스에 등록할 때 제공받는 비밀키
“grant_type” = 권한 유형을 확인하는 데 사용함</p>

<p><strong>액세스 토큰 응답 값 예시</strong></p>
<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
	</span><span class="nl">"access_token"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"ffddeep"</span><span class="p">,</span><span class="w">
	</span><span class="nl">"token_type"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"Bearer"</span><span class="p">,</span><span class="w">
	</span><span class="nl">"expires_in"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">3600</span><span class="p">,</span><span class="w">
	</span><span class="nl">"scope"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"openid profile"</span><span class="w">
	</span><span class="err">...생략...</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p><strong>액세스 토큰으로 API 응답 &amp; 반환</strong>
요청을 통해 response로 제공받은 액세스 토큰으로 리소스 오너의 정보를 가져올 수 있다.
정보가 필요할 때마다 API 호출을 통해 정보를 가져오고 리소스 서버는 토큰이 유효한지 검사한 뒤에 응답한다.</p>

<h4 id="리소스-오너의-정보를-가져오는-요청-예시">리소스 오너의 정보를 가져오는 요청 예시</h4>
<p>``` API Request
GET https://권한서버uri/userinfo</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>header : Authorization: Bearer ffddeep
</code></pre></div></div>

<p>```</p>

<h1 id="참고">참고</h1>
<ul>
  <li>스프링 부트 3 백앤드 개발자 되기 : 자바 편 (2판)</li>
</ul>]]></content><author><name>Your Name</name></author><summary type="html"><![CDATA[구글로 로그인하기 - 권한 부여 코드 승인 타입 OAuth란? 제 3의 서비스에 계정 관리를 맡기는 방식을 말한다. 우리가 자주 사용하는 네이버 로그인, 카카오 로그인, 구글 로그인 등을 이용하여 로그인 하는 방식을 말한다.]]></summary></entry><entry><title type="html">로그인 예제 실습</title><link href="https://m2316.github.io/%EB%A1%9C%EA%B7%B8%EC%9D%B8_-%EC%98%88%EC%A0%9C_%EC%8B%A4%EC%8A%B5/" rel="alternate" type="text/html" title="로그인 예제 실습" /><published>2024-05-07T00:00:00+00:00</published><updated>2024-05-07T00:00:00+00:00</updated><id>https://m2316.github.io/%EB%A1%9C%EA%B7%B8%EC%9D%B8_%20%EC%98%88%EC%A0%9C_%EC%8B%A4%EC%8A%B5</id><content type="html" xml:base="https://m2316.github.io/%EB%A1%9C%EA%B7%B8%EC%9D%B8_-%EC%98%88%EC%A0%9C_%EC%8B%A4%EC%8A%B5/"><![CDATA[<h1 id="로그인-회원가입-실습">로그인, 회원가입 실습</h1>

<p><br />
<br />
<br /></p>

<blockquote>
  <h2 id="git-repository">Git Repository</h2>
  <p>https://github.com/M2316/jap-and-oauth-example.git
—</p>
</blockquote>

<p><br />
<br />
<br /></p>

<h2 id="로그인-기능-만드는-순서">로그인 기능 만드는 순서</h2>
<ol>
  <li>domain 패키지에 User Entity 생성 [User.java]</li>
  <li>repository 패키지에 User Repository 생성 [UserRepository.java]
    <ol>
      <li>findByEmail 메서드 추가</li>
    </ol>
  </li>
  <li>service 패키지에 UserDetail Service 생성 [userDetailService.java]
    <ol>
      <li>Security의 UserDetailService 인터페이스를 상속받기</li>
    </ol>
  </li>
  <li>Config 패키지에 WebSecurityConfig 생성 [WebSecurityConfig.java]</li>
</ol>

<p><br />
<br /></p>

<h2 id="회원가입-기능-만드는-순서">회원가입 기능 만드는 순서</h2>
<ol>
  <li>dto 패키지에 AddUserRequest 생성 [AddUserRequest.java]</li>
  <li>service 패키지에 UserService 생성 [UserService.java]
    <ol>
      <li>save 메서드 정의</li>
    </ol>
  </li>
  <li>controller 패키지에 UserApiController 생성 [UserApiController.java]
    <ol>
      <li>PostMapping signup메서드 추가</li>
    </ol>
  </li>
  <li>controller 패키지에 UserViewController 생성 [UserViewController.java]
    <ol>
      <li>GetMapping login메서드 구성</li>
      <li>GetMapping signup메서드 구성</li>
    </ol>
  </li>
  <li>templates 디렉터리에 login.html, signup.html 파일을 생성</li>
</ol>

<p><br />
<br /></p>

<h2 id="로그아웃-기능-만드는-순서">로그아웃 기능 만드는 순서</h2>
<ol>
  <li>controller 패키지의 UserApiController 에서 logout메서드 추가하기</li>
  <li>삭 페이지에 로그아웃 요청을 보낼 수 있는 버튼을 만들기
    <ol>
      <li>“/logout” 으로 get요청이 보내지면 됨</li>
    </ol>
  </li>
</ol>]]></content><author><name>Your Name</name></author><summary type="html"><![CDATA[로그인, 회원가입 실습]]></summary></entry><entry><title type="html">JWT 로그인 로그아웃 예제 실습</title><link href="https://m2316.github.io/JWT_%EB%A1%9C%EA%B7%B8%EC%9D%B8_%EB%A1%9C%EA%B7%B8%EC%95%84%EC%9B%83_%EC%98%88%EC%A0%9C_%EC%8B%A4%EC%8A%B5/" rel="alternate" type="text/html" title="JWT 로그인 로그아웃 예제 실습" /><published>2024-05-06T00:00:00+00:00</published><updated>2024-05-06T00:00:00+00:00</updated><id>https://m2316.github.io/JWT_%EB%A1%9C%EA%B7%B8%EC%9D%B8_%EB%A1%9C%EA%B7%B8%EC%95%84%EC%9B%83_%EC%98%88%EC%A0%9C_%EC%8B%A4%EC%8A%B5</id><content type="html" xml:base="https://m2316.github.io/JWT_%EB%A1%9C%EA%B7%B8%EC%9D%B8_%EB%A1%9C%EA%B7%B8%EC%95%84%EC%9B%83_%EC%98%88%EC%A0%9C_%EC%8B%A4%EC%8A%B5/"><![CDATA[<p><br /></p>
<blockquote>
  <p>의존성 추가</p>
</blockquote>

<div class="language-gradle highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">dependencies</span> <span class="o">{</span>
	<span class="o">...</span><span class="err">생략</span><span class="o">...</span>
	
	<span class="c1">// 자바 JWT 라이브러리  </span>
	<span class="n">implementation</span> <span class="s1">'io.jsonwebtoken:jjwt:0.9.1'</span>
	
	<span class="c1">// XML 문서와 Java 객체 간 매핑 자동화</span>
	<span class="n">implementation</span> <span class="s1">'javax.xml.bind:jaxb-api:2.3.1'</span> 
	
<span class="o">}</span>
</code></pre></div></div>

<blockquote>
  <p>application.yml 파일에 발급자, 비밀키 값 넣기</p>
</blockquote>

<div class="language-yml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="s">...생략...</span>
<span class="na">jwt</span><span class="pi">:</span>
<span class="err">	</span><span class="na">issuer</span><span class="pi">:</span> <span class="s">myDomainName.com/projectName // http://도메인주소/프로젝트명</span>
<span class="na">	secret_key</span><span class="pi">:</span> <span class="s">key-is-secret-code</span>
<span class="s">...생략...</span>
</code></pre></div></div>

<ol>
  <li>config.jwt 패키지안에 JwtProperties.java 파일 생성</li>
  <li>같은 패키지 안에 TokenProvider.java 파일 생성</li>
  <li>JWT 테스트 코드 작성
    <ol>
      <li>test 디렉터리에 config.jwt 패키지를 생성하고 JwtFactory.java 파일 생성
        <ul>
          <li>이 파일은 JWT 토큰 서비스를 테스트하는 데 사용할 모킹(mocking)용 객체</li>
          <li>테스트를 실행할 때 객체를 대신하는 가짜 객체임…</li>
        </ul>
      </li>
      <li>같은 패키지에 TokenProviderTest.java 파일 생성</li>
    </ol>
  </li>
  <li>리프레시 토큰 구현
    <ol>
      <li>domain 패키지에 RefreshToken.java 생성</li>
      <li>repository 패키지에 RefreshTokenRepository.java 생성</li>
      <li>config.jwt 패키지에 TokenAuthenticationFilter.java 생성
        <ul>
          <li>액세스 토큰값이 담긴 Authorization 헤더값을 가져온 뒤 액세스 토큰이 유요하다면 인증 정보를 설정하는 필터</li>
        </ul>
      </li>
      <li>UserService.java파일을 열어 수정
        <ol>
          <li>public User findById(Long userId) 메서드 추가</li>
        </ol>
      </li>
      <li>service 패키지에 RefreshTokenService.java 파일 생성</li>
      <li>service 패키지에 TokenService.java 파일 생성</li>
      <li>dto 패키지에 CreateAccessTokenRequest 생성</li>
      <li>dto 패키지에 CreateAccessTokenResponse 생성</li>
      <li>controller 패키지에 TokenApiContreoller.java 생성</li>
      <li>리프레시 토큰 테스트 코드 작성
        <ol>
          <li>test 디렉토리로 가서 controller 패키지 안에 TokenApiControllerTest.java 생성</li>
        </ol>
      </li>
    </ol>
  </li>
</ol>]]></content><author><name>Your Name</name></author><summary type="html"><![CDATA[의존성 추가]]></summary></entry><entry><title type="html">JWT_로그인_로그아웃</title><link href="https://m2316.github.io/JWT_%EB%A1%9C%EA%B7%B8%EC%9D%B8_%EB%A1%9C%EA%B7%B8%EC%95%84%EC%9B%83/" rel="alternate" type="text/html" title="JWT_로그인_로그아웃" /><published>2024-05-05T00:00:00+00:00</published><updated>2024-05-05T00:00:00+00:00</updated><id>https://m2316.github.io/JWT_%EB%A1%9C%EA%B7%B8%EC%9D%B8_%EB%A1%9C%EA%B7%B8%EC%95%84%EC%9B%83</id><content type="html" xml:base="https://m2316.github.io/JWT_%EB%A1%9C%EA%B7%B8%EC%9D%B8_%EB%A1%9C%EA%B7%B8%EC%95%84%EC%9B%83/"><![CDATA[<h1 id="jwt를-이용한-로그인-유지">JWT를 이용한 로그인 유지</h1>

<hr />

<blockquote>
  <p>서버에서 올바른 사용자 인지를 식별하는 방법은 크게 두가지로 나눌 수 있다.<br />
서버 기반 인증과 토큰 기반 인증으로 나눌 수 있으며 Spring Security는 Session기반의 인증을 제공해 준다.
이 포스팅에서는 토큰 기반 인증방식을 JWT를 이용하여 설명해 보겠다.</p>
</blockquote>

<hr />

<h3 id="동작-원리">동작 원리</h3>
<ol>
  <li>사용자는 서버로 ID, Password 등 사용자를 식별할 수 있는 값들을 서버로 보냄</li>
  <li>서버는 사용자가 보내온 값들을 서버에 저장되어 있는 값들과 비교하여 올바른 요청이 맞는지 판단</li>
  <li>올바른 요청이 맞다 면 사용자에게 인가 되었다는 정보가 담긴 JWT토큰을 발행해 사용자에게 보냄</li>
  <li>사용자는 인가 된 정보가 담긴 JWT 토큰을 받아 두었다가 서버에 요청을 보낼 때 마다 토큰을 같이 보냄</li>
  <li>서버는 사용자가 보내온 요청과 함께 토큰을 검증하여 토큰에 유효성 검사가 통과되면 사용자의 요청을 수행함</li>
</ol>

<h3 id="사진-참고">사진 참고</h3>
<p><img src="..\images\2024-05-05-JWT_로그인_로그아웃\토큰_인증_과정-1715175485320-23.png" alt="토큰_인증_과정" /></p>

<hr />

<h3 id="특징">특징</h3>
<ol>
  <li>무상태성
    <ul>
      <li>사용자의 인증 정보가 담겨 있는 토큰이 서버가 아닌 클라이언트에 있으므로 서버에 저장할 필요가 없다.</li>
      <li>서버에 요청을 보낼 수 있는 사용자 명단을 서버가 관리하지 않아 서버 리소스를 아낄 수 있다.</li>
      <li>사용자의 인증 상태를 유지하면서 이후 요청을 처리하는 것을 상태 관리라고 하는데 토큰을 이용하면 서버에서 상태 관리를 하지 않게 되어 무상태성이 된다.</li>
    </ul>
  </li>
  <li>확장성
    <ul>
      <li>서버를 증설하거나 다른 서버의 서비스랑 연계해야 할 때 각각의 서버마다 상태 연동이 필요하지 않아 확장에도 용이하다.</li>
    </ul>
  </li>
  <li>무결성
    <ul>
      <li>토큰 방식은 HMAC(hash-dased message authentication) 기법이라고도 부르는데 이는 토큰 발급 이후에는 토큰 정보를 변경하지 못한다는 것을 의미한다.</li>
      <li>토큰이 발행된 이후에 수정할 수 없기 때문에 무결성이 보장된다.</li>
    </ul>
  </li>
</ol>

<hr />

<h3 id="jwt-json-web-token">JWT( Json Web Token)</h3>

<p>토큰 기반의 인증을 수행하기 위해서는 사용자에게 여러 방법으로 토큰을 보내줄 수 있다.
토큰을 쿠키에 담아 전송도 가능하며 HTTP 요청 헤더 중에 Authorization의 키 값으로 사용자에게 전달하는 등의 방법들이 있다.</p>

<p>여기서는 HTTP 요청 헤더에 Authorization의 키 값을 이용하는 방법으로 설명할 것이다.</p>

<h4 id="jwt-사용-예시">JWT 사용 예시</h4>
<ul>
  <li>HTTP 요청 헤더에 Authorization의 키 값을 입력할 때 “bearer” + “JWT 토큰값”을 넣어 보내야 한다.</li>
</ul>

<blockquote>
  <p>객체 상태 예시</p>
  <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="err">//</span><span class="w"> </span><span class="err">Request</span><span class="w"> </span><span class="err">Headers</span><span class="w">
</span><span class="p">{</span><span class="w">
	</span><span class="err">...생략...</span><span class="w">
	</span><span class="err">Authorization:</span><span class="s2">"bearer 헤더.내용.서명"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div>  </div>
</blockquote>

<hr />

<h4 id="jwt-구조">JWT 구조</h4>
<blockquote>
  <p>JWT는 헤더(header).내용(payload).서명(signature) 구조를 갖는다.</p>
</blockquote>

<ol>
  <li>헤더(header)
    <ul>
      <li>헤더에는 토큰 타입과 해싱 알고리즘을 지정하는 정보를 담고 있다.</li>
    </ul>
  </li>
  <li>페이로드(payload) = 내용
    <ul>
      <li>페이로드에는 토큰과 관련된 정보를 담는다.</li>
      <li>내용의 한 덩어리를 <strong>클레임</strong>이라고 부른다.</li>
      <li>클레임은 키값의 한 쌍을 이룬다.</li>
      <li>클레임은 등록된 클레임, 공개 클레임, 비공개 클레임으로 나눌 수 있다.</li>
      <li>등록된 클레임 : 토큰에 대한 정보를 담는 데 사용한다.</li>
      <li>공개 클레임 :
        <ul>
          <li>공개되어도 상관없는 크레임을 의미한다.</li>
          <li>충돌을 방지할 수 있는 이름을 가져야 한다.</li>
          <li>보통 클레임 이름을 URI로 짓는다.</li>
        </ul>
      </li>
      <li>비공개 클레임 :
        <ul>
          <li>공개되면 안 되는 클레임을 의미한다.</li>
          <li>클라이언트와 서버 간의 통신에 사용된다.
            <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="w">  </span><span class="p">{</span><span class="w">
  </span><span class="nl">"iss"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"email@naver.com"</span><span class="p">,</span><span class="w"> </span><span class="err">//등록된</span><span class="w"> </span><span class="err">클레임</span><span class="w">
  </span><span class="nl">"iat"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">1234238402</span><span class="p">,</span><span class="w"> </span><span class="err">//등록된</span><span class="w"> </span><span class="err">클레임</span><span class="w">
  </span><span class="nl">"exp"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="mi">123124235235</span><span class="p">,</span><span class="w"> </span><span class="err">//등록된</span><span class="w"> </span><span class="err">클레임</span><span class="w">
  </span><span class="err">//공개</span><span class="w"> </span><span class="err">클레임</span><span class="w">
  </span><span class="nl">"https://mydomainaddress.com/jwt_claims/is_admin"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span><span class="w">
  </span><span class="nl">"email"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"email@naver.com"</span><span class="p">,</span><span class="w"> </span><span class="err">//비공개</span><span class="w"> </span><span class="err">클레임</span><span class="w">
  </span><span class="nl">"hello"</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="s2">"안녕하세요!"</span><span class="w"> </span><span class="err">//비공개</span><span class="w"> </span><span class="err">클레임</span><span class="w">
  </span><span class="p">}</span><span class="w">
</span></code></pre></div>            </div>
          </li>
        </ul>
      </li>
      <li>iss, iat, exp는 JWT 자체에서 등록된 클레임이다.</li>
      <li>이 외의 등록된 클레임도, 공개 클레임도 아닌 클레임들은 비공개 클레임이다.</li>
    </ul>
  </li>
  <li>시그니처(signature) = 서명
    <ul>
      <li>서명은 해당 토큰이 조작되었거나 변경되지 않았음을 확인하는 용도로 사용함.</li>
      <li>헤더의 인코딩 값과 내용의 인코딩값을 합친 후에 주어진 비밀키를 사용해 해시값을 생성한다.</li>
    </ul>
  </li>
</ol>

<hr />

<h3 id="리프레시-토큰">리프레시 토큰</h3>
<blockquote>
  <p>토큰에는 유효 기간이 존재한다.</p>
</blockquote>

<h4 id="리프레시-토큰이-필요한-이유">리프레시 토큰이 필요한 이유</h4>
<p>토큰은 서버에서 관리되는 것이 아니기 때문에 토큰이 탈취되면 탈취된 토큰을 무력화 시키는 것은 매우 어려운 일이다. 토큰 기반의 인증은 이러한 문제점들을 해결하고자 유효 기간이라는 것을 명시하여 유효 기간이 지나면 토큰이 폐기될 수 있도록 하였다.
유효 기간이 너무 길면 탈취당한 토큰이 오래 살아있게 되어 보안에 취약해지고 너무 짧은 유효기간을 설정하면 그만큼 많은 양의 토큰을 다시 발행해야 하기 때문에 사용자들은 짧은 시간마다 로그인을 다시 요청하게 되는 번거로움이 발생 된다.
위 문제를 해결하기 위해 리프레시 토큰이란 것이 존재한다.</p>

<h4 id="동작순서">동작순서</h4>

<p><img src="..\images\2024-05-05-JWT_로그인_로그아웃\리프레시토큰_동작순서-1715175359564-21.png" alt="리프레시토큰_동작순서" /></p>]]></content><author><name>Your Name</name></author><summary type="html"><![CDATA[JWT를 이용한 로그인 유지]]></summary></entry><entry><title type="html">로그인 프로세스 포스팅</title><link href="https://m2316.github.io/%EB%A1%9C%EA%B7%B8%EC%9D%B8_%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4_%ED%8F%AC%EC%8A%A4%ED%8C%85/" rel="alternate" type="text/html" title="로그인 프로세스 포스팅" /><published>2024-05-05T00:00:00+00:00</published><updated>2024-05-05T00:00:00+00:00</updated><id>https://m2316.github.io/%EB%A1%9C%EA%B7%B8%EC%9D%B8_%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4_%ED%8F%AC%EC%8A%A4%ED%8C%85</id><content type="html" xml:base="https://m2316.github.io/%EB%A1%9C%EA%B7%B8%EC%9D%B8_%ED%94%84%EB%A1%9C%EC%84%B8%EC%8A%A4_%ED%8F%AC%EC%8A%A4%ED%8C%85/"><![CDATA[<h1 id="로그인-기능을-구현하는-방식">로그인 기능을 구현하는 방식</h1>
<p><br /><br /><br /></p>
<h2 id="들어가기-전">들어가기 전</h2>
<blockquote>
  <p>이 글은 로그인 예제 프로젝트를 진행하면서 핵심적인 부분들, 예제에서 알려준 로직에 대해 메모한 글이다.<br />
<strong>로그인 로직에 대해서 지식이 이미 있다면 이 글은 추천하지 않는다.</strong></p>
</blockquote>

<p><br /><br /></p>

<h2 id="로그인-기능-청사진">로그인 기능 청사진</h2>
<p><img src="..\images\2024-05-05-로그인_프로세스_포스틩\로그인로직-1715175550061-26.png" alt="image" /></p>

<p><br /><br /></p>

<h2 id="스프링-시큐리티">스프링 시큐리티</h2>
<blockquote>
  <p>Spring 애플리케이션의 보안(인증, 인가, 권한)을 담당하는 Spring 하위 프레임워크이다.<br />
Spring Security를 사용하면 인증과 인가에 대한 관리 기능을 쉽게 구현할 수 있다.</p>
</blockquote>

<p><br /><br /></p>

<h3 id="특징">특징</h3>
<ul>
  <li>Spring Security는 Spring 애플리케이션의 보안 프레임워크</li>
  <li>애너테이션 설정이 매우 간편함</li>
  <li>CSRF,session flxtion 공격을 방어해줌
    <blockquote>
      <p>session flxtion은 세션에 들어있는 사용자의 인증 정보를 탈취하거나 변조하는 공격을 말함</p>
    </blockquote>
  </li>
  <li>
    <p>요청 헤더를 보안처리 해줌</p>

    <p><br /></p>
  </li>
</ul>

<h3 id="spring-security-filter-chain-구조">Spring Security Filter Chain 구조</h3>
<p><img src="..\images\2024-05-05-로그인_프로세스_포스틩\SpringSecurityFilterChain-1715175577820-29.png" alt="image" /></p>
<blockquote>
  <p>위 사진을 보면서 원하는 위치에 Custom Filter를 만들어 원하는 위치에 Filter Chain을 연결해줄 수 있다</p>
</blockquote>

<p>| 필터명 | 설명 |
|———-|———-|
| SecurityContextPersistenceFilter   | SecurityContextRepository에서 SecurityContext(접근 주체와 인증에 대한 정보를 담고 있는 객체)를 가져오거나 저장하는 역할을 합니다 |
| Logoutfilter   | 설정된 로그아웃 URL로 오는 요청을 확인해 해당 사용자를 로그아웃 처리합니다 |
| UsernamePasswordAuthenticationFilter   | 인증 관리자입니다. 폼 기반 로그인을 할 때 사용되는 필터로 아이디, 패스워드 데이터를 파싱해 인증 요청을 위임합니다. <br />인증이 성공하면 AuthenticationSuccessHandler를<br /> 인증에 실패하면 AuthenticationFailureHandler를<br /> 실행합니다 |
| DefaultLoginPageGeneratingFilter   | 사용자가 로그인 페이지를 다로 지정하지 않았을 때 기본으로 설정하는 로그인 페이지 관련 필터입니다. |
| BasicAuthenticationFilter   | 요청 헤더에 있는 아이디와 패스워드를 파싱해서 인증 요청을 위임합니다. <br />인증이 성공하면 AuthenticationSuccessHandler를<br /> 인증에 실패하면 AuthenticationFailureHandler를<br /> 실행합니다  |
| RequestCacheAwareFilter   | 로그인 성공 후, 관련 있는 캐시 요청이 있는지 확인하고 캐시 요청을 처리해줍니다. 예를 들어 로그인하지 않은 상태로 방문했던 페이지를 기억해두었다가 로그인 이후에 그 페이지로 이동 시켜줍니다. |
| SecurityContextHoldlerAwareRequestFilter   | HttpServletRequest 정보를 감쌉니다. 필터 체인 상의 다음 필터들에게 부가 정보를 제공하기 위해 사용합니다. |
| AnonymousAuthenticationFilter   | 필터가 호출되는 시점까지 인증되지 않았다면 익명 사용자 전용 객체인 AnonymousAuthentication을 만들어 SecurityContext에 넣어줍니다. |
| SessionManagementFilter   | 인증된 사용자와 관련된 세션 관련 작업을 진행합니다. 세션 변조 방지 전략을 설정하고, 유효하지 않은 세션에 대한 처리를 하고, 세션 생성 전략을 세우는 등의 작업을 처리합니다. |
| ExceptionTranslationFilter   | 요청을 처리하는 중에 발생할 수 있는 예외를 위임하거나 전달합니다. |
| FilterSecurityInterceptor   | 접근 결정 관리자입니다. AccessDecisionManager로 권한 부여 처리를 위임함으로써 접근 제어 결정을 쉽게 해줍니다. 이 과정에서는 이미 사용자가 인증되어 있으므로 유효한 사용자인지도. 즉, 인가 관련 설정을 할 수 있습니다. |
—-
<br /></p>

<h3 id="체크하고-넘어갈-security-filter-동작">체크하고 넘어갈 Security Filter 동작</h3>
<ol>
  <li>UsernamePasswordAuthenticationFilter
    <ul>
      <li>ID와 PASSWORD가 로그인 요청과 같이 넘어오면 인증 요청을 위임하는 인증 관리자 역할을 한다.</li>
    </ul>
  </li>
  <li>FilterSecurityInterceptor
    <ul>
      <li>권한 부여 처리를 위임해 접근 제어 결정을 쉽게 하는 접근 결정 관리자 역할을 한다.</li>
    </ul>
  </li>
  <li>사용자가 폼 기반의 로그인 요청을 보냈을 때 Security의 동작
    <ol>
      <li>사용자가 폼에 아이디와 패스워드를 입력하면 HTTPServletRequest에 아이디와 비밀번호 정보가 전달된다.</li>
      <li>유효성 검사가 끝나면 실제 구현체인 UsernamePasswordAuthenticationToken을 만들어 넘겨줌</li>
      <li>전달받은 인증용 객체인 UsernamePasswordAuthenticationToken을 AuthenticationManager에게 보냄.</li>
      <li>UsernamePasswordAuthenticationToken을 AuthenticationProcider에 보냄</li>
      <li>사용자 아이디를 UserDetailService에 보냄
        <ol>
          <li>UserDetailService는 사용자 아이디로 찾은 사용자의 정보를 UserDetails 객체로 만들어 AuthenticationProvider에게 전달 함</li>
        </ol>
      </li>
      <li>DB에 있는 사용자 정보를 가져옵니다.</li>
      <li>입력 정보와 UserDetails의 정보를 비교해 실제 인증 처리를 합니다.</li>
      <li>인증이 완료되면 SecurityContextHolder에 Authentication을 저장하고 인증 성공 여부에 따라 성공하면 AuthenticationSuccessHandler를 실패하면 AuthenticationFailureHandler를 실행합니다.</li>
    </ol>
  </li>
</ol>]]></content><author><name>Your Name</name></author><summary type="html"><![CDATA[로그인 기능을 구현하는 방식 들어가기 전 이 글은 로그인 예제 프로젝트를 진행하면서 핵심적인 부분들, 예제에서 알려준 로직에 대해 메모한 글이다. 로그인 로직에 대해서 지식이 이미 있다면 이 글은 추천하지 않는다.]]></summary></entry></feed>