<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>entry_dsm.log</title>
        <link>https://velog.io/</link>
        <description>대덕소프트웨어마이스터고등학교의 입학전형시스템을 개발하고 있는 팀 EntryDSM입니다. https://velog.io/@entrydsm 에 이어 전공 지식을 공유하기 위해 블로그를 개설하게 되었습니다.</description>
        <lastBuildDate>Wed, 13 Jul 2022 06:46:48 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>entry_dsm.log</title>
            <url>https://velog.velcdn.com/images/entry_dsm/profile/1ce508f1-2889-4b6a-8aa1-bc9bce4da6ff/image.PNG</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. entry_dsm.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/entry_dsm" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[로그인? 난 부럽지가 않어]]></title>
            <link>https://velog.io/@entry_dsm/%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%82%9C-%EB%B6%80%EB%9F%BD%EC%A7%80%EA%B0%80-%EC%95%8A%EC%96%B4</link>
            <guid>https://velog.io/@entry_dsm/%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EB%82%9C-%EB%B6%80%EB%9F%BD%EC%A7%80%EA%B0%80-%EC%95%8A%EC%96%B4</guid>
            <pubDate>Wed, 13 Jul 2022 06:46:48 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/entry_dsm/post/a0e3be17-cfaf-4476-b8d5-8d8a2f73b460/image.png" alt=""></p>
<blockquote>
<p>안녕하세요! 대덕소프트웨어마이스터고등학교의 입학전형 시스템의 백엔드 개발자 2학년 김범진입니다!
저는 언제나 새로운 것을 배우고 끊임없이 도전하는 것을 즐기며 개발을 하고 있습니다. 글 내용 중 오류가 있거나 저에게 궁금한 점이 있다면 댓글 또는 <a href="mailto:sdpthf@naver.com">sdpthf@naver.com</a>으로 연락해주세요.</p>
</blockquote>
<br>

<h1 id="oauth가-뭐길래">OAuth가 뭐길래..</h1>
<p>OAuth는 Open Authorization의 줄임말입니다. 이는 말 그대로 <strong>개방된 권한</strong>을 뜻합니다.</p>
<blockquote>
<p>인터넷 사용자들이 비밀번호를 제공하지 않고 다른 웹사이트 상의 자신들의 정보에 대해 웹사이트나 애플리케이션의 접근 권한을 부여할 수 있는 공통적인 수단으로서 사용되는, 접근 위임을 위한 개방형 표준이다. (위키백과)</p>
</blockquote>
<p>간단히 말해서, OAuth는 로그인을 다른 웹사이트로 위임하는 사용자 인증 방식입니다.</p>
<p>매번 회원가입과 로그인 기능을 구현하면 귀찮을 뿐만 아니라 보안상 취약점이 존재할 가능성이 큽니다.
이를 구글이나 카카오처럼 큰 회사에서 잘 만들어놓은 로그인을 통해 사용자를 인증한다면 믿을 만할 것 같은데요?</p>
<p>지금부터 OAuth에 대해서 살펴보겠습니다.
<br></p>
<h1 id="oauth-20-파보기">OAuth 2.0 파보기</h1>
<h2 id="용어-정리">용어 정리</h2>
<p>OAuth에 대해서 톺아보기 전에 사용되는 용어에 대한 정리부터 해보겠습니다.</p>
<ul>
<li><p><strong><code>Authentication</code></strong> : 인증이라는 뜻으로, 접근 자격이 있는지 검증하는 단계를 말합니다.</p>
</li>
<li><p><strong><code>Authorization</code></strong> : 인가라는 뜻으로, 자원에 접근할 권한을 부여하는 것입니다. 인가가 완료되면 리소스 접근 권한이 담긴 Access Token이 Client에게 부여됩니다.</p>
</li>
<li><p><strong><code>Resource Server</code></strong> : OAuth2 서비스를 제공하고, 자원을 관리하는 서버입니다.</p>
</li>
<li><p><strong><code>Resource Owner</code></strong> : Resource Server의 계정을 소유하고 있는 사용자를 의미합니다.</p>
</li>
<li><p><strong><code>Client</code></strong> : Resoure Server에 접속해서 정보를 가져오고자 하는 애플리케이션입니다. (쉽게 말해 내가 만든 서버를 의미합니다.)</p>
</li>
<li><p><strong><code>Client App</code></strong> : Resource Owner의 요청을 도와 서버로 요청을 보내는 앱 또는 웹 애플리케이션입니다. (프론트엔드, 안드로이드, iOS 애플리케이션을 의미합니다.)</p>
</li>
<li><p><strong><code>Authorization Server</code></strong> : 인증/인가를 수행하는 서버로, Client의 접근 자격을 확인하고 Access Token을 발급하여 권한을 부여하는 역할을 수행합니다.</p>
</li>
<li><p><strong><code>My Access Token</code></strong> : 이 글에서는 Client에서 발급되어 Client의 서비스를 사용할 수 있도록 해주는 access token을 My Access Token이라 부르겠습니다.</p>
</li>
<li><p><strong><code>Access Token</code></strong> : Authorization Server에서 발급된 토큰으로, Resource Server에서 Resource Owner의 보호된 자원을 획득할 때 사용되는 만료 기간이 있는 토큰입니다. (자체 로그인 기능을 개발하면 Client가 Authorization Server이자 Resource Server가 됩니다)</p>
</li>
<li><p><strong><code>Refresh Token</code></strong> : Access Token 만료시 이를 갱신하기 위한 용도로 사용하는 토큰입니다. Refresh Token은 일반적으로 Access Token보다 만료 기간이 깁니다.</p>
<br>

</li>
</ul>
<h2 id="oauth의-흐름">OAuth의 흐름</h2>
<p>OAuth 인증 방식은 여러 가지 방법이 있지만, 가장 대표적으로 사용되는 <strong>Authorization Code Grant</strong> 방식에 대해 자세히 알아보겠습니다. (다른 방식이 궁금하다면 <a href="https://surprisecomputer.tistory.com/41">여기</a>를 참고해주세요.)</p>
<h3 id="느낌-잡기">느낌 잡기</h3>
<p><img src="https://velog.velcdn.com/images/entry_dsm/post/8bbf8e32-fa95-44a3-b5a5-6e76a2136546/image.png" alt=""></p>
<blockquote>
<p>Client가 Authorization Server와 Resource Server를 이용하기 위해서 사전 승인을 받습니다.</p>
</blockquote>
<ol>
<li>Resource Owner가 Client 서비스 이용을 위해 Client로 로그인 요청을 보냅니다.</li>
<li>Client가 Authorization Server로 Redirect 시켜 Resource Owner가 Authorization Server로 로그인을 할 수 있도록 합니다.</li>
<li>로그인이 완료되면 Authorization Server에서 Client로 인증 허가되었다는 의미로 Authorization Code를 발급합니다.</li>
<li>Client는 Authorization Code를 이용해 Authorization Server로부터 Access Token과 Refresh Token을 받습니다.</li>
<li>Resource Owner의 정보가 필요할 경우 해당 토큰을 통해 Resource Server로부터 정보를 가져옵니다.</li>
<li>Access Token이 만료된다면, Refresh Token을 통해 재발급 받습니다.</li>
</ol>
<p>자, 이제 전반적인 흐름에 대해 파악하였다면 각 단계에 대해 조금 더 자세하게 알아볼까요?</p>
<p>OAuth 서비스 중 <a href="https://developers.google.com/identity/protocols/oauth2">구글</a>을 이용한다고 가정해봅시다. 그리고 대부분 사용자 정보를 데이터베이스에 저장하기 때문에 서버에서 인증 작업을 하는 것을 기준으로 하겠습니다.
<br></p>
<h1 id="oauth-api-사용">OAuth API 사용</h1>
<h2 id="사전-작업">사전 작업</h2>
<ol>
<li>Google OAuth를 사용하기 위해서는 가장 먼저 프로젝트를 생성해야 합니다.</li>
<li>몇가지 동의를 한 후 우리의 서비스 URI를 등록합니다.
&#39;승인된 리디렉션 URI&#39;의 URI에는 사용자가 인증을 한 후 리디렉션 될 주소를 적으면 됩니다.
(ex <a href="http://localhost:8080/auth">http://localhost:8080/auth</a>)</li>
<li>OAuth Client를 생성하면 Client ID와 Client Secret을 받을 수 있습니다. OAuth를 사용할 때 중요한 정보이니 잘 보관합니다.<br>

</li>
</ol>
<h2 id="자세한-예시">자세한 예시</h2>
<ol>
<li>처음 요청을 보내는 URL은 <a href="https://accounts.google.com/o/oauth2/v2/auth">https://accounts.google.com/o/oauth2/v2/auth</a> 입니다. 
해당 URL 뒤에 여러 파라미터를 더해 요청을 보내야 합니다.</li>
</ol>
<ul>
<li><strong>client_id</strong> : 처음 등록할 때 받은 Client ID</li>
<li><strong>redirect_uri</strong> : 사전에 등록한 리디렉션 될 주소</li>
<li><strong>response_type</strong> : 요청에 대한 응답 타입(Authorization Code Grant 방식을 이용하기 때문에 &#39;code&#39;를 입력)</li>
<li><strong>scope</strong> : Resource Server(구글)로부터 받아올 정보의 범위(ex. 이메일, 공개된 모든 정보)
<img src="https://velog.velcdn.com/images/softpeanut/post/4ce94398-635d-44d8-a411-8d1dde6658ca/image.png" alt="https://velog.velcdn.com/images/softpeanut/post/4ce94398-635d-44d8-a411-8d1dde6658ca/image.png"></li>
</ul>
<p>필수적으로 요청을 보내야 하는 이 4가지 외에도 <code>access_type</code>, <code>state</code>, <code>include_granted_scopes</code> 등 다양한 파라미터가 있습니다.</p>
<p>이제 OAuth API를 사용하는 대략적인 Flow에 대해 설명 드리겠습니다.</p>
<ol>
<li>Authorization Server(구글)에서 반환한 URI로 Client App(프론트엔드)에서 요청을 보냅니다.</li>
<li>Resource Owner(사용자)가 구글 아이디와 비밀번호를 입력해 Authorization Server(구글)에 로그인 요청을 보냅니다.</li>
<li>Authorization Server(구글)에 인증이 완료되면 Authorization Server(구글)에서 리디렉션 URI로 <a href="https://localhost:3000/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7">https://localhost:3000/auth?code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7</a> 와 같이 승인 코드를 반환해줍니다. <code>4/P7q7W91a-oMsCeLvIaQm6bTrgtp7</code>이 바로 인코딩된 코드값입니다.</li>
<li>Client(개인 서버)에서 인코딩된 코드값을 디코딩한 후 Resource Owner(사용자)의 정보를 받아오기 위한 토큰으로 바꾸어야 합니다. <a href="https://oauth2.googleapis.com/token">https://oauth2.googleapis.com/token</a> 로 여러 파라미터와 함께 요청을 보냅니다.</li>
</ol>
<ul>
<li><strong>client_id</strong> : 처음 등록할 때 받은 Client ID</li>
<li><strong>client_secret</strong> : 처음 등록할 때 받은 Client Secret</li>
<li><strong>grant_type</strong> : 요청에 대한 응답 타입(Authorization Code Grant 방식을 이용하기 때문에 <strong><code>authorization_code</code></strong>를 입력)</li>
<li><strong>code</strong> : 디코딩한 코드값</li>
<li><strong>redirect_uri</strong> : 사전에 등록한 리디렉션 될 주소
<img src="https://velog.velcdn.com/images/softpeanut/post/d1658622-4e0d-45d8-b324-13e429074d3c/image.png" alt="https://velog.velcdn.com/images/softpeanut/post/d1658622-4e0d-45d8-b324-13e429074d3c/image.png"></li>
</ul>
<ol start="5">
<li>이제는 토큰을 이용해 Resource Owner의 정보를 가져올 차례입니다. 아까 받은  <code>1/fFAGRNJru1FTz70BzhT3Zg</code>와 같은 토큰을 매개변수로 넣어 <a href="https://www.googleapis.com/oauth2/v1/userinfo?alt=json&amp;access_token=1/fFAGRNJru1FTz70BzhT3Zg">https://www.googleapis.com/oauth2/v1/userinfo?alt=json&amp;access_token=1/fFAGRNJru1FTz70BzhT3Zg</a> 처럼 요청을 보냅니다.</li>
<li>아까 설정한 scope에 따라 Resource Server(구글)로부터 정보를 받아옵니다. 해당 토큰을 다시 사용할 일이 있다면 별도의 저장소(redis 등)에 저장을 하면 되고, 1회성으로 Resource Owner(사용자)의 정보를 받아오고 끝낸다면 별도로 저장하지 않습니다. Resource Owner(사용자)가 우리 서비스를 사용할 수 있도록 별도의 토큰(My Access Token)을 만들어 반환해야 합니다.</li>
</ol>
<p>이렇게 하면 Resource Owner가 직접 회원가입을 하지 않고도 로그인을 할 수 있고 Resource Server(구글)에서 받아온 정보를 DB에 입력해 활용할 수 있습니다.</p>
<p>이제 정말 OAuth를 통한 로그인 끝 !!</p>
<p>인줄 알았죠? 😱
하지만 매우 아쉽게도 Authorization Code Grant 방식에는 몇가지 문제점이 존재합니다.</p>
<ol>
<li>중간에 Authorization Server(구글)로부터 받은 <strong>인증 코드를 탈취</strong>당할 수 있는 취약점이 있습니다.</li>
<li>구글로부터 미리 발급받은 Client Secret을 앱 또는 웹 어딘가에 저장해야 합니다. <strong>Client App에서 저장해야한다는 말은 탈취될 가능성이 있다</strong>는 것을 의미합니다.</li>
</ol>
<blockquote>
<p>그래서 뭘 어떻게 하라는 말이에요오.. 🤔</p>
</blockquote>
<br>

<h1 id="oauth-20-pkce">OAuth 2.0 PKCE</h1>
<blockquote>
<p>PKCE(Proof Key for Code Exchange)란?
: 동일한 컴퓨터에 침입하는 악성 프로그램이 인증 코드를 가로채는 것을 방지하기 위한 모바일 장치의 공용 클라이언트용 OAuth 2.0 보안 확장이다. (loginradius)</p>
</blockquote>
<p><strong>PKCE</strong>는 간단히 말해서 Authorization Code Grant 방식에서 <strong>Client Secret</strong>을 이용하던 것을 <strong>일회용 암호</strong>를 이용하는 것으로 변경한 것입니다.</p>
<p>PKCE(Proof Key for Code Exchange)로 알려진 <strong>인증을 받기 위한 코드를 교환할 때 증명할 수 있는 키</strong>를 사용하는 방식은 악의적인 공격을 방지하고 Authorization Code Grant 방식을 안전하게 수행하기 위한 방법입니다.</p>
<p>주로 Client Secret을 사용하는 클라이언트 애플리케이션이나 Authorization Code Grant 방식에 사용되는 <strong>Client Secret을 대체</strong>하기에 유용합니다.</p>
<p>이 방식은 기본적으로 <em><code>code_verifier</code>, <code>code_challenge</code>, <code>code_challenge_method</code></em> 라는 세 개의 매개 변수와 함께 동작합니다.</p>
<p>말로 설명하는 것보다 사진을 보는 것이 더 이해가 잘 될 것입니다. 아래 사진에 <strong>Authorization Code Grant + PKCE</strong> 방식이 잘 나타나있습니다.
<img src="https://velog.velcdn.com/images/softpeanut/post/ca522353-5d5d-4bbd-b036-fbd1a371354d/image.png" alt="https://velog.velcdn.com/images/softpeanut/post/ca522353-5d5d-4bbd-b036-fbd1a371354d/image.png"></p>
<ul>
<li><strong>code_verifier</strong> : 48 ~ 128 글자수를 가진 Random String이다. A-Z, a-z, 0-9, -._~ 문자들로만 구성됩니다.
<code>ex) code_verifier=EAp91aanXdoMcoOc2Il55H3UDDIV909k9olEEcl6L24J6_9X</code></li>
<li><strong>code_challenge</strong> : 선택한 해싱 알고리즘으로 Code Verifier를 해싱한 후 Base64로 인코딩을 한 값입니다. -&gt; Base64Encode(Sha256(code_verifier))
<code>ex) code_challenge=HVoKJYs8JruAxs7hKcG4oLpJXCP-z1jJQtXpQte6GyA</code></li>
<li><strong>code_challenge_method</strong>(선택) : 코드 챌린지를 해싱하는데 사용한 메서드를 표기합니다. 기본값은 &#39;plain&#39;입니다.
<code>ex) code_challenge_method=S256</code></li>
</ul>
<p>PKCE 방식은 기본적으로 <strong>Authorization Code Grant 방식의 보안적인 취약점을 보완</strong>하고 더 안전하게 수행할 수 있도록 합니다. Authorization Code Grant 방식에서 변경된 점은 다음과 같습니다.</p>
<ol>
<li>Client는 code_challenge, code_challenge_method와 함께 인증 요청을 보냅니다.</li>
<li>Authorization Server는 code_challenge, code_challenge_method를 저장하고 Authorization Code를 발급합니다.</li>
<li>Client는 code_verifier와 함께 액세스 토큰 요청을 보냅니다.</li>
<li>Authorization Server는 code_challenge와 code_challenge_method를 이용해 code_verifier를 검증한 후 액세스 토큰을 발급합니다.</li>
</ol>
<p><a href="https://www.oauth.com/playground/authorization-code-with-pkce.html">OAuth 공식 사이트</a>에서 PKCE를 직접 체험해 볼 수 있다고 합니다. 아직 이해가 되지 않았거나 직접 체험해보고 싶은 사람들은 사이트에 방문해보면 좋을 것 같습니다.</p>
<h1 id="마지막으로">마지막으로</h1>
<p>이번 글에서는 OAuth의 용어와 흐름, 더 나아가 PKCE에 대해서 알아보았습니다. OAuth에 대한 기본적인 용어와 흐름에 대해 이해를 했다고 해서 바로 적용할 수 있는 것은 아닙니다. 요청을 보낼 때 필요한 요소들은 알려주었지만 구체적으로 어떻게 해야 하는지에 대한 언급은 없었습니다. 아쉽지만 이번 글은 OAuth에 대한 독자의 이해를 돕기 위함이 목적이기 때문에 적용하는 방법에 대해 하나씩 알려주지 않았습니다.</p>
<p>사용하고 있는 프레임워크에서 외부 API를 호출하는 방법, 토큰을 다루는 방법 등 외적으로 알아야 할 것들이 존재합니다. 따라서 해당 글을 보고 이해를 했다고 해서 방심하지 말고 직접 해보며 익혔으면 좋겠습니다 😊</p>
<h3 id="참고">참고</h3>
<p>OAuth 정의 : <a href="https://ko.wikipedia.org/wiki/OAuth">https://ko.wikipedia.org/wiki/OAuth</a>
OAuth 용어 : <a href="https://blog.naver.com/mds_datasecurity/222182943542">https://blog.naver.com/mds_datasecurity/222182943542</a>
OAuth 흐름 : <a href="https://bravenamme.github.io/2019/10/25/oauth2.0">https://bravenamme.github.io/2019/10/25/oauth2.0</a></p>
<p>PKCE 정의 : <a href="https://www.loginradius.com/blog/engineering/pkce/">https://www.loginradius.com/blog/engineering/pkce/</a> , <a href="https://datatracker.ietf.org/doc/html/rfc7636">https://datatracker.ietf.org/doc/html/rfc7636</a>
PKCE 용어 : <a href="https://juniortech.tistory.com/15">https://juniortech.tistory.com/15</a>
PKCE 흐름 : <a href="https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-proof-key-for-code-exchange-pkce">https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-proof-key-for-code-exchange-pkce</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[철이 없었죠, 엔트리를 몰랐다는 게]]></title>
            <link>https://velog.io/@entry_dsm/%EC%B2%A0%EC%9D%B4-%EC%97%86%EC%97%88%EC%A3%A0-%EC%97%94%ED%8A%B8%EB%A6%AC%EB%A5%BC-%EB%AA%B0%EB%9E%90%EB%8B%A4%EB%8A%94-%EA%B2%8C</link>
            <guid>https://velog.io/@entry_dsm/%EC%B2%A0%EC%9D%B4-%EC%97%86%EC%97%88%EC%A3%A0-%EC%97%94%ED%8A%B8%EB%A6%AC%EB%A5%BC-%EB%AA%B0%EB%9E%90%EB%8B%A4%EB%8A%94-%EA%B2%8C</guid>
            <pubDate>Thu, 30 Jun 2022 10:46:38 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/entry_dsm/post/83a56d34-52a9-4367-a040-576cddbf3928/image.png" alt=""></p>
<blockquote>
<p>안녕하세요, 대덕소프트웨어마이스터고등학교의 입학전형 시스템 개발팀 EntryDSM입니다.
4기, 5기 선배들이 작성했던 <a href="https://velog.io/@entrydsm">https://velog.io/@entrydsm</a>에 이어 1학년들에게 도움을 주고자 벨로그를 작성하게 되었습니다.</p>
</blockquote>
<br>

<h3 id="entrydsm이란">EntryDSM이란?</h3>
<p>EntryDSM은 대덕소프트웨어마이스터고등학교의 입학전형 시스템 개발팀입니다.</p>
<p>2022년도 현재 엔트리는 2학년 9명(프론트엔드 5명, 백엔드 4명), 3학년 4명(프론트엔드 2명, 백엔드 2명)으로 총 13명으로 이루어져 있습니다.
팀원 모집은 매년 2학기 중에 진행하고 있으며, 실제 개발은 2학년과 3학년이 참여하고 있습니다.
현재 진행하고 있는 프로젝트는 2가지가 있습니다.<br></p>
<ol>
<li><a href="https://www.entrydsm.hs.kr/">Entry</a> : 대덕소프트웨어마이스터고등학교 입학전형 시스템</li>
<li>REPO : 학생, 선생님, 기업이 사용하는 레쥬메 시스템</li>
</ol>
<p>EntryDSM의 간단한 소개를 마치며, 팀원들이 소개하는 팀 엔트리는 어떤지 들어보겠습니다.</p>
<h3 id="팀-엔트리는-본인에게-어떤-의미인가요">팀 엔트리는 본인에게 어떤 의미인가요?</h3>
<p>🦖 : 무모한 도전을 할 용기를 주고 그 무모한 도전을 성공할 수 있게 해주는 고맙고 든든한 존재입니다.</p>
<p>🥋 : 항상 새로운 것을 접할 기회를 제공해주는, 모험과도 같은 존재입니다.</p>
<p>🎲 : 언제나 따라붙고 없으면 허전한 그림자 같은 존재입니다.</p>
<p>🦹‍♂️ : 미리 다녀보는 직장이라고 생각합니다. 좋은 사람들과 좋은 시간~</p>
<p>🥺 : 엔트리가 아니었다면 지금의 저는 존재하지 않았을 거라고 생각합니다. 어둠 속 유일한 한줄기의 빛이었어요.
<br></p>
<h3 id="엔트리-팀에-합류한-계기는-무엇인가요">엔트리 팀에 합류한 계기는 무엇인가요?</h3>
<p>🍇 : 확실한 결과물을 만들어낸 팀이기에 들어와서 성과를 보고 싶었습니다.</p>
<p>🦹‍♂️ : 입학 전형 시스템을 엔트리 팀에서 개발했다는 것을 알게 되었죠. 그때부터였어요.. 엔트리에 반하게 된 게 </p>
<p>🎃 : 엔트리라는 좋은 동아리라는 인식이 컸고, 실력이 부족한 저에게는 둘도 없는 기회여서 지원했습니다!</p>
<p>🥺 : 실사용자가 있는 프로젝트를 진행해 볼 수 있는 몇 안 되는 기회여서 안 할 이유가 없었어요. 그리고 선배들이 믿음직해서 엔트리에 합류하면 많은 것을 배울 수 있겠다는 확신이 있었습니다.
<br></p>
<h3 id="동아리-활동하면서-가장-뿌듯했던-순간은-언제인가요">동아리 활동하면서 가장 뿌듯했던 순간은 언제인가요?</h3>
<p>🥑 : 처음으로 입학 전형시스템 코드를 제가 직접 짠 것이었습니다. 기능을 짜면서 어려운 부분을 하나씩 해결해 가며 &#39;내가 성장하고 있구나!&#39;를 느낄 수 있었습니다.</p>
<p>🍇 : 저도 엔트리 랜딩페이지가 배포되었을 때인 것 같습니다. 맡은 부분은 크지 않았으나 협업을 통해 결과물을 만들었다는 점에서 인상 깊이 남았습니다.</p>
<p>🐸 : 신입생들이 들어오고, 전공 동아리 면접을 진행할 때 &#39;엔트리 서비스 사용했던 것이 기억나나요?&#39;를 가끔 물어볼 때가 있는데요, 저희 서비스를 사용해보고 기억해 준다는 것에 뿌듯함을 느꼈습니다.</p>
<p>🎲 : 엔트리에서의 첫 코드리뷰가 가장 뿌듯했던거 같습니다. 실제로 프로젝트에 기여한다는 느낌을 받았거든요.
<br></p>
<h3 id="엔트리의-자랑은-역시">엔트리의 자랑은 역시…?</h3>
<p>🥑 : 엔트리의 자랑은 엔트리 팀원들입니다. 서로 알지 못했던 부분, 어려운 부분을 함께 알려주기도 하고 배우기도 하며 같이 성장할 수 있는 환경이 갖춰진 것이 좋은 것 같습니다.</p>
<p>🥋 : 엔트리 팀원과 경험, 기회라고 생각합니다. 함께 새로운 것을 배우고 가르쳐 주는 것에서 그치지 않고, 실제로 같이 사용해볼 수 있는 기회를 제공하는 멋진 동아리라고 생각합니다.</p>
<p>🐛 : 어떤 안건에 대해 여러 방향에서 들여다보고, 다양한 의견을 자유롭게 낼 수 있는 것이 가장 큰 장점이라고 생각해요.</p>
<p>🎲 : 제가 느낀 엔트리의 자랑은 도전에 있습니다. 과거의 틀에서 벗어나 언제나 새로운 시도를 하는 매력적인 동아리입니다.</p>
<p>🥺 : 멋진 팀원들! 실력 좋은 팀원들과 함께 협업하면서 배운 점이 많았습니다. 의사소통의 중요성을 모르는 저에게 의사소통의 중요성을 알려주었고, 나만 이해하는 코드가 아닌 다른 팀원들을 생각하는 코드에 대해 고민하는 계기가 되었습니다.
<br></p>
<h3 id="마치며">마치며</h3>
<p>이번 글로 EntryDSM에 관심을 갖는 계기가 되었으면 좋겠습니다.
더 좋은 프로젝트와 더 좋은 글로 다시 뵙겠습니다.
혹시 궁금한 사항이 있으시다면, <a href="https://www.facebook.com/entrydsm">여기</a>로 연락 주세요:)
짧지 않은 글 끝까지 읽어주셔서 감사합니다!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[뭐? 요청을 보냈는데 기다리라고?? 킹받네;]]></title>
            <link>https://velog.io/@entry_dsm/%EB%AD%90-%EC%9A%94%EC%B2%AD%EC%9D%84-%EB%B3%B4%EB%83%88%EB%8A%94%EB%8D%B0-%EA%B8%B0%EB%8B%A4%EB%A6%AC%EB%9D%BC%EA%B3%A0-%ED%82%B9%EB%B0%9B%EB%84%A4</link>
            <guid>https://velog.io/@entry_dsm/%EB%AD%90-%EC%9A%94%EC%B2%AD%EC%9D%84-%EB%B3%B4%EB%83%88%EB%8A%94%EB%8D%B0-%EA%B8%B0%EB%8B%A4%EB%A6%AC%EB%9D%BC%EA%B3%A0-%ED%82%B9%EB%B0%9B%EB%84%A4</guid>
            <pubDate>Thu, 09 Jun 2022 02:04:01 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>안녕하세요, 대덕소프트웨어마이스터고등학교 입학 전형시스템 EntryDSM 6.0의 어드민 서비스 웹 클라이언트를 개발한 전규현입니다. 
저는 1학년 때 HTML과 CSS를 접한 뒤 점점 재미를 붙여 프론트엔드를 더욱 깊게 공부하고 있습니다. 프론트엔드 개발과 관련하여 궁금한 점이 있다면 언제든지 연락해주세요. 친절하게 답변해 드리겠습니다.</p>
<p>📩 <a href="https://www.facebook.com/Ghyeon10/">페이스북</a> </p>
</blockquote>
<h1 id="동기-비동기">동기? 비동기?</h1>
<p>우리는 모두 데이터를 처리하기 위해 동기 방식과 비동기 방식을 사용합니다. 그런데 정확히 <strong>동기</strong>는 무엇이고 <strong>비동기</strong>는 무엇일까요?</p>
<p>이번 파트에서는 <strong>동기(Sync)</strong>와 <strong>비동기(Async)</strong> 방식, <strong>블록(Blocking)</strong>과 <strong>논블록(Non-Blocking)</strong>에 대해 설명하도록 하겠습니다.</p>
<h2 id="동기">동기</h2>
<p><strong>동기</strong>란 말 그대로 동시에 일어난다는 뜻입니다. <strong>요청(Request)</strong>을 보내면 그에 해당하는 <strong>결과(Response)</strong>가 동시에 일어난다는 약속이죠. 때문에, 시간이 얼마나 걸리던 요청한 자리에서 결과가 주어져야 합니다.</p>
<h2 id="비동기">비동기</h2>
<p><strong>비동기</strong>란 동시에 일어나지 않는다는 의미입니다. <strong>‘요청한 결과는 동시에 일어나지 않을거라는 약속’</strong>이죠. </p>
<h1 id="동기와-비동기는-왜-쓸까-🔎">동기와 비동기는 왜 쓸까? 🔎</h1>
<p><img src="https://velog.velcdn.com/images/jgh10070/post/691bbda5-139a-41f1-b6eb-d1387b53fd13/image.gif" alt=""></p>
<p>그렇다면 이러한 동기와 비동기는 왜 쓰는 것일까요? 
동기와 비동기는 상황에 따라 각각 장단점이 존재합니다.</p>
<p><strong>동기방식은</strong> 설계가 매우 간단하고 직관적이지만 결과가 주어질 때까지는 아무 작업을 못하고 대기해야만 하는 단점이 있습니다.</p>
<p><strong>비동기 방식</strong>은 동기보단 구조가 복잡하지만 결과가 주어지는데 많은 시간이 걸리더라도 그 시간 동안 다른 작업을 병행 할 수 있으므로 효율적으로 사용할 수 있는 장점이 있습니다. </p>
<h2 id="예시로-보는-동기와-비동기-⏳">예시로 보는 동기와 비동기 ⏳</h2>
<h3 id="동기-⏸">동기 ⏸</h3>
<blockquote>
<p>현재 제가 A에게 돈을 송금하려고 합니다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/entry_dsm/post/848c3117-ab92-4349-b1b3-1fe9e8fe03dd/image.png" alt=""></p>
<blockquote>
<p>저는 A의 계좌번호를 확인한 후 6700원을 송금합니다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/entry_dsm/post/1f9b4063-8c9d-4d73-a166-1836256a32ac/image.png" alt=""></p>
<blockquote>
<p>A는 계좌에 돈이 송금되었다는 것을 확인한 후 돈을 받았다고 답장합니다. </p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/entry_dsm/post/9f036bfb-df64-4871-a58a-6e8b52179d63/image.png" alt=""></p>
<p>순서를 보면, 저와 A는 송금(요청)과 응답을 확인하며 <strong>같은 일을 동시에</strong> 진행하였습니다.
계좌이체같은 작업은 위와 같은 <strong>동기</strong>방식으로 처리해야 A에게 돈을 보냈는데 받지 못하는 상황이 없을 것입니다.</p>
<h3 id="비동기-▶">비동기 ▶</h3>
<blockquote>
<p>A는 동아리 시간이 기다려집니다. 회식이 기다리고 있기 때문입니다. 
배달을 담당하기로 한 A는 배달앱에서 피자를 시킵니다.</p>
</blockquote>
<p align="center"><image src="https://velog.velcdn.com/images/jgh10070/post/eb41b76c-8014-47b1-9b48-5794eb26c4c2/image.png" width="50%"></p>

<blockquote>
<p>주문 요청을 받은 피자가게는 즉시 피자를 굽습니다.</p>
</blockquote>
<p align="center"><image src="https://velog.velcdn.com/images/jgh10070/post/cc0f0ca5-cc4c-4f97-82ee-882784ae6b88/image.png" width="50%"></p>

<blockquote>
<p>피자를 맛있게 굽고 배달 준비를 모두 마친 피자가게는 배달을 출발합니다.
... (20분 후) 피자가 도착했습니다! 맛있게 먹기만 하면 되겠네요.</p>
</blockquote>
<p align="center"><image src="https://velog.velcdn.com/images/jgh10070/post/da600694-f73e-4aa4-8afe-4c2722f02769/image.png" width="50%"></p>

<p>A와 피자가게는 <strong>&quot;피자&quot;</strong>라는 link가 있지만 피자에 행하는 목적은 서로 다릅니다. A는 피자를 배달시키는 역할을 하고, 피자가게는 피자를 굽고 배달을하는 역할을 합니다. <strong>서로의 목적은 다르기에 둘의 작업 처리기간은 일치하지 않으며, 일치하지 않아도 됩니다.</strong></p>
<h1 id="블록-논블록은-뭐지-🧐">블록, 논블록은 뭐지? 🧐</h1>
<p>앞서 소개한 <strong>동기/비동기</strong>는 요청받은 함수가 작업을 완료했는지를 누가 체크하느냐의 차이였다면, <strong>블록/논블록</strong>은 요청받은 함수가 제어권(함수실행권)을 언제 넘겨 주느냐의 차이입니다.</p>
<h3 id="블록">블록</h3>
<p><strong>블록</strong>은 요청받는 함수가 작업을 모두 마치고 나서야 요청자에게 제어권을 넘기는 현상입니다. (그동안 요청자는 아무것도 하지않고 기다림)</p>
<p>작업이 완료된 후 새로운 작업을 수행할 수 있습니다. </p>
<h3 id="논블록">논블록</h3>
<p><strong>논블록</strong>은 요청받은 함수가 요청자에게 제어권을 바로 넘겨주는 현상입니다. (그동안 요청자는 다른 일을 할 수 있음)</p>
<p>작업의 완료여부와 관계없이 새로운 작업을 수행할 수 있습니다.</p>
<h2 id="예시로-보는-블록과-논블록-🔃">예시로 보는 블록과 논블록 🔃</h2>
<h3 id="블록--동기"><strong>블록</strong> + <strong>동기</strong></h3>
<blockquote>
<p><strong>호출된 함수</strong>의 작업이 끝나야 제어권을 돌려받고, <strong>호출 함수</strong>는 결과가 나올 때까지 계속 확인한다.</p>
</blockquote>
<ul>
<li><strong>A</strong> : 혹시 이 부분좀 해줄 수 있어?</li>
<li><strong>B</strong> : 가능하지! 옆에서 조금만 기다려봐</li>
<li><strong>A</strong> : (B 옆에서 아무것도 안 하며 기다린다. 언제 끝나는지 궁금함.)</li>
<li><strong>B</strong> : (열심히 하는 중..)</li>
<li><strong>A</strong> : (지켜봄)</li>
<li><strong>A</strong> : 오 끝났네! 고마워 ㅎㅎ</li>
</ul>
<h3 id="블록--비동기"><strong>블록</strong> + <strong>비동기</strong></h3>
<blockquote>
<p><strong>호출된 함수</strong>의 작업이 끝나야 제어권을 돌려받고, 결과는 <strong>호출된 함수</strong>가 알려준다.</p>
</blockquote>
<ul>
<li><strong>A</strong> : 혹시 이 부분좀 해줄 수 있어?</li>
<li><strong>B</strong> : 가능하지! 옆에서 조금만 기다려봐</li>
<li><strong>A</strong> : (B 옆에서 아무것도 안 하며 기다린다. 언제 끝나는지 관심 없음)</li>
<li><strong>B</strong> : (열심히 하는 중..)</li>
<li><strong>B</strong> : 끝났다! 자 여기</li>
</ul>
<h3 id="논블록--동기"><strong>논블록</strong> + <strong>동기</strong></h3>
<blockquote>
<p>제어권은 바로 돌려주고, <strong>호출 함수</strong>는 결과가 나올때까지 계속 확인한다.</p>
</blockquote>
<ul>
<li><strong>A</strong> : 혹시 이 부분좀 해줄 수 있어?</li>
<li><strong>B</strong> : 가능하지!</li>
<li><strong>A</strong> : (자기 할거 하다가) 다했어?</li>
<li><strong>B</strong> : 잠시만</li>
<li><strong>A</strong> : (자기 할거 하다가) 다했어?</li>
<li><strong>B</strong> : 끝났어, 여기</li>
</ul>
<h3 id="논블록--비동기"><strong>논블록</strong> + <strong>비동기</strong></h3>
<blockquote>
<p>제어권은 바로 돌려주고, 결과는 <strong>호출된 함수</strong>가 알아서 알려준다.</p>
</blockquote>
<ul>
<li><strong>A</strong> : 혹시 이 부분좀 해줄 수 있어?</li>
<li><strong>B</strong> : 가능하지! 다하고 말해줄게</li>
<li><strong>A</strong> : (자기 할거 하는 중)</li>
<li><strong>B</strong> : 끝났어! 여기</li>
</ul>
<br>

<h1 id="정리하며-📝">정리하며 📝</h1>
<p>이번 글에서는 sync/async &amp; blocking/non-blocking 대한 개념을 짚어보았습니다. 동기와 비동기같은 경우는 시점과 같은 개념이기 때문에 실제 코드에서는 애매할 것 같기도 합니다. 때문에 글에서는 동기와 블록킹, 비동기와 논블록킹의 개념을 섞어 작성하여 어느정도 구분이 지어진 것 같습니다. 정말 중요한 부분이니 꼭 직접 공부해보시길 추천드립니다 😉 
<br></p>
<h3 id="참고">참고</h3>
<ul>
<li><a href="https://joooing.tistory.com/entry/%EB%8F%99%EA%B8%B0%EB%B9%84%EB%8F%99%EA%B8%B0-%EB%B8%94%EB%A1%9C%ED%82%B9%EB%85%BC%EB%B8%94%EB%A1%9C%ED%82%B9">https://joooing.tistory.com/entry/동기비동기-블로킹논블로킹</a></li>
<li><a href="https://cotak.tistory.com/136">https://cotak.tistory.com/136</a></li>
<li><a href="https://www.ibm.com/docs/ko/baw/20.x?topic=styles-synchronous-over-asynchronous-invocation">https://www.ibm.com/docs/ko/baw/20.x?topic=styles-synchronous-over-asynchronous-invocation</a></li>
<li><a href="https://private.tistory.com/24">https://private.tistory.com/24</a></li>
<li><a href="https://velog.io/@daybreak/%EB%8F%99%EA%B8%B0-%EB%B9%84%EB%8F%99%EA%B8%B0-%EC%B2%98%EB%A6%AC">https://velog.io/@daybreak/동기-비동기-처리</a></li>
<li><a href="https://koras02.tistory.com/87">https://koras02.tistory.com/87</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[응~ 배포하면 그만이야~]]></title>
            <link>https://velog.io/@entry_dsm/%EC%9D%91-%EB%B0%B0%ED%8F%AC%ED%95%98%EB%A9%B4-%EA%B7%B8%EB%A7%8C%EC%9D%B4%EC%95%BC</link>
            <guid>https://velog.io/@entry_dsm/%EC%9D%91-%EB%B0%B0%ED%8F%AC%ED%95%98%EB%A9%B4-%EA%B7%B8%EB%A7%8C%EC%9D%B4%EC%95%BC</guid>
            <pubDate>Wed, 08 Jun 2022 06:57:51 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/entry_dsm/post/4854883c-ecc2-4e3a-8ada-2da15e6dd917/image.png" alt=""></p>
<blockquote>
<p>안녕하세요! EntryDSM의 프론트엔드팀에 속해 있는 3학년 <strong>김혜준</strong>입니다. 🙇🏻‍♀️
대덕소프트웨어마이스터고등학교 입학 전형 시스템 <strong>Entry 6.0 LTS</strong>에서 <strong>메인 서비스 프론트엔드</strong>를 담당하였습니다.
누구보다 즐겁게 개발하면서 어제보다 더 멋있어지기 위하여 노력하고 있습니다.
엔트리 서비스 또는 해당 게시글에 관하여 궁금한 점이 있다면 <a href="https://www.facebook.com/hyejun68">이곳</a>으로 연락해 주세요.
엔트리 서비스 코드가 궁금하시다면? <a href="https://github.com/EntryDSM">깃허브</a>로 구경 오세요!</p>
</blockquote>
<br>


<h1 id="배포가-뭐야-🍐🍐🍐🍐">배포가 뭐야? 🍐🍐🍐🍐?</h1>
<p>→ <strong>배포</strong>란 <strong>컴파일</strong>과 <strong>빌드</strong>를 통해 만들어진 산출물을 <strong>사용자들에게 공개하는 것</strong>입니다.
<br></p>
<h2 id="컴파일-빌드-뭐라는거야">컴파일? 빌드? 뭐라는거야</h2>
<h3 id="컴파일">컴파일</h3>
<ul>
<li><p><strong>컴파일러</strong>가 java, python, javascript와 같은 <strong>프로그래밍 언어</strong>로 작성한 <strong>소스 코드</strong>를 기계가 이해할 수 있는 <strong>바이너리 코드</strong>로 <strong>변환</strong>하는 과정입니다.</p>
</li>
<li><p><em><em>(Typescript는 컴파일 후 자바스크립트로 변환됩니다.)</em>*</em></p>
</li>
<li><p>한마디로 내가 짠 프로그래밍 언어의 코드를 기계 언어로 변환시키는 것입니다.</p>
</li>
</ul>
<h3 id="빌드">빌드</h3>
<ul>
<li>컴파일된 코드를 사용자들에게 보여주기 위해 실행 가능한 <strong>소프트웨어 산출물</strong>로 만드는 과정입니다.</li>
<li><strong>빌드 도구</strong>는 소스 코드를 컴파일, 테스트, 정적 분석 등을 사용하여 실행 가능한 애플리케이션으로 <strong>자동 생성하는 프로그램</strong>입니다.<ul>
<li>계속해서 늘어나는 라이브러리의 <strong>자동 추가 및 관리</strong> 해주고 <strong>라이브러리 버전</strong>을 자동으로 동기화해줍니다.</li>
</ul>
</li>
</ul>
<p><img src="https://velog.velcdn.com/images/entry_dsm/post/fb1f29d3-8cc0-434b-b15d-0a495c68e62f/image.png" alt=""></p>
<h2 id="배포">배포</h2>
<p>→ <strong>컴파일</strong>과 <strong>빌드</strong>를 통해 만들어진 산출물을 각각의 서버에서 동작하도록 하여 서비스를 <strong>사용자들에게 공개하는 것</strong>입니다.</p>
<p>이제 이해가 조금 되셨나요? 쉽게 말하자면 서비스의 공개 범위를 <strong>나만보기</strong>에서 <strong>전체공개</strong>로 돌렸다고 볼 수 있습니다.</p>
<p>작성한 코드를 빌드하고, 빌드가 완성된 파일을 사용자가 접근할 수 있는 환경에 배치하면 배포가 완료됩니다. → 빌드를 해서 생성된 파일을 AWS에 올리는 것을 예시로 들 수 있겠네요.
<br></p>
<h2 id="코드를-수정하고-빌드하고-테스트하고-배포까지">코드를 수정하고 빌드하고 테스트하고 배포까지</h2>
<p>상당히 많은 시간이 소요됩니다. 누가 대신 빌드와 테스트, 배포까지 해줬으면 좋겠죠?</p>
<p>쓸데없이 소모하는 시간을 단축시키고 개발에 더 집중할 수 있을 것입니다.</p>
<p>개발자 대신 빌드와 테스트, 배포까지 해주는 대표적인 방법으로 <strong>CI/CD 파이프라인</strong>이 있습니다.
<br></p>
<h1 id="자-이제부터-ci--cd에-대해-알아봅시다">자 이제부터 CI / CD에 대해 알아봅시다.</h1>
<p>개발을 공부하고 있다면 CI/CD에 대해서 다들 한 번쯤은 들어보셨을 겁니다.</p>
<p>→ 애플리케이션 개발 단계를 <strong>자동화</strong>하여 애플리케이션을 <strong>짧은 주기</strong>로 고객에게 제공하는 방법입니다.</p>
<p>애플리케이션의 통합(merge)및 테스트 단계에서부터 제공 및 배포 단계까지 <strong>지속적인 자동화</strong>와 <strong>지속적인 모니터링</strong>을 제공합니다. 이러한 구축을 일반적으로 <strong>CI/CD 파이프라인</strong>이라고 합니다.</p>
<p><img src="https://velog.velcdn.com/images/entry_dsm/post/3a373e60-ce81-4236-ad8b-e5d1dec7b554/image.png" alt=""></p>
<h2 id="ci">CI</h2>
<p><strong>C</strong>ontinuous <strong>I</strong>ntegration의 약자로 <strong>지속적 통합(merge)</strong>을 뜻합니다.</p>
<p>→ 버그 수정이나 새로운 코드 변경이 <strong>주기적으로 빌드 및 테스트</strong>되면서 공유 리포지토리에 통합하는 것을 의미합니다.</p>
<p>간단히 말하자면 <strong>빌드/테스트 자동화 과정</strong>이라고 할 수 있습니다. <strong>개발자를 위한</strong> 자동화 프로세스입니다.</p>
<p><img src="https://velog.velcdn.com/images/entry_dsm/post/41c1973c-8b04-4345-9476-ede97c945cab/image.png" alt=""></p>
<h3 id="1-코드-변경사항을-주기적으로-자주-통합merge하기">1. <strong>코드 변경사항을 주기적으로 자주 통합(merge)하기</strong></h3>
<p>여러 명의 개발자들이 자주 머지하지 않고 한 번에 많은 양의 코드를 머지하게 된다면 어떻게 될까요?</p>
<p>맞습니다. 여러분이 생각한 것처럼 많은 코드들이 충돌 나는 문제가 발생합니다.</p>
<p>새로운 기능의 코드를 작성하는 시간보다 충돌하는 많은 코드를 수정하는 데에 시간이 더 오래 걸릴 수 있습니다.</p>
<p>이러한 문제를 발생시키지 않게 가능한 <strong>작은 단위</strong>로 나눠서 주기적으로 개발하고 계속해서 통합해나가야 합니다.</p>
<hr>
<ol>
<li>개발한 코드들을 github와 같은 관리 시스템에 통합합니다.</li>
<li>통합한 코드가 제대로 작동하는지 <strong>빌드 및 테스트</strong>를 진행합니다.</li>
<li>버그가 발생하면 정리해두어 버그를 해결해야 합니다.</li>
</ol>
<hr>
<h3 id="2-통합-단계의-자동화">2. <strong>통합 단계의 자동화</strong></h3>
<p>빈번하게 통합하는 것은 다 좋은데 너무 귀찮아요. 빌드하고 테스트하는 과정은 굳이 사람이 하지 않아도 되는 작업입니다.</p>
<p>그래서 말인데, 자동화를 사용하면 어떨까요? github에 코드를 올리면 나머지 작업인 테스트와 빌드를 프로그램이 자동으로 해주는 것입니다.</p>
<p>귀찮은 반복 작업은 자동화를 통해서 전부 생략되어 시간도 아끼고 복잡한 작업을 하나 덜할 수 있습니다.</p>
<hr>
<ol>
<li>개발한 코드들을 github와 같은 관리 시스템에 통합합니다.</li>
<li>빌드 및 테스트는 자동으로 진행되므로, 버그가 생기면 다음에 확인해서 해결합니다.</li>
</ol>
<hr>
<h3 id="장점-장점-장점">장점 장점 장점</h3>
<ul>
<li>코드의 검증에 들어가는 시간이 줄어듭니다.</li>
<li>개발 편의성이 증가합니다.</li>
<li>좋은 코드 퀄리티를 유지할 수 있습니다.<br>

</li>
</ul>
<h2 id="cd">CD</h2>
<p>→ <strong>C</strong>ontinuous <strong>D</strong>elivery 지속적인 제공 / <strong>C</strong>ontinuous <strong>D</strong>eployment 지속적인 배포를 의미합니다.</p>
<h3 id="지속적인-제공">지속적인 제공</h3>
<p>→ 변경 사항이 <strong>빌드와 버그 테스트</strong>를 거쳐 리포지토리에 <strong>자동으로 업로드</strong>되는 것입니다.</p>
<p>효과적인 지속적인 제공을 실현하기 위해서 CI가 먼저 구축되어 있어야 합니다.</p>
<p>지속적인 제공의 목표는 서비스로 배포할 준비가 되어있는 코드를 확보하는 것입니다.</p>
<h3 id="지속적인-배포">지속적인 배포</h3>
<p>→ 개발자의 변경 사항을 리포지토리에서 고객이 사용 가능한 프로덕션 환경까지 <strong>자동으로 릴리스</strong>하는 것입니다.</p>
<p>애플리케이션 제공 속도를 저해하는 수동 프로세스로 인한 <strong>프로세스 과부하 문제를 해결</strong>합니다.</p>
<p>품질 저하 없이 <strong>최대한 빨리</strong> 사용자에게 새로운 기능을 제공할 수 있습니다.</p>
<p>강력하고 신뢰할 수 있는 자동화 배포를 구축하면 하루에도 여러 번 이루어지는 릴리스에도 걱정 없습니다 :)
<br></p>
<h2 id="한-번-써보면-장점을-몸소-느낄-수-있을걸-🤩">한 번 써보면 장점을 몸소 느낄 수 있을걸 🤩</h2>
<p>개념만 보고 실제로 사용을 안 해보면 장점을 들어도 아 그렇구나 하고 넘길 수 있습니다.</p>
<p>하지만 실제로 CI/CD 파이프라인을 구축하여 사용해 본다면 다음 프로젝트를 진행할 때 필수적으로 가져가게 될 것입니다. 하하하</p>
<p>프론트엔드 &amp; 백엔드 상관없이 해당 파트의 배포를 해야 하는 때가 온다면 CI/CD 파이프라인을 구축해 보세요!
CI/CD 파이프라인 구축하여 서비스를 배포하는 경험은 누구나 쉽게 해볼 수 있는 경험이 아니랍니다.
<br></p>
<h2 id="대표적인-cicd-종류">대표적인 CI/CD 종류</h2>
<p>기억해두고 나중에 사용해 보세요. Jenkins와 Github Actions을 쉽게 접하실 수 있을거에요.</p>
<ul>
<li>Jenkins</li>
<li>CircleCI</li>
<li>TravisCI</li>
<li>Github Actions<br>

</li>
</ul>
<h1 id="글을-마무리-지으며">글을 마무리 지으며</h1>
<p>이번 글에서 CI/CD 파이프라인에 대해서 다루어 보았습니다.</p>
<p>쉽게 정리한 글이지만, 여러분들이 읽으시면서 처음 보는 개념도 있고 이해하기 어려운 내용들도 있을 수도 있습니다.</p>
<p>프로젝트를 진행하면서 배포, CI/CD는 빼먹고 갈 수 없는 단계입니다.</p>
<p>지금 당장 이해하기 어렵겠지만 프로젝트를 진행하고, 전공 공부를 하면서 CI/CD 파이프라인을 구축해야 하는 때가 올 것입니다. 그 때를 위하여 미리 예습하는 것도 나쁘지 않겠죠? 😄
<br></p>
<h3 id="참고-문서">참고 문서</h3>
<ul>
<li><a href="https://seosh817.tistory.com/104">https://seosh817.tistory.com/104</a></li>
<li><a href="https://www.redhat.com/ko/topics/devops/what-is-ci-cd">https://www.redhat.com/ko/topics/devops/what-is-ci-cd</a></li>
<li><a href="https://jud00.tistory.com/entry/CICD%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%BC%EA%B9%8C">https://jud00.tistory.com/entry/CICD란-무엇일까</a></li>
<li><a href="https://artist-developer.tistory.com/24">https://artist-developer.tistory.com/24</a></li>
<li><a href="https://tecoble.techcourse.co.kr/post/2021-08-14-ci-cd/">https://tecoble.techcourse.co.kr/post/2021-08-14-ci-cd/</a></li>
<li><a href="https://itholic.github.io/qa-cicd/">https://itholic.github.io/qa-cicd/</a></li>
<li><a href="https://www.redhat.com/ko/topics/devops/what-cicd-pipeline">https://www.redhat.com/ko/topics/devops/what-cicd-pipeline</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[슈슉 슈슉. 슉. 슉.C..C.CORS 놈아]]></title>
            <link>https://velog.io/@entry_dsm/%EC%8A%88%EC%8A%89-%EC%8A%88%EC%8A%89.-%EC%8A%89.-%EC%8A%89.C..C.CORS-%EB%86%88%EC%95%84</link>
            <guid>https://velog.io/@entry_dsm/%EC%8A%88%EC%8A%89-%EC%8A%88%EC%8A%89.-%EC%8A%89.-%EC%8A%89.C..C.CORS-%EB%86%88%EC%95%84</guid>
            <pubDate>Wed, 08 Jun 2022 06:29:19 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/entry_dsm/post/01f9f504-6080-4a26-a9f7-5f2bce4c64b3/image.png" alt=""></p>
<blockquote>
<p>안녕하세요, 대덕소프트웨어마이스터고등학교의 입학전형 시스템의 어드민 서버를 개발한 3학년 이승윤입니다!
꾸준히 팀 내에서 스스로의 책임을 되물으며 능동적인 팔로워가 되기 위해 노력하고 있습니다.
글 내용 중 오류가 있는 경우 <a href="https://www.facebook.com/profile.php?id=100040101679630">여기</a>로 연락해주시면 재빨리 답변드리겠습니다.</p>
</blockquote>
<br>

<h1 id="또-cors라고-🤯">또 CORS라고? 🤯</h1>
<p>웹 프로젝트를 진행하면 브라우저에서 CORS 오류를 종종 볼 수 있습니다.</p>
<p>대체 CORS가 뭐길래 우리를 이렇게 힘들게 하는 걸까요?</p>
<p>CORS 개념을 이해하기 전, SOP에 대해 먼저 살펴보겠습니다.
<br></p>
<h1 id="sop-넌-누구니-🤨">SOP 넌 누구니? 🤨</h1>
<p>SOP는 Same Origin Policy의 줄임말입니다. 즉, ‘같은 출처 정책’을 말합니다.</p>
<p><strong>같은 출처에서만 자원들을 공유</strong>할 수 있도록 하는 자바스크립트 엔진 표준 스펙의 정책입니다.</p>
<blockquote>
<p>자바스크립트 엔진이란, 쉽게 말해 자바스크립트 코드를 실행하는 프로그램으로서 주로 웹 브라우저를 위해 사용되는 것입니다.</p>
</blockquote>
<p>자바스크립트 엔진 표준 스펙의 정책이기 때문에 <script></script> 태그 안에 둘러싸인 것 외의 다른 정보는 SOP의 관여 없이 GET 메소드를 사용하여 불러올 수 있습니다.</p>
<p>같은 출처에서만 자원을 공유해야 한다니 요래 저래 불편하네요. 하지만 누구든지 내 정보를 가지고 갈 수 있다면 어떨까요?</p>
<p>계정의 비밀번호를 가져가는 스크립트(<a href="https://developer.mozilla.org/en-US/docs/Glossary/Cross-site_scripting">XSS, Cross-Site Scripting</a>)를 만들지도 모릅니다.</p>
<p>이와 같은 상황을 방지하고 <strong>보안을 지키기 위해 만들어진 정책이 SOP</strong>입니다.
<br></p>
<h1 id="같은-출처-기준이-뭐지-🤔">같은 출처? 기준이 뭐지 🤔</h1>
<p><img src="https://velog.velcdn.com/images/entry_dsm/post/d8f59d29-cb9f-4f14-bcaa-9a47c36d86f3/image.png" alt="">
위 사진과 같이 URL에는 Protocol, Host, Port, Path 등으로 이루어져 있습니다.</p>
<p>같은 출처인지 비교하기 위해서는 두 URL의 <strong>Protocol(Scheme), Host(Domain), Port 이 세 가지 요소가 모두 동일</strong>해야 합니다.</p>
<blockquote>
<p>URL의 포트 번호는 생략되는 경우가 많습니다. HTTP는 80, HTTPS는 443으로 기본 포트가 정해져 있기 때문입니다.</p>
</blockquote>
<p>예를 들어, 로컬에서 Spring boot와 React를 실행시키면 따로 설정하지 않는 이상 Spring boot는 <a href="http://localhost:8080">http://localhost:8080</a>으로 기본 실행되고, React는 <a href="http://localhost:3000">http://localhost:3000</a>으로 실행됩니다.</p>
<p>만약 로컬의 React에서 로컬의 Spring boot 서버에 접근하면 어떨까요?</p>
<p>두 URL의 Protocol(http://)과 Host(localhost)는 같지만 Port가 달라서 CORS를 따로 설정해주지 않으면 오류가 발생할 것입니다.
<br></p>
<h1 id="그럼-cors는-뭐야-🤓">그럼 CORS는 뭐야? 🤓</h1>
<p>SOP 정책에 몇 가지 예외 상황을 두어 <strong>다른 Origin끼리도 자원을 주고받을 수 있도록 하는 정책</strong>이 CORS(Cross-Origin Resource Sharing)입니다.</p>
<p>이전에는 동일한 도메인에서만 자료를 받아왔지만, 클라이언트에서 도메인이 다른 서버를 사용하는 일이 많아지면서 CORS가 등장했습니다.</p>
<p>서버 측에서 CORS를 설정하면, 허용된 Origin(출처), 허용된 Method(메소드)로는 접근이 가능해집니다.
<br></p>
<h1 id="cors-동작원리-🤖">CORS 동작원리 🤖</h1>
<p>대표적인 CORS 동작으로는 Simple Request, Preflight가 있습니다. </p>
<p>클라이언트에서 따로 설정해주지 않아도  W3C 사양에 따라 <strong>브라우저는</strong> 지원되는 메소드가 서버에서 유효한지 확인하기 위해 실제 요청을 보내기 전에 <strong>OPTIONS 요청을 수행</strong>합니다 (<a href="https://medium.com/@f2004392/cors-preflight-request-options-9d05b9248e5a">https://medium.com/@f2004392/cors-preflight-request-options-9d05b9248e5a</a>). </p>
<h3 id="simple-request">Simple Request</h3>
<p>먼저, <strong>단순 요청</strong>으로 보낼 때는 다음 세 가지 조건이 모두 충족해야 합니다.</p>
<ul>
<li><code>GET</code>, <code>HEAD</code>, <code>POST</code> 메서드를 사용해야 합니다.</li>
<li>User agent에서 자동으로 설정한 헤더 외에 수동으로 설정할 수 있는 헤더는 <a href="https://fetch.spec.whatwg.org/#cors-safelisted-request-header">Fetch에 정의되어 있는 헤더</a> 뿐입니다.</li>
<li>만약 Content-Type를 사용하는 경우에는 <code>application/x-www-form-urlencoded</code>, <code>multipart/form-data</code>, <code>text/plain</code>만 허용됩니다.</li>
</ul>
<p>Simple Request의 시나리오를 따르기 위해서는 사용자 인증을 위한 <code>Authorization</code>도 사용할 수 없으며, 대부분의 HTTP 요청에서 사용하는 <code>Content-Type</code>인 <code>application/json</code>도 설정할 수 없습니다.</p>
<h3 id="preflight">Preflight</h3>
<p>Simple Request의 까다로운 조건을 다 맞추는 상황을 만들기는 쉽지 않습니다. 그래서 우리는 preflight을 보내는 방식을 주로 사용하게 됩니다.</p>
<p>여기서 preflight란, <strong>사전 요청</strong> 정도로 생각하시면 됩니다.</p>
<p><img src="https://velog.velcdn.com/images/entry_dsm/post/ab8d0bef-af0c-4d92-a82a-2e0cc35ac169/image.png" alt=""></p>
<ol>
<li>자바스크립트의 Fetch API를 사용하여 브라우저에게 리소스를 받아오라고 명령을 보내면, 브라우저는 실제 요청을 보내기 전 <code>OPTIONS</code>라는 HTTP 메소드를 사용하여 사전 요청을 보냅니다.<blockquote>
<p><code>OPTIONS</code>는 목표 리소스와의 통신 옵션을 설명하기 위해 사용되는 메소드입니다.</p>
</blockquote>
</li>
<li>서버는 이에 대한 응답으로 어떤 <strong>메소드, 출처 등을 허용하는지에 대한 정보를 헤더에 담아</strong> 반환합니다.</li>
<li>그럼 <strong>브라우저는 이때 받은 응답과 보낼 요청을 비교</strong>한 후 요청을 보내도 안전하다고 생각하면 실제 요청을 보내고 서버에게 받은 응답 데이터를 자바스크립트로 전달해줍니다.<br>

</li>
</ol>
<h1 id="credentialed-request-🔐">Credentialed Request 🔐</h1>
<p>사전 요청의 응답으로 사용할 때, 실제 요청에서 자격증명을 이용할 수 있는지에 대해서 알려줍니다. </p>
<p>서버에서 쿠키를 따로 사용하는 것이 아니라면, credentials를 사용하지 않아도 요청/응답이 가능합니다.</p>
<p>같은 출처에서 HTTP 통신을 하는 경우 별도의 설정 없이 쿠키가 요청 헤더에 들어갑니다. 하지만 CORS는 기본적으로 보안상의 이유로 쿠키를 요청으로 보낼 수 없도록 막고 있습니다. 따로 쿠키에 인증과 관련된 정보를 담을 수 있게 해주는 옵션인 <code>credentials</code>을 설정해주어야 정상적인 응답을 받을 수 있습니다.</p>
<p>credentials의 옵션은 3가지가 있습니다. </p>
<ul>
<li>same-origin : 같은 출처 간 요청에만 인증 정보를 담는다. (기본)</li>
<li>include : 모든 요청에 인증 정보를 담는다.</li>
<li>omit : 모든 요청에 인증 정보를 담지 않는다.</li>
</ul>
<p>Preflight Request의 응답에서 <code>Access-Control-Allow-Credentials: false</code>이거나 생략한 경우, 실제 요청을 서버에 보낼 때에는 credentials 정보를 함께 보내지 않습니다.</p>
<p>Simple GET 요청의 경우 사전 요청 과정이 없기 때문에 credentials 정보와 함께 CORS 요청을 합니다. 단, 서버에서 서버에서 <code>Access-Control-Allow-Credentials: false</code>이거나 생략한 경우, 브라우저는 받은 응답을 자바스크립트 코드에 전달하지 않습니다.</p>
<p><code>Access-Contol-Allow-Credentials: true</code>로 설정했다면 동일 출처 여부와 상관없이 모든 요청에 인증 정보가 포함되도록 설정된 것이기 때문에 <code>Access-Control-Allow-Origin: *</code>는 불가능합니다.
<br></p>
<h1 id="추가-정보-➕">추가 정보 ➕</h1>
<ul>
<li>CORS는 클라이언트 측 웹 애플리케이션의 보안정책이기 때문에 앱과 통신하는 경우, Postman 등을 사용하여 서버끼리 통신하는 경우에는 적용되지 않습니다.</li>
<li>기본적으로는 SOP만 적용되므로 몇 가지 예외 상황을 두기 위해서는 서버 측에서 CORS 설정을 해주어야 합니다.<br>

</li>
</ul>
<h1 id="cors-이슈-해결방법-🦸">CORS 이슈 해결방법 🦸</h1>
<p>CORS의 개념만 설명하면 아쉬우니 CORS를 해결하는 다양한 방법 중에서 Entry DSM의 기술 스택인 <code>Spring boot</code>를 기준으로 해결 방법 두 가지 경우를 말씀드리겠습니다.</p>
<h3 id="controller마다-crossorigin-붙이기">Controller마다 @CrossOrigin 붙이기</h3>
<pre><code class="language-java">@CrossOrigin(origins = &quot;http://localhost:3000&quot;) //&#39;origins =&#39;는 생략 가능
@RestController
public class TestController {

    @GetMapping
    public void test() {}

}</code></pre>
<p><code>@CrossOrigin</code>은 Spring에서 CORS를 적용할 수 있게 만든 어노테이션입니다. origins 속성으로 허용 출처를 허용하면 다른 Origin이더라도 요청을 주고 받을 수 있게 됩니다.</p>
<p>위의 코드처럼 클래스 단에서 어노테이션을 추가할 수도 있고, 각 메소드마다 설정해줄 수도 있습니다. 하지만, 컨트롤러가 많을 수록, 기능이 많을 수록 설정해야 하는 어노테이션이 많아진다는 단점이 있습니다.</p>
<h3 id="webconfig에서-전역으로-설정하기">WebConfig에서 전역으로 설정하기</h3>
<pre><code class="language-java">@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping(&quot;/**&quot;)
                .allowedMethods(&quot;GET&quot;, &quot;POST&quot;, &quot;DELETE&quot;, &quot;PATCH&quot;, &quot;PUT&quot;)
                .allowedOrigins(&quot;http://localhost:3000&quot;, &quot;http://localhost:3001&quot;,
                        &quot;http://localhost:3002&quot;, &quot;https://apply.entrydsm.hs.kr&quot;, &quot;https://admin.entrydsm.hs.kr&quot;);
    }

}</code></pre>
<p>현재 Entry DSM에서 사용하는 방법입니다. 특정 도메인으로 오는 요청에 대해 전역으로 CORS를 적용하고 싶은 경우 사용합니다. WebMvcConfigurer의 구현체를 빈으로 등록한 후 <code>addCorsMappings</code> 메소드를 오버라이딩하면 간편하게 설정할 수 있습니다.</p>
<ul>
<li><code>.addMapping()</code> : CORS를 적용할 URL 패턴을 정의합니다. Entry DSM에서는 모든 요청의 CORS를 전역으로 설정하기 위해 <code>“/**”</code>로 설정하였습니다.</li>
<li><code>allowedMethods()</code> : 허용할 Http Method를 지정합니다. 모든 메소드를 허용하기 위해서는 <em>“</em>”*만 적어주면 됩니다.</li>
<li><code>allowedOrigins()</code> : 자원 공유를 허락할 출처를 지정합니다. 모든 출처를 허용하려면 <em>“</em>”*만 적어주면 됩니다. Entry DSM에서는 React의 로컬 주소와 배포 주소만 허락하였습니다.</li>
</ul>
<p>추가로 로컬 환경에서 API를 사용 시, </p>
<p><a href="https://chrome.google.com/webstore/detail/allow-cors-access-control/lhobafahddgcelffkeicbaginigeejlf">Allow CORS: Access-Control-Allow-Origin</a></p>
<p>위의 프로그램을 활성화시키게 되면, CORS 문제를 해결할 수 있다고 합니다.</p>
<p>모든 메소드를 허용하고, 모든 출처를 허용하는 것은 보안적으로 절대 좋은 방법이 아닙니다. 각자 사용하는 언어/프레임워크에서 CORS를 해결하는 방법을 찾아보고 최소한으로 허용하는 것을 추천드리며 이 글을 마치도록 하겠습니다.
<br>
<br></p>
<h3 id="참고">참고</h3>
<ul>
<li><a href="https://developer.mozilla.org/ko/docs/Web/HTTP/CORS">https://developer.mozilla.org/ko/docs/Web/HTTP/CORS</a></li>
<li><a href="https://evan-moon.github.io/2020/05/21/about-cors/">https://evan-moon.github.io/2020/05/21/about-cors/</a></li>
<li><a href="https://velog.io/@hoit_98/SOP%EC%99%80-CORS">https://velog.io/@hoit_98/SOP와-CORS</a></li>
<li><a href="https://jaeyeong951.medium.com/options-%EC%9A%94%EC%B2%AD%EC%9D%80-%EC%B2%98%EC%9D%8C-%EB%B3%B4%EB%8A%94%EB%8D%B0%EC%9A%94-sop-cors-398f780601bb">https://jaeyeong951.medium.com/options-요청은-처음-보는데요-sop-cors-398f780601bb</a></li>
<li><a href="https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-CORS-%F0%9F%92%AF-%EC%A0%95%EB%A6%AC-%ED%95%B4%EA%B2%B0-%EB%B0%A9%EB%B2%95-%F0%9F%91%8F">https://inpa.tistory.com/entry/WEB-📚-CORS-💯-정리-해결-방법-👏</a></li>
<li><a href="https://velog.io/@logqwerty/CORS">https://velog.io/@logqwerty/CORS</a></li>
<li><a href="https://youtu.be/bW31xiNB8Nc">https://youtu.be/bW31xiNB8Nc</a></li>
<li><a href="https://shinsunyoung.tistory.com/86">https://shinsunyoung.tistory.com/86</a></li>
</ul>
]]></description>
        </item>
    </channel>
</rss>