'2019/04'에 해당되는 글 4건

Programming/.NET

GC는 힙에 할당된 객체의 소멸을 자동으로 처리하여 메모리를 관리합니다. 이때 객체가 할당된 힙메모리의 관리는 세대로 구분하여 처리하게 됩니다.

 

예를 들어

static void Main(string[] args)
{
    MyClass m = new MyClass();

    Console.WriteLine(GC.GetGeneration(m));
}

위에서 처럼 new를 통해 최초로 개체를 생성하면 이 개체는 0세대로 분류됩니다. 참고로 GC의 GetGeneration메서드를 사용하면 특정 개체의 세대를 확인할 수 있습니다.

 

이렇게 프로그램 내에서 생성되는 참조형식의 개체들은 0세대로 분류해 계속 힙메모리를 할당하다가 어느정도 용량이 커지게 되면 GC가 자동으로 실행되어 현재 0세대중 사용되지 않는 개체를 골라내어 소멸처리하게 됩니다. GC가 개체의 사용유무를 확인하는 방법은 스택에 개체가 할당된 힙의 주소가 있는지 또는 다른 개체에서 참조하고 있는지의 여부입니다. 이런것들을 루트참조라고 하는데 이 루트참조가 없으면 개체를 메모리에서 제거하게 됩니다.

static void Main(string[] args)
{
    MyClass m = new MyClass();
    MyClass m2 = new MyClass();

    m = null;

    GC.Collect();

    Console.WriteLine(GC.GetGeneration(m2));
}

예제에서 처음 개체 m은 생성후 null을 할당해 스택의 주소를 제거하도록 하였습니다. 그런 후 GC를 실행하면 m은 소멸되고 m2만 남게 되는데 GC의 실행으로 남은 m2는 1세대로 올라가게 됩니다. GC가 세대를 구분하는 기준은 현재 힙공간을 가리키고 있는 내부 포인터의 위치입니다.

 

개체를 힙공간에 할당하기전 최초 포인터는 0세대로 정해지는데 개체를 생성할때마다 힙공간에 개체에 필요한 용량을 할당하게 되고 포인터는 그 주소만큼 증가하여 다음 힙공간을 가리키게 됩니다. 그러다가 일정 용량이상이 커지거나 Collect()메서드호출등의 이유로 GC가 실행되면 지금 현재 포인터가 가리키고 있는 주소부터 그 이전까지 할당된 힙공간을 모두 기존의 0세대에서 1세대로 변경하는 방식으로 세대를 증가시키게 됩니다. 증가하는 세대수는 2세대가 최대이며 2세대 부터는 메모리를 계속 점유하면서 남아있게 됩니다.

 

GC가 세대를 구분하는 이유는 GC동작의 효휼성 때문입니다. GC가 동작할때마다 전세대를 대상으로 한다면 GC입장에서는 부담이 아닐 수 없습니다. 그래서 처음에는 0세대만을 대상으로 GC를 수행하다가 메모리 부족현상이 발생하면 0과 1세대를 대상으로 GC가 동작하게 됩니다. 그러다가 다시 메모리 부족이 발생하면 2세대를 포함한 모든 세대를 대상으로 GC가 수행됩니다. 예제에서 Collect() 메서드를 호출해 GC의 동작을 평가하고 있는데 이때 메서드호출시 0 이나 1 또는 2값을 매개변수로 전달하면 해당 세대에 대해서만 GC가 동작되도록 지정할 수 있습니다.

 

그런데 이 과정에서 특정 개체가 메모리에서 소멸하게 되면 개체가 소멸된 힙공간은 비어있게 되는데 GC는 이를 그대로 두지 않고 뒤에 있는 개체를 당겨와 비어있는 공간을 메우게 됩니다. 그래서 개체가 최초로 생성될때의 메모리 주소와 GC가 실행되고 난 이후의 메모리 주소는 달라질 수 있습니다. 하지만 꼭 그렇지 않은 경우도 있습니다. 용량이 너무 큰 개체(85,000 Byte)의 경우에는 그 개체에 할당된 힙을 LOH(Large Object Heap)로 분류하고 위치를 고정시키는데 너무 큰 개체를 GC가 동작할때마다 메모리 내부에서 이동시키기에는 부담이 너무 크기 때문입니다. LOH는 시작부터 2세대로 들어가며 메모리 위치를 바꾸지 않기에 메모리에 공백이 생길수도 있어서 주의해야 합니다.

 

참고로 GC의 Collect() 메서드는 GC를 수행하는 메서드인데 이 메서드를 호출한다고 해서 무조건 GC가 수행되지는 않고 실제 GC가 필요한지는 CLR이 판단하여 수행여부를 결정합니다.

'Programming > .NET' 카테고리의 다른 글

[C#] Stopwatch  (0) 2019.05.09
가비지 수집기 : GC (Garbage Collector)  (0) 2019.04.30
[C#] null 조건  (0) 2019.04.16
[ASP.NET] 인증및 접근제어와 로그인  (0) 2019.04.11
[C#] yield  (0) 2019.04.02
[C#] params  (0) 2019.03.19
0 0
Programming/.NET

다음은 참조형 변수가 null인 상황을 확인하는 전형적인 방법입니다.

myClass m = new myClass();

if (m != null) {
    Console.WriteLine(m?.i);
}

하지만 null 조건을 사용하면 아래와 같이 소스코드를 간단히 변경할 수 있습니다.

myClass m = new myClass();
m = null;

Console.WriteLine(m?.i);

만약 m이 null이라면 null을 반환하고 그렇지 않으면 m의 멤버변수 i의 값을 출력할 것입니다.

'Programming > .NET' 카테고리의 다른 글

[C#] Stopwatch  (0) 2019.05.09
가비지 수집기 : GC (Garbage Collector)  (0) 2019.04.30
[C#] null 조건  (0) 2019.04.16
[ASP.NET] 인증및 접근제어와 로그인  (0) 2019.04.11
[C#] yield  (0) 2019.04.02
[C#] params  (0) 2019.03.19
0 0
Programming/.NET

 1. 인증

 

웹사이트에서 사용하는 대부분의 인증은 Form인증방식입니다. 사이트 자체에서 사용자의 정보를 확인하고 인증을 처리해 주는 방식입니다. 이 방식의 인증을 활용하기 위해서는 우선 web.config의 <system.web>하위에 다음과 같이 인증방식을 설정합니다.

 

<authentication mode="Forms"/>

 

필요에 따라 <forms> 요소를 통해 인증과 관련된 여러가지 설정사항을 등록할 수 있습니다.

 

<authentication mode="Forms">
  <forms name="_auth_" loginUrl="login.aspx" protection="All" timeout="30" requireSSL="false" 

slidingExpiration="true" cookieless="AutoDetect"></forms>
</authentication>

 

ASP.NET은 인증이 완료되면 사용자에게 특정 쿠키값을 제공하는데 name은 이 쿠기값의 이름을 의미합니다. 이름의 기본값은 .ASPXAUTH입니다.

 

사용자가 인증이 필요한 페이지에 접속을 시도하거나 로그인을 시도하는 경우 보여줄 로그인을 페이지는 loginUrl로 지정합니다.

 

인증이 완료되고 나면 쿠키값을 받게 되는데 이때 쿠키의 보호수준을 protection으로 지정합니다. 기본으로 적용되는 All은 쿠키의 암호화와 유효성을 확인하는 옵션이며 Encryption은 암호화만 수행할뿐 유효성검사는 수행하지 않습니다. 반면 Validation은 암호화를 수행하지 않지만 유효성은 확인하며 None은 쿠키보호에 대한 어떤 작업도 하지 않습니다. All값을 권장합니다.

 

쿠키만료시간은 timeout으로 설정합니다. 단위는 '분'이며 기본은 30분입니다.

 

로그인시도시 관련 사용자정보를 전송할때 SSL통신이 필요한지를 requireSSL로 지정합니다.

 

timeout이 30으로 설정되어 있다면 사용자가 로그인을 하고 난 후 아무런 작업도 하지 않은채 30분이 경과할시 쿠키는 만료됩니다.(로그아웃처리) 만약 30분이 되기 전에 어떤 작업이라도 수행해서 웹서버로부터 HTTP통신을 한다면 이 시간은 자동으로 갱신되 다시 30분주기를 갖게 됩니다. 그런데 만일 slidingExpiration을 false로 설정하면 최초로그인부터 쿠키만료시간은 30분간격으로 일정하게 유지됩니다. 사용자가 중간에 어떤 작업을 하더라도 이 시간은 갱신되지 않으며 30분이 지나면 쿠키는 만료될 것입니다.

 

쿠키는 다양한 방법으로 처리될 수 있습니다. cookieless를 UseUri로 하면 URL을 통해 처리되며 UseDeviceProfile은 사용자 웹브라우저 상황을 판단하여 쿠키를 사용할지 결정하게 됩니다. UseCookies는 항상 쿠키를 사용하여 인증처리하도록 하고 AutoDetect는 쿠키전달을 UseUri로 할지 UseCookies로 할지 자동으로 판단합니다.

 

참고로 UseUri는 일단 먼저 쿠키에 값을 저장하고 해당 값을 Url을 통해 전달하는 방식입니다.(쿠키를 사용하지 않는게 아닙니다.)

 

인증에 필요한 설정에서 mode값은 Forms이외에 다음과 같은 값을 가질 수도 있습니다.

 

<authentication mode="Windows"></authentication>

 

Windows는 윈도우서버상에서 사용자를 생성하고 해당 사용자에 대한 접근처리를 수행하는 인증방식입니다. Passport는 장담하건데 쓸일이 없으므로 넘어가도 좋습니다. 그외 None값이 있으며 이는 인증모드를 사용하지 않음을 의미합니다.

 

사용자가 소수로 제한되어 있다면 Web.config의 forms요소 하위에 인증할 수 있는 사용자를 특정할 수도 있습니다.

 

<forms name="_auth_" loginUrl="login.aspx" protection="All" timeout="30" requireSSL="false" slidingExpiration="true" cookieless="AutoDetect">
    <credentials passwordFormat="Clear">
      <user name="cliel" password="12345"/>
    </credentials>
  </forms>

 

credentials 요소에는 passwordFormat 속성으로 암호화 방식을 지정하며 Clear값은 일반 텍스트로 암호를 비교할 것임을 의미합니다. 만일 암호화 형식을 바꾸면 암호도 그에 맞게 지정되어야 합니다.

 

<credentials passwordFormat="SHA1">
  <user name="cliel" password="A6H0A6H70AYT7HTYH359HWNPBWPEJBSJN5IJ6"/>
</credentials>

 

그러나 실제 일반텍스트에서 암호로 변한 문자가 어떻게 될지는 모를일인데 이런 경우 HashPasswordForStringInConfigFile 메소드로 암호를 확인하고 설정하시면 됩니다.

 

string password = FormsAuthentication.HashPasswordForStoringInConfigFile("12345", "SHA1");

 

이렇게 설정한 사용자의 유효성 확인은 '3.로그인' 에서 다시 살펴보겠습니다.

 

참고로 사용자 인증후에는 User개체를 통해 인증과 관련된 몇가지 정보를 조회할 수 있습니다. 사용가능한 항목은 아래 표를 참고해 주십시오.

 

 AuthenticationType

 사용자의 인증타입을 가져옵니다. Basic, NTLM, Forms, Passport 등이 있습니다.

 IsAuthenticated

 현재 사용자가 인증된 상태인지를 확인합니다.

 Name

 사용자의 아이디(이름)을 가져옵니다. 윈도우 인증이라면 도메인명도 같이 가져오게 됩니다.

 

 2. 접근제어

 

웹 사이트의 특정 페이지가 인증된 사용자만이 접근할 수 있는 페이지라면 해당 페이지에 익명사용자는 거부되고 인증된 사용자만이 접근할 수 있도록 설정해야할 필요가 있을 것입니다.

 

이를 위해서는 우선 접근제어가 필요한 웹페이지와 같은 위치에 web.config를 생성하고 <authorization>요소와 <deny>요소를 이용해 익명사용자를 거부하도록 합니다.

 

<?xml version="1.0"?>
<configuration>
    <system.web>
      <authorization>
        <deny users="?"/>
      </authorization>
    </system.web>
</configuration>

 

users에 ?를 설정하는건 인증되지 않은 모든 사용자(익명사용자)를 의미합니다. 또한 특정한 페이지를 따로 지정하지 않는다면 해당 경로(위 설정이 적용된 web.config가 존재하는)에 있는 모든 페이지가 영향을 받게 됩니다. 만약 같은 위치에 익명사용자에 대한 접근거부 페이지와 접근허용페이지가 혼재하는 경우에는 거부되어야할 페이지를 다음과 같이 명시해야 합니다.

 

참고로 이러한 개념은 allow의 경우에도 마찬가지 입니다.

 

<?xml version="1.0"?>
<configuration>
  <system.web>
    <authorization>
      <deny roles="mygroup"/>
    </authorization>
  </system.web>
</configuration>

 

roles는 특정 Group에 대한 접근이나 거부를 설정하고자 할때 사용합니다. Form인증의 경우 역활을, Windows인증의 경우 생성된 그룹명을 여기에 지정할 수 있습니다.

 

<?xml version="1.0"?>
<configuration>
  <system.web>
    <authorization>
      <deny verbs="GET"/>
    </authorization>
  </system.web>
</configuration>

 

verbs는 HTTP요청에 대한 접근제어를 설정하는 것입니다. 위 예제처럼 하면 HTTP의 GET요청은 거부될 것입니다.

 

<?xml version="1.0"?>
<configuration>
  <location path="WebForm.aspx">
    <system.web>
      <authorization>
        <deny users="?"/>
      </authorization>
    </system.web>
  </location>
</configuration>

 

익명 사용자가 WebForm.aspx에 접근을 시도하면 HTTP 404에러가 표시될 것입니다. 특정 사용자에 대한 거부라면

 

<?xml version="1.0"?>
<configuration>
  <location path="WebForm.aspx">
    <system.web>
      <authorization>
        <deny users="username"/>
      </authorization>
    </system.web>
  </location>
</configuration>

 

처럼 사용자명을 지정해 주면 됩니다. 윈도우인증인 경우 '도메인/사용자명'형식으로 지정합니다.

 

접근거부에 대한 결과인데 이를 좀더 자연스럽게 처리하려면 login페이지를 따로 만들고 프로젝트의 web.config <form>요소에 loginUrl속성으로 지정합니다.

 

<authentication mode="Forms">
  <forms loginUrl="login.aspx"></forms>
</authentication>

 

그러면 익명사용자가 인증이 필요한 페이지에 접근할때 기존 에러페이지를 표시하는대신 login.aspx로 이동하게될 것입니다. forms에는 name속성도 지정할 수 있는데 일반적으로 사용자를 식별하기 위한 쿠키이름을 지정합니다. 이름을 지정하지 않으면 .ASPXAUTH라는 이름이 사용됩니다.

 

 3. 로그인

 

익명사용자를 인증사용자로 전환하기 위해서는 로그인과정을 거쳐야 하는데 이를 위해 다음과 같이 Login컨트롤을 페이지에 배치합니다.

 

<form id="form1" runat="server">
<div>
    <asp:Login ID="Login1" runat="server"></asp:Login>
</div>
</form>

 

이걸로 로그인을 위한 준비는 끝났습니다. 하지만 사용자가 존재해야 해당 사용자가 로그인을 할텐데 사용자 생성에 관해서는 아래 글을 참고해 주시기 바랍니다.

 

2016/03/21 - [Programming/ASP.NET] - [ASP.NET] CreateUserWizard와 관련API


이 글은 위 글의 연장선에 있으며 이미 생성된 사용자(anchor37)가 있다고 가정합니다.

 

로그인 컨트롤은 기본적으로 Remember me next time. 체크 박스를 표시하는데 RememberMeText 속성을 원하는 내용으로 설정하면 Remember me next time.를 설정내용으로 바꿀 수 있으며 DisplayRememberMe속성을 false로 하면 아예 이 체크박스가 표시되지 않습니다.


또한 RememberMeSet 속성을 true로 하면 로그인할때 로그인정보를 클라이언트의 쿠키에 담도록 하며 이때 DisplayRememberMe속성을 true로 하면 자동으로 체크박스가 선택된 상태로 표시되지만 false로 하면 사용자가 체크여부를 선택할 수 없으므로 무조건 로그인정보가 쿠키로 저장됩니다.


따라서 별도의 로그아웃을 거지치 않으면 해당 사용자의 로그인은 계속 유지되므로 주의가 필요합니다.

 

사용자가 로그인을 시도할때 계정이 없는 경우 계정을 만들도록 유도하기 위해서는 CreateUserText와 CreateUserUrl속성을 사용합니다.

<asp:Login ID="Login1" runat="server" CreateUserText="회원가입" CreateUserUrl="~/Default.aspx"></asp:Login>

 

마찬가지로 암호를 찾기위한 경우는 PasswordRecoveryText와 PasswordRecoveryUrl속성을, 도움말 표시를 위해서는 HelpPageText, HelpPageUrl 속성을 사용합니다.

 

로그인 컨트롤을 사용하지 않는 경우나 직접 로그인처리를 해야하는 경우라면 FormsAuthentication클래스의 RedirectFromLoginPage메소드를 사용합니다.

 

FormsAuthentication.RedirectFromLoginPage("anchor37", false);

 

이 메소드의 첫번째 인수는 사용자 ID이며 두번째 인수는 해당 사용자의 쿠키를 영구생성할지를 지정합니다. 하지만 이 경우에도 사용자에 대한 정보를 확인하고 해당 사용자가 맞는지에 대한 인증을 거칠 필요가 있는데 이때는 Membership클래스의 ValidateUser메소드를 사용하면 됩니다.

 

if (Membership.ValidateUser("anchor37", "12356"))

                 FormsAuthentication.RedirectFromLoginPage("anchor37", false);

 

ValidateUser메소드는 사용자의 아이디와 비밀번호를 파라메터로 받고 결과를 bool값으로 반환합니다. 만약 Web.config에서 credentials요소를 통해 사용자를 특정한 상태라면 해당 사용자에 대한 유효여부는 Authenticate메소드로 처리할 수 있습니다.

 

if (FormsAuthentication.Authenticate("username", "password"))
                FormsAuthentication.RedirectFromLoginPage("anchor37", false);

 

위 예제에서 처럼 ASP.NET 에서 Form인증과 관련된 대부분의 API처리는 FormsAuthentiation 클래스를 사용하고 있습니다. 예제에서 사용된 메소드나 속성이외에도 FormsAuthentiation 클래스는 다음과 같은 유용한 메소드/속성을 가지고 있습니다.

 

 FormsCookieName

 쿠키이름을 반환합니다.

 FormsCookiePath

 쿠키경로를 반환합니다.

 Initialize

 Web.config 구성을 읽고 FormsAuthentication 클래스를 초기화 합니다.

 SignOut

 로그아웃 처리를 수행합니다.

 Decrypt

 암호화된 쿠키를 복호화합니다.

 Encrypt

 암호화된 쿠키를 생성합니다.

 

어느 웹서비스든 뻘짓하는 사용자가 존재하기 마련인데 특정 아이디에 대한 비밀번호를 반복적으로 입력해 정공법으로 해당 사용자의 계정을 취득하려는 경우가 대표적입니다. ASP.NET에서는 기본적으로 10분동안 로그인 시도횟수를 5번으로 제한하고 있는데 이러한 정책을 수정하려면 Membership공급자를 재정의해야 합니다.

 

<membership>

    <providers>

        <clear/>

        <add name="AspNetSqlMembershipProvider" 

type="System.Web.Security.SqlMembershipProvider, System.Web, Version=4.0.0.0, Culture=neutral, 

PublicKeyToken=b03f5f7f11d50a3a" connectionStringName="sqlprovider" enablePasswordRetrieval="false" 

enablePasswordReset="true" requiresQuestionAndAnswer="true" applicationName="/" 

requiresUniqueEmail="false" passwordFormat="Hashed" maxInvalidPasswordAttempts="5" 

minRequiredPasswordLength="7" minRequiredNonalphanumericCharacters="1" 

passwordAttemptWindow="10" passwordStrengthRegularExpression=""/>

     </providers>

</membership>


우선 공급자의 설정내용을 살펴보면 maxlnvalidPasswordAttempts가 5로 되어 있는 것을 볼 수 있는데 이는 5번의 시도를 의미합니다. passwordAttemptWindow의 값이 10이므로 제한시간은 10분이 됩니다.

 

실제 사용자가 잘못된 비밀번호를 입력하는 경우 개인화 DB의 aspnet_Membership 테이블에 그 기록이 남게 됩니다.

 

테이블의 FailedPasswordAttemptCount는 실패횟수를 FailedPasswordAttemptWindowStart는 실패시간을 의미합니다.

 

사용자가 아이디와 비밀번호를 입력하고 로그인을 시도했는데 위 설정 정책에 따라 10분동안 5번로그인에 실패하면 aspnet_Membership 의 IsLockedOut 컬럼에 true값이 입력되고 계정은 잠기게 됩니다.

 

계정 잠금에 관해서는 MembershipUser객체를 생성해 필요한 내용을 확인하거나 조치를 취하면 됩니다.

 

MembershipUser mu = Membership.GetUser("anchor37");

 

if (mu.IsLockedOut) { //잠긴계정 확인

    Response.Write("귀하의 계정음 잠겼습니다.");

 

    if (mu.UnlockUser()) //계정잠금 풀기

        Response.Write("귀하의 계정이 풀렸습니다.");

}

 

Login 컨트롤을 통해서 직업 사용자명과 비밀번호를 확인하고자 한다면 컨트롤의 OnAuthenticate 이벤트를 활용하면 됩니다.

 

<asp:login runat="server" ID="login1" OnAuthenticate="login1_Authenticate"></asp:login>

protected void login1_Authenticate(object sender, AuthenticateEventArgs e)
{
    if (login1.UserName == "username" && login1.Password == "password") {
    }
}

 

참고로 Remember me next time 설정값은 RememberMeSet 속성으로 확인할 수 있습니다.

'Programming > .NET' 카테고리의 다른 글

가비지 수집기 : GC (Garbage Collector)  (0) 2019.04.30
[C#] null 조건  (0) 2019.04.16
[ASP.NET] 인증및 접근제어와 로그인  (0) 2019.04.11
[C#] yield  (0) 2019.04.02
[C#] params  (0) 2019.03.19
[C#] HttpWebRequest / HttpWebResponse / WebClient  (0) 2019.03.12
0 0
Programming/.NET

yield는 반복구문안에서 return이나 break에 붙여 쓸 수 있는 예약어입니다.

 

yield return은 처음 yield return이 실행된 코드를 기억했다가 다음번 재호출시 다음 yield return다음의 코드부터 실행하는 특징을 가지고 있습니다.

 

static void Main(string[] args)
{
    foreach (int i in TestYield())
        Console.WriteLine(i.ToString());

    Console.Read();
}

static IEnumerable<intTestYield()
{
    yield return 10;
    yield return 20;
    yield return 30;
}

 

처음 TestYield 실행시 10이 반환됐다가 다시 TestYield가 호출되면 20이 반환되고 또 다시 호출되면 30이 반환됩니다. 마지막으로 yield return이 실행됐던 바로 다음코드부터 실행되기 때문입니다.

 

yield break는 열거를 중지하는 역활을 수행합니다.

 

static IEnumerable<intTestYield()
{
    yield return 10;
    yield break;
    yield return 30;
}

'Programming > .NET' 카테고리의 다른 글

[C#] null 조건  (0) 2019.04.16
[ASP.NET] 인증및 접근제어와 로그인  (0) 2019.04.11
[C#] yield  (0) 2019.04.02
[C#] params  (0) 2019.03.19
[C#] HttpWebRequest / HttpWebResponse / WebClient  (0) 2019.03.12
[C#] 시프트(Shift) 연산자  (0) 2019.03.05
0 0
1
블로그 이미지

클리엘