2016년 초 블로그를 개설만 해놓고 들여다 보지도 않던때
개발업무를 하면서 구글링을 하다보면 티스토리 블로그가 눈에띄게 많았다.
그리고 글에 붙어있는 광고.

저 광고 뭐지? 애드센스? 돈 좀 되나? 나도 해볼까?

시작은 아무생각 없었다.
그냥 블로그에 복습겸, 취미겸 코딩에 대한 글을 올릴생각 이였고, 광고가 붙으면 뭔가 뿌듯할거 같았다.

그래서 애드센스에 대해 구글링을 하기 시작했다.
쉽게만 생각했던 애드센스는 "애드고사"라는 별명이 있었다.
별생각 없이 블로그를 운영하고 싶었던 나는 글 3개? 정도를 올리고 애드센스 신청을 했고 당연히 거절됐다.
그리고 글이 6개가 되었을때 다시한번 애드센스를 신청했는데...?

됐다.!!!
(승인이 2018년 8월인건 안비밀... 2년 반동안 글 6개 밖에 안올렸다.. ㅋㅋ)

 

"애드고사"라는 말이 무색했다. 무슨원리인지는 모르겠지만 통과한 기쁨에 얼른 광고를 게재해봤고.
내 블로그에 광고가 뜨는게 너무 신기해 5분동안 턱괴고 화면만 보았었다. ㅋㅋㅋ

그리고 현재 1년 반동안 글 6개를 더 게시 하여 총 12개다.
(그냥 심심해서 하는 걸로...)

그렇게 1년 반동안 애드센스 수익은 10.95$

수익을 위해 열심히 글을 올리고 싶은 생각은 없다.
애초에 시작도 호기심과 재미였으며, 복습을 위해서 였다.
그래도 신경안쓰다 어쩌다 한번 보면 1$씩 올라가있는 잔고가 왠지 뿌듯하다..ㅋㅋ

'Life' 카테고리의 다른 글

이제서야 써보는 애드센스 후기  (0) 2019.12.11

최근 Winform을 이용하여 네이버 카페에 자동으로 글을 등록하는 프로그램을 개발하게 되어 기술과 소스를 공유하고자 작성한다.

 

로그인 / 글쓰기 테스트

 

1. 네이버 자동 로그인

네아로(네이버 아이디로 로그인)을 활용하여 자동 로그인을 구현하려 했다.

Winform의 WebBrowser 혹은 ASP.NET MVC or ASP.NET Webform을 활용하여 네이버 로그인을 구현한 경험은 있지만, WebBrowser없이 로그인을 구현하는 경우는 처음이라 많이 삽질을 했다. 구글에 WebBrowser를 띄우지 않고 로그인하는 방법은 많지 않았고, 있다고 하더라고 POST 패킷 분석 로그인 방법이였다.

 

패킷 분석 로그인 방법은 두 곳을 참조 하였다.

[참조]

- http://non-sponsor.tistory.com/6 (네이버 bvsd 로그인)

- https://it-raccoon.tistory.com/15 (위 코드 기반으로 최신업데이트)

 

 

* bvsd : 네이버 로그인시 전송하는 파라미터의 key이다. 위 [참조] 사이트 들에서는 bvsd를 생성하여 로그인하는 방법을 안내하고 있다. 로그인 성공 이후 Cookie를 저장하여 로그인을 유지한다.

 

위 두 코드를 활용하여 bvsd 로그인 시 OAuth 로그인이 되도록 수정하였다.

할땐 골치 아프더니 다 하고 나니 생각보다 간단

 

1-1. 네이버 로그인 OAuth 구현

보통 네이버 로그인 OAuth 가이드에 따라

[네이버 OAuth 로그인 Url] https://nid.naver.com/oauth2.0/authorize?client_id={client_id}&response_type=code&redirect_uri={callback_url}&state={state} 

경로를 브라우저에 띄워 로그인을 유도한다. 하지만, 원하는건 브라우저 혹은 WebBrowser없이 코드로 로그인을 하는것이다.

 

##

추가적으로 response_type=token으로 할 경우와 code로 할 경우 응답 값이 다르다.

둘 다 로그인 구현은 가능하지만 응답값이 다르다.

token의 경우 응답값으로 Access Token을 받을 수 있으며, Refresh Token을 받을 수 없다.

code의 경우 응답값으로 code와 state를 받아 Access Token과 Refresh Token을 발급 받아야 한다.

##

 

HttpWebRequest로 해당 Url에 bvsd와 OAuth 파라미터를 추가하여 로그인 시도를 한다.

* logintp=oauth2, url=https://nid.naver.com/oauth2.0/authorize?client_id={client_id}&response_type=code&redirect_uri={callback_url}&state={state}을 넣어주면된다.

추가적으로, svctype, smart_LEVEL은 PC마다 다르게 나올수도 있다. 해당값을 바꿔줘야 하는지는 잘 모르겠다.

위 이미지의 파란박스가 bvsd이다.

 

소스에서는 위와 같이 작성되어 있다.

 

이렇게 해주면 bvsd를 활용하여 OAuth 로그인을 성공할 수 있다.

이후 작업은 OAuth 로직에 맞춰 진행되며, 위에서 언급한 code와 state로 Access Token과 Refresh Token을 발급 받아 네이버 API 이용할 수 있다.

 

Refesh Token을 저장하여 추후 ID, PW입력없이 API 사용이 가능하다.

 

1-2. 카페 API 사용

소스는 네이버 개발자 카페 글쓰기 명세에서 그대로 가져와서 썼다.

아주 친절하게 잘 작성되어있다.

 

카페 글쓰기 API 사용시 ClubID와 MenuID를 알아야 글을 작성 할 수 있다.

ClubID와 MenuID는 카페 메뉴에서 오른쪽 클릭 후 "새 창에서 열기" or "새 탭에서 열기"를 하면 확인 가능하다.

https://cafe.naver.com/블라블라?iframe_url=/ArticleList.nhn%3Fsearch.clubid=카페아이디%26search.menuid=메뉴아이디%26search.boardtype=L

 

 

textbox에 미리 값을 채워서 사용해주세요. (안그럼 먹통 인건 안비밀)

 

 

// 급하게 해서 소스가 더러워도 이해해주세여ㅠㅠ

NaverCafeTest.zip
0.02MB

'Programming > C#' 카테고리의 다른 글

[C#] 네이버 자동 로그인 / 카페 글쓰기 API  (9) 2019.11.01
[C#]ini file 사용법 & 소스 공유  (3) 2017.01.03
[C#]Log4Net 사용법  (2) 2017.01.03
[C#]Snappy 사용법  (5) 2016.12.30
[C#]DataTable Sorting 간단 사용법  (0) 2016.12.30
  1. 2019.12.30 17:40

    비밀댓글입니다

    • 지금도 잘 되긴 합니다. 다만 보다보니 수정해야하는 부분이 잇더라구요.
      redirect url은 api에 등록된거면 아무거나 상관없습니다. 저는 그냥 카페 주소로 햇어여:)
      code값이 안넘어 오는건 아마도 동의 화면 때문일수 잇을거 같아요. 동의 화면이 나오면 동의 form작성해서 post를 해야 하더라구요 그부분이 빠져잇어요

  2. ㅁㅁ 2019.12.30 19:17

    답변 감사합니다. 말씀하신대로 동의 화면에서 https://nid.naver.com/login/noauth/allow_oauth.nhn 으로 Post 값을 보내려는데 oauth_token은 어디서 얻어 올 수 있을까요? 다른 값들은 그냥 똑같이 보내면 될 듯한데.. 잘못 접근한건지ㅠ

    • oauth token은 자동으로 hidden 필드에 들어가 있습니다 저는 정규표현식으로 걸러서 사용햇어요
      아마 scope도 넣어서 같이 보내야 할거예요 그래야 카페 글쓰기가 가능합니다~

  3. ㅁㅁ 2019.12.30 20:51

    감사합니다. access토큰이랑 refresh토큰의 값은 불러왔습니다. 이제 글쓰기가 문제인데요.. 자꾸 401권한 문제가 나타나는데
    토큰도 문제 없이 받았는데 이런적 있으신가요?

    • api에 카페 권한 있으신거 맞죠??
      해당 계정 내정보 - 보안 설정 에 권한이 들어가 있나 확인 해보셔야 할거 같아요.
      혹은 카페에 글쓰기 권한이 없으실수도 있어요

  4. kaze 2020.02.19 14:30

    혹시.. 더이상 이 코드는 작동이 안되는건가요?
    로그인 시도시 예외 처리하면서 오류를 뿜네요.

    • Favicon of https://akinokaze.tistory.com 방구천사 2020.02.19 14:44 신고

      아래 함수내의
      public async Task<PostReponse> AsyncPostRequest(string Url, NameValueCollection param = null)

      HttpWebResponse webResponse = (HttpWebResponse)await postreq.GetResponseAsync();
      이부분 실행시 예외가 발생합니다.

    • 지금도 잘 되긴 합니다. 다만 보다보니 수정해야하는 부분이 잇더라구요.
      redirect url은 api에 등록된거면 아무거나 상관없습니다. 저는 그냥 카페 주소로 햇어여:)
      code값이 안넘어 오는건 아마도 동의 화면 때문일수 잇을거 같아요. 동의 화면이 나오면 동의 form작성해서 post를 해야 하더라구요 그부분이 빠져잇어요

WebForms 개발시 Repeater를 자주 사용하게 된다. (회사마다 다르겠지만)
Repeater 사용시 중첩으로 사용하고 싶은 경우들이 있다.

예를들어.

A사 (Key: A)  
  A-1 계열사 (FKey: A)
B사 (Key: B)  
  B-1 계열사 (FKey: B)
  B-2 계열사 (FKey: B)

위와 같은 테이블을 만들기 위해 중첩 Repeater를 사용할 수 있다. (물론 DB조회를 잘 해와서 하나의 Repeater로도 충분히 표현 가능하다. 예시일뿐.)

사용하려는 방법은 DataSet의 Relations를 활용한 방법이다.
* MS Docs DataRelation 참고
Relations를 활용하면 키값으로 두개의 DataTable을 묶어서 사용할 수 있다.
구글링을 하여 찾아보면, OnItemDataBound에서 한번 더 쿼리를 실행해 바인딩(부모의 매 Row마다 실행)하는 방법을 많이 볼 수 있다.
하지만 DataRelation을 사용하면 한번의 쿼리 실행으로 원하는 결과를 만들 수 있다.

코드를 확인하며 이해해보자

[aspx]
Repeater 두개를 중첩하여 작성하였다.
OnItemDataBound에서 Relation정보를 찾아와 SubCompanyList에 바인딩 한다.
    * MS Docs DataBinder.Eval 참고

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<table>
    <tbody>
        <asp:Repeater ID="CompanyList" runat="server" OnItemDataBound="CompanyList_ItemDataBound">
            <ItemTemplate>
                <tr>
                    <td><%# Eval("Name") %> (Key: <%# Eval("Key") %>)</td>
                    <td>&nbsp;</td>
                </tr>
                <asp:Repeater ID="SubCompanyList" runat="server">
                    <ItemTemplate>
                        <tr>
                            <td>&nbsp;</td>
                            <td><%# DataBinder.Eval(Container.DataItem, "[\"Name\"]") %> (FKey: <%# DataBinder.Eval(Container.DataItem, "[\"FKey\"]") %>)</td>
                        </tr>
                    </ItemTemplate>
                </asp:Repeater>
            </ItemTemplate>
        </asp:Repeater>
    </tbody>
</table>
cs

 

[aspx.cs]
1. Page_Load에서 dtCompany, dtSubCompany(임시로 만든 정보입니다. 현업에서는 DB를 읽어와 사용하겠죠?)를 불러와 DataSet을 생성한다.
2. DataSet.Relations를 추가 하여 관계를 생성한다. (관계의 이름은 "CompanyKey"이다.)
    * Relations의 파라미터로 "관계의 이름", "부모 키 컬럼", "자식 키 컬럼"을 넣어준다.

3. 최상단 Repeater에 부모 Table을 바인딩한다.
4. OnItemDataBound Event에서 자식 Table을 찾아 Sub Repeater에 바인딩한다. (GetChildRows 함수 사용)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
 
protected void Page_Load(object sender, EventArgs e)
{
    var dtCompany = InitCompanyData();
    var dtSubCompany = InitSubCompanyData();
    // 데이터셋 생성
    var ds = new DataSet();
    ds.Tables.Add(dtCompany);
    ds.Tables.Add(dtSubCompany);
    // 관계 설정
// DB 조회시에는 SP에서 테이블을 여러개 읽어와 Fill로 DataSet을 만든 후 Relation만 잡아주면 된다.
    ds.Relations.Add("CompanyKey", ds.Tables["CompanyTable"].Columns["Key"], ds.Tables["SubCompanyTable"].Columns["FKey"]);
    // 부모 테이블 바인딩
    CompanyList.DataSource = ds.Tables["CompanyTable"];
    CompanyList.DataBind();
}
 
private DataTable InitCompanyData()
{
    var dtCompany = new DataTable();
    dtCompany.TableName = "CompanyTable";
    dtCompany.Columns.Add("Key"typeof(string));
    dtCompany.Columns.Add("Name"typeof(string));
    var newRow = dtCompany.NewRow();
    newRow["Key"= "A";
    newRow["Name"= "A사";
    dtCompany.Rows.Add(newRow);
    newRow = dtCompany.NewRow();
    newRow["Key"= "B";
    newRow["Name"= "B사";
    dtCompany.Rows.Add(newRow);
    return dtCompany;
}
 
private DataTable InitSubCompanyData()
{
    var dtSubCompany = new DataTable();
    dtSubCompany.TableName = "SubCompanyTable";
    dtSubCompany.Columns.Add("FKey"typeof(string));
    dtSubCompany.Columns.Add("Name"typeof(string));
    var newRow = dtSubCompany.NewRow();
    newRow["FKey"= "A";
    newRow["Name"= "A-1 계열사";
    dtSubCompany.Rows.Add(newRow);
    newRow = dtSubCompany.NewRow();
    newRow["FKey"= "B";
    newRow["Name"= "B-1 계열사";
    dtSubCompany.Rows.Add(newRow);
    newRow = dtSubCompany.NewRow();
    newRow["FKey"= "B";
    newRow["Name"= "B-2 계열사";
    dtSubCompany.Rows.Add(newRow);
    return dtSubCompany;
}
 
protected void CompanyList_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
    if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
    {
        Repeater SubCompanyList = e.Item.FindControl("SubCompanyList"as Repeater;
        // 관계가 설정된 자식 테이블 얻어오기
// 이 부분에서 한번 더 쿼리를 실행할 필요 없이, 관계가 맺어진 정보를 읽어올 수 있다.
        var childRows = ((DataRowView)e.Item.DataItem).Row.GetChildRows("CompanyKey");
        SubCompanyList.DataSource = childRows;
        SubCompanyList.DataBind();
    }
}
cs

 

 

[결과]

직접 디버깅을 해보면 알겠지만 OnItemDataBound Event에서 부모 Table의 Row에 자식 테이블이 엮여 있는것을 볼 수 있다.

 

* DB조회시 까다로운 쿼리 혹은 전혀 관계 없는 데이터를 코드딴에서 묶어서 사용하고 싶을때도 유용하게 사용가능하다. 일자별로 묶어서 데이터를 처리한다던가 하는 그런것들 말이다.

 

다음번 글은 MS사의 Bot Framework와 Language Understanding(LUIS:루이스)을 작성해볼까 한다. (텔레그램, 스카이프 등등 연동도 간편하고 좋다. 단지 LUIS가 유료)

 

끗.

+ Recent posts