Programming/.NET

 1. 개인화 일반

 

일반적으로 웹사이트에서는 사용자의 이름이나 별명, 기타 정보를 관리하기 위해 쿠키나 세션을 많이 사용합니다. 그런데 쿠키는 클라이언트상에서 변경이 가능하므로 보안을 위해서는 쿠키를 암호화 해야 하며 세션은 서버에 저장되는 것으로 비교적 보안에 대한 부담은 적으나 서버의 리소스를 일정부분 점유한다는 측면에서 성능이슈에 관한 논의가 종종 나오곤 합니다.

 

ASP.NET에서는 기존의 쿠키나 세션과 같은 방법이 아닌 사용자 정보관리를 위한 개인화시스템을 제공합니다. 물론 쿠키, 세션등을 사용할 수 있지만 개인화를 사용하면 좀더 안정적이고 편리하게 사용자 정보를 관리할 수 있습니다.

 

우선 가장 기본적인 개인화를 구현해 보도록 하겠습니다. 예를 들어 사용자에 관한 이름, 전화번호, 주소정보를 관리할 필요가 있다면 web.config의 <system.web>하위에 다음과 같이 필요한 속성을 추가시켜 줍니다.

 

<anonymousIdentification enabled="true" />
<profile>
  <properties>
    <add name="Name" allowAnonymous="true" />
    <add name="Phone" allowAnonymous="true" />
    <add name="Address" allowAnonymous="true" />
  </properties>
</profile>

 

위 예제에서는 필요한 각 속성을 정의한것 이외에 추가적으로 anonymousIdentification요소와 각 add요소의 allowAnonymous속성에 true로 된것을 확인할 수 있습니다. 이것은 익명사용자를 위한 속성접근을 허가한 것으로 만약 이 요소를 제외한다면 윈도우인증을 받은 사용자만이 속성에 접근할 수 있게 됩니다. 개인화는 윈도우인증이 아닌 경우 다른 인증(이를 테면 Form인증과 같은)이나 혹은 인증받지 않은 사용자는 모두 익명으로 간주합니다.

 

Profile 요소에는 automaticSaveEnabled 속성을 추가할 수도 있는데 이 속성은 기본값이 true로서 개인화 속성에 값을 대입하면 자동으로 해당 값을 저장합니다. 이 속성을 false로 설정하면 ProfileBase 객체의 Save 메소드를 직접호출해야 개인화 속성값이 저장됩니다.

 

위에서 추가한 속성에 접근이 가능한지를 테스트해보기 위해 aspx에 버튼하나를 배치하고 버튼의 클릭이벤트에 다음과 같이 코드를 작성합니다.

 

protected void Button1_Click(object sender, EventArgs e)
{
    HttpContext.Current.Profile["Name"] = "cliel";
    HttpContext.Current.Profile["Phone"] = "000-1234-5678";
    HttpContext.Current.Profile["Address"] = "대구 광역시";

    Response.Write(string.Format("당신의 이름은 {0}입니다.", HttpContext.Current.Profile["Name"]));
}

 

보시는 바와같이 개인화는 아주 간단히 구현될 수 있습니다. 참고로 개인화공급자를 따로 수정하지 않으면 데이터를 저장하는 기본은 내부 mdf (SQL Server Express)입니다.

 

웹 프로젝트를 웹사이트(Web Site)로 생성하면 Profile 사용법이 좀더 달라질 수 있습니다. Web.config에 위 예제처럼 개인화 속성을 추가하고 나면 다음과 같이 Profile객체를 바로 호출해 원하는 속성을 사용할 수 있습니다. 웹사이트 프로젝트에서는 Web.Config를 수정하면 자동 컴파일되기 때문에 가능한 일입니다.

 

protected void Page_Load(object sender, EventArgs e)
{
    Profile.Name = "홍길동";
}

 

 2. 익명사용자 처리

 

여기 잠깐 익명화를 얘기하자면 anonymousIdentification 요소가 enabled="true"로 설정되는 경우 ASP.NET에서는 비인증 사용자 즉, 익명사용자를 식별하기 위한 고유의 식별값을 사용하게 됩니다. 식별값은 사용자의 컴퓨터에 .ASPXANONYMOUS라는 이름으로 쿠키에 저장되며 ASP.NET에 요청이 발생하면 그때마다 해당 식별값을 전송합니다.

 

만약 익명사용자를 위한 쿠키값을 바꾸어야 한다면 다음과 같이 web.config를 설정할 수 있으며

 

<anonymousIdentification enabled="true" cookieName="anonymous" />

 

cookieTimeout 속성을 사용해 쿠키가 저장되는 시간을 설정할 수도 있습니다.

 

<anonymousIdentification enabled="true" cookieName="anonymous" cookieTimeout="1440" />

 

참고로 cookieTimeout 시간은 기본이 100,000분(70일)이며 1440분은 하루정도의 시간입니다. 하지만 이 설정은 사용자의 웹브라우저설정을 우선할 수 없습니다. 만약 사용자가 쿠키를 고의적으로 삭제하거나 웹브라우저의 설정이 수시로 쿠키를 삭제하도록 되어 있다면 cookieTimeout은 제 기능을 발휘할 수 없을 것입니다.

 

<anonymousIdentification enabled="true" cookieName="anonymous" cookieTimeout="1440" 

cookieless="UseUri" />

 

cookieless는 쿠키대신 사용자를 식별할 다른 방법을 제시하는 것입니다. 여기에 사용할 수 있는 값으로는 UseUri(URL을 식별자로 사용함), UseCookies(기본값:쿠키를 식별자로 사용함), AutoDetect(UseCookies와 UseUri를 자동설정/만약 사용자가 쿠키를 사용하지 않도록 되어 있다면 UseUri가 설정됨/판단을 위한 처리가 별도로 필요하므로 처리가 다소 느릴 수 있음), UseDeviceProfile(브라우저나 디바이스별로 필요한 식별자를 설정)등이 있습니다.

 

URL을 식별자로 한다면 좀 의아할 수도 있는데 실제 이렇게 설정해놓고 웹프로그램을 실행해 보면 임의의 URL을 생성해 관리함을 알 수 있습니다.

 

참고로 프로그램에서 익명사용자의 식별값을 판단하려면 Request의 AnonymousID속성을 사용합니다.

 

Request.AnonymousID

 

이 값은 GUID로 중복되지 않는 값인데 익명 사용자가 생성되면 자동으로 할당됩니다. 만일 이 생성값을 임의로 바꾸려 한다면 익명사용자가 생성될때의 이벤트를 가로채서 식별값을 설정하면 됩니다.

 

public void AnonymousIdentification_Creating(object sender, AnonymousIdentificationEventArgs args)
{
    args.AnonymousID = "익명사용자";
}.

 

웹프로그램에서 익명사용자에게 로그인과 같은 인증된 사용자로 전환할 수 있는 통로를 제공하면 익명사용자는 언제든 인증된 사용자로 바뀔 수 있습니다. 때문에 필요에 따라서는 익명 사용자의 개인화속성값을 그대로 가져와 인증된 상태에서의 해당 속성값을 갱신해야 하는 경우가 있습니다.

 

ASP.NET에서는 익명사용자가 인증된 사용자로 전환될때의 이벤트를 제공하며 해당 이벤트를 통해 개인화 속성값을 갱신하는 방법을 취할 수 있습니다.

 

public void Profile_MigrateAnonymous(object sender, ProfileMigrateEventArgs e)
{
    ProfileCommon pc = Profile.GetProfile(e.AnonymousID);
    Profile.Name = pc.Name;

    Response.Write(User.Identity.Name + "님의 이름은 " + Profile.Name + "입니다.");
}

 

익명사용자가 인증사용자로 전환되는 경우 Profile_MigrateAnonymous이벤트가 실행되며 이벤트 안에서 e.AnonymousID값을 통해 익명사용자의 개인속성값을 가져와 이 값을 현재인증사용자의 개인속성에 저장합니다.

 

참고로 위 이벤트는 Global.asax안에 정의되어 있어야 하며 ProfieCommon이나 Profile객체이용을 위해서는 웹 프로젝트가 웹사이트 프로젝트로 생성되어 있어야 합니다.

 

 3. 개인화 속성 그룹화

 

개인화를 사용하는 경우 사용자그룹별로 다른 데이터가 관리될 수 있습니다. 이런 경우를 대비해 개인화도 그룹별화하는 것이 가능합니다.

 

<anonymousIdentification enabled="true" />
<profile>
  <properties>
    <group name="userDetail">
      <add name="Name" allowAnonymous="true" />
      <add name="Phone" allowAnonymous="true" />
      <add name="Address" allowAnonymous="true" />
    </group>
    <group name="adminDetail">
      <add name="Name" allowAnonymous="true" />
      <add name="SecurityCode" allowAnonymous="true" />
    </group>
  </properties>
</profile>

 

개인화 속성을 userDetail과 adminDetail로 나누었습니다. Name이라는 같은 속성이 존재하지만 그룹이 다르므로 오류는 발생하지 않을 것입니다.

 

protected void Button1_Click(object sender, EventArgs e)
{
    System.Web.Profile.ProfileGroupBase pgb_d = HttpContext.Current.Profile.GetProfileGroup("userDetail");
    pgb_d["Name"] = "cliel";

    System.Web.Profile.ProfileGroupBase pgb_a = HttpContext.Current.Profile.GetProfileGroup("adminDetail");
    pgb_a["Name"] = "administrator";

    Response.Write(string.Format("일반사용자의 이름은 {0}이며 관리자의 이름은 {1}입니다.", pgb_d["Name"].ToString(), pgb_a["Name"].ToString()));
}.

 

그룹지어진 속성에 접근하는 경우 Profile의 GetProfileGroup메소드를 사용해 특정 그룹에 해당하는 속성접근 ProfileGroupBase객체를 가져와야 합니다. 이렇게 가져온 객체를 통해 필요한 속성에 접근하는 것입니다.

 

 4. 데이터 타입 지정

 

개인화 속성은 따로 타입을 지정하지 않으면 기본이 String형입니다. 위에서 선언한 모든 속성도 별도의 타입을 지정하지 않았으므로 값의 형태는 String형이 됩니다.

 

데이터 형식 지정을 알아보기 위해 일반 사용자의 방문일자 저장을 위한 DateTime형의 속성을 하나더 추가해 보도록 하겠습니다.

 

<anonymousIdentification enabled="true" />
<profile>
  <properties>
    <group name="userDetail">
      <add name="Name" allowAnonymous="true" />
      <add name="Phone" allowAnonymous="true" />
      <add name="Address" allowAnonymous="true" />
      <add name="Date_Visit" allowAnonymous="true" type="System.DateTime" />
    </group>
    <group name="adminDetail">
      <add name="Name" allowAnonymous="true" />
      <add name="SecurityCode" allowAnonymous="true" />
    </group>
  </properties>
</profile>

 

속성의 데이터 타입은 닷넷 데이터타입형식으로 정의할 수 있습니다.

 

protected void Button1_Click(object sender, EventArgs e)
{
    System.Web.Profile.ProfileGroupBase pgb_d = HttpContext.Current.Profile.GetProfileGroup("userDetail");
    pgb_d["Name"] = "cliel";
    pgb_d["Date_Visit"] = DateTime.Now;

    Response.Write(string.Format("{0}님은 반갑습니다. 방문하신 오늘은 {1}입니다.", pgb_d["Name"].ToString(), ((DateTime)pgb_d["Date_Visit"]).ToString("yyyy-MM-dd")));
}

 

특정 속성의 값을 가져오는 경우 특정 데이터타입을 다루는 경우라면 해당 데이터형식으로의 변환이 필요합니다. 속성은 기본적으로 object형식입니다.

 

물론 닷넷 데이터형식 이외에도 개발자가 따로 정의하는 별도의 데이터형식을 지정할 수도 있습니다. 예를 들어 관리자의 나이와 금전데이터를 다루는(좀 어거지지만) 클래스가 만들어 이 클래스형식 자체를 개인화속성으로 다루어야 하는 경우를 살펴보겠습니다.

 

우선 해당 클래스를 프로젝트의 App_Code폴더에 mycls라는 이름으로 다음과 같이 생성합니다.

 

[Serializable]
public class mycls
{
    public int age
    {
        get;
        set;
    }

    public double money
    {
        get;
        set;
    }
}

 

mycls 클래스안에는 age와 money속성 2개가 존재하며 각각 나이와 금액데이터를 저장할 것입니다. 클래스에는 [Serializable]이라는 특성이 선언되어 있는데 클래스 자체를 MDF DB내부에 바이너리 형태로 저장할 것이므로 위 특성이 필요합니다.(App_Code 안에 들어간 클래스파일은 Build Action이 Compile로 지정되어 있어야 합니다.)

 

이제 위에서 작성한 클래스를 web.config에 속성으로 선언합니다.

 

<group name="adminDetail">
  <add name="Name" allowAnonymous="true" />
  <add name="SecurityCode" allowAnonymous="true" />
  <add name="MYcls" type="web_form_test.App_Code.mycls" serializeAs="Binary" allowAnonymous="true" />
</group>

 

mycls 클래스는 web_form_test.App_Cde 네임스페이스에 속해 있으므로 type속성을 지정할때는 이를 정확히 지정해 줘야 합니다. 추가된 serializeAs 속성에는 Binary로 지정되어 있는데 속성을 저장하는 저장소에 직렬화 형태로 데이터를 저장하기 위함입니다. 이 밖에 다음과 같은 값을 지정할 수 있으니 참고하시기 바랍니다.

 

● Binary : 개체를 바이너리 형태로 직렬화 하고 저장합니다.

● ProviderSpecific : 개체의 저장형태를 특정 공급자에 의존하여 어떤형식으로 어떻게 저장할지를 공급자에 전적으로 맡기게 됩니다.

● String : 기본설정입니다. 문자열로 개체를 저장합니다.

● XML : 개체를 XML형태로 저장합니다.

 

클래스 형태의 데이터를 속성화 한다고 해서 클래스를 사용하는 방법이 달라지지는 않습니다. 속성을 통해 개체를 클래스형태로 변환해 읽어오면 해당 클래스의 개체를 그대로 사용할 수 있게 됩니다.

 

System.Web.Profile.ProfileGroupBase pgb = HttpContext.Current.Profile.GetProfileGroup("adminDetail");
mycls m = new mycls();
m.age = 30;
m.money = 3.40;

pgb["MYcls"] = m;

mycls m2 = pgb["MYcls"] as mycls;

Response.Write(string.Format("나이는 {0}세이고 잔액은 {1:G}원입니다.", m2.age.ToString(), m2.money));
 

 

 5. 기본값 설정

 

개인화 속성을 지정했는데 아무런 값도 입력되지 않은 경우에 대비해 다음과 같이 지정하면 기본적으로 저장될 값을 설정할 수 있습니다.

 

<add name="Name" allowAnonymous="true" defaultValue="none" />.

 

Name이 아무런 값도 입력되지 않으면 "none"이라는 문자열이 대신 저장될 것입니다.

 

 6. 읽기 전용

 

특정 속성을 읽기만 하고 저장할 수 없도록 하려면 readOnly 속성을 true로 설정합니다.

 

<add name="Name" allowAnonymous="true" readOnly="true" />

 

 7. 공급자 변경

 

개인화 속성에 값을 저장하면 해당 값은 기본적으로 내부 App_Data폴더에 mdf파일을 생성하고 저장하게 됩니다. 이 기본설정은 필요한 테이블이나 프로시저등을 알아서 생성해 모두 처리하지만 내부 MDF대신 외부 MSSQL의 DB서버를 개인화저장소로 사용하기로 했다면 필요한 설정을 수동으로 잡아줘야 합니다.

 

이런 작업과정을 거치는 방법은 2가지 정도가 있는데 우선 첫번째는 Visual Studio의 명령프롬프트창에서 aspnet_regsql.exe 명령을 통해 DB설정을 수행하는 것입니다.

 

아니면 두번째 방법으로 InstallPersonalization.sql 스크립트 파일을 이용해 설정과정을 처리할 수 있는데 이 파일은 C:\Windows\Microsoft.NET\Framework64\v4.0.xxxxx 폴더안에 있니다. 만약 이 DB설정을 취소하고 원래대로 되돌리려면 UninstallPersonalization.sql 스크립트를 실행하면 됩니다.

 

위 2가지중 하나의 방법을 사용해 설정을 거치고 나면 공급자를 변경해 실제 DB연결정보를 제공해 줘야 합니다.

 

<profile>
  <providers>
    <clear/>
    <add name="AspNetSqlProfileProvider" connectionStringName="sqlprovider" 

applicationName="/" type="System.Web.Profile.SqlProfileProvider, System.Web, Version=4.0.0.0, 

Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
  </providers>
  <properties>
    <group name="userDetail">
      <add name="Name" allowAnonymous="true" />
      <add name="Phone" allowAnonymous="true" />
      <add name="Address" allowAnonymous="true" />
      <add name="Date_Visit" allowAnonymous="true" type="System.DateTime" />
    </group>
    <group name="adminDetail">
      <add name="Name" allowAnonymous="true" readOnly="true" />
      <add name="SecurityCode" allowAnonymous="true" />
      <add name="MYcls" type="web_form_test.App_Code.mycls" serializeAs="Binary" allowAnonymous="true" />
    </group>
  </properties>
</profile>.

 

providers 요소 하위에<clear />요소로 우선 기존 공급자 정의를 제거하고 AspNetSqlProfileProvider 이름으로 공급자를 정의하였습니다. 여기서 중요한건 connectionStringName속성인데 예제에서는 sqlprovider로 설정되어 있습니다. 따라서 같은 이름의 연결정보가 다음과 같이 web.config에 정의되어 있어야 합니다.

 

<connectionStrings>
    <add name="sqlprovider" connectionString="Data Source=localhost;Initial Catalog=aspnetdb;

User ID=sa;Password=12345;"/>
 </connectionStrings>

 

필요하다면 속성에 따라 공급자를 나눌 수도 있습니다. 예를 들어 userDetail 그룹은 Local MDF에 adminDetail그룹은 외부 SQL Server에 저장하고자 한다면 각 개인화 속성에서 provider속성을 이용해 저장하고자 하는 저장소의 공급자를 지정하면 됩니다.

 

<add name="Name" allowAnonymous="true" provider="AspNetSqlProfileProvider" />

 

 8. ProfileManager

 

개인화 기능은 사용자의 데이터를 저장하고 사용하는데 편리함을 제공하지만 데이터자체를 관리해주지는 않습니다. 예를들면 익명사용자로 저장된 오래된 데이터를 삭제하거나 인증된 사용자가 사이트를 탈퇴하는 과정등으로 인해 더이상 정보를 저장할 필요가 없는 경우 등이 있을 수 있는데 개인화기능 자체는 이런 형태의 데이터관리기능을 제공하지 않습니다.

 

데이터 관리자체는 직접 해줘야 하지만 ProfileManager 클래스를 이용하면 이런 작업을 좀더 쉽게 구현할 수 있습니다. 클래스자체에 대한 사용방법은 어렵지 않으며 일련의 속성과 메소드를 알고 이를 필요에 따라 적절히 호출해서 사용하면 됩니다.

 

 ApplicationName

 개인화 속성을 저장할때 사용할 애플리케이션 이름을 설정하거나 가져옵니다.

 AutomaticSaveEnable

 개인화 속성을 자동으로 저장할지에 대한 여부를 설정합니다.

 Enabled

 개인화 속성의 사용 여부를 설정합니다.

 Provider

 개인화 속성을 저장하는 공급자를 확인합니다.

 Providers

 개인화 속성을 저장하는데 사용가능한 공급자를 확인합니다.

▶ 속성

 

 DeleteInactiveProfiles

 지정시간 이후로 사용되지 않은 개인화 속성데이터를 삭제합니다.

 DeleteProfile

 지정한 사용자의 개인화 속성데이터를 삭제합니다.

 DeleteProfiles

 DeleteProfile와 같으나 여러 사용자를 컬렉션으로 지정할 수 있습니다.

 FindInactiveProfilesByUserName

 특정 사용자의 개인화 데이터를 검색하되 지정된 시간 이후로 사용되지 않는 것만 검색합니다.

 FindProfilesByUserName

 특정 사용자의 개인화 데이터를 검색합니다.

 GetAllInactiveProfiles

 지정된 시간 이후로 사용되지 않는 모든 개인화 데이터를 검색합니다.

 GetNumberOfInactiveProfiles

 지정된 시간 이후로 사용되지 않는 모든 개인화 데이터의 갯수를 확인합니다.

 GetAllProfiles

 모든 개인화 데이터를 검색합니다.

 GetNumberOfProfiles

 모든 개인화 데이터 갯수를 확인합니다.

▶ 메소드

 

ProfileInfoCollection pic = ProfileManager.FindProfilesByUserName(ProfileAuthenticationOption.All, "guest");

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

[ASP.NET] WCF - 1  (0) 2016.08.31
[C#] Stream  (0) 2016.08.24
[ASP.NET] 개인화(Personalization)  (0) 2016.08.16
[ASP.NET] 서버 컨트롤 - 2 (렌더링)  (0) 2016.08.09
[ASP.NET] 서버 컨트롤 - 1 (기본생성)  (0) 2016.08.01
[ASP.NET] ListView  (0) 2016.07.27
0 0