사용자 지정 권한 구현
업데이트: 2007년 11월
모든 권한 개체는 IPermission 인터페이스를 구현해야 합니다. CodeAccessPermission은 IPermission을 구현하고 권한에 필요한 대부분의 메서드를 제공하므로 CodeAccessPermission 클래스에서 상속하는 것이 가장 쉽게 사용자 지정 권한을 만드는 방법입니다. 또한, 모든 사용자 지정 코드 액세스 권한에 대해 IUnrestrictedPermission 인터페이스를 구현해야 합니다. 명령적과 선언적 보안 지원 둘 다 사용자 지정 권한 클래스를 요구하므로 선언적 보안만 사용하는 경우에도 사용자 지정 권한 클래스를 만들어야 합니다.
![]() |
---|
사용자 지정 권한은 이 권한이 참조되는 어셈블리 이외의 다른 어셈블리에 정의되어야 합니다. 사용자 지정 권한에 선언적 보안의 보안 특성이 포함된 경우에는 사용자 지정 권한과 보안 특성을 별도의 어셈블리에 정의해야 합니다. 이는 어셈블리가 로드되면 보안 특성이 실행되는데, 이 특성이 만들어지지 않은 상태에서 참조될 수 있기 때문입니다. 보안 특성이 정의되어 있는 어셈블리에서 선언적 권한을 사용하려고 하면 TypeLoadException이 throw됩니다. |
권한 클래스 정의
CodeAccessPermission 클래스에서 파생시키려면 다음과 같은 5개의 주요 메서드를 재정의하고 사용자가 직접 구현해야 합니다.
Copy는 현재 권한 개체와 중복되는 개체를 만듭니다.
Intersect는 현재 클래스에 대해 허용된 권한과 전달된 클래스에 대해 허용된 권한의 교집합을 반환합니다.
IsSubsetOf는 현재 권한에서 허용하는 모든 내용이 전달된 권한에 포함되어 있으면 true를 반환합니다.
FromXml은 사용자 지정 권한의 XML 표현을 디코딩합니다.
ToXml은 사용자 지정 권한의 XML 표현을 인코딩합니다.
Union은 현재 권한과 지정된 권한의 합집합에 해당하는 권한을 만듭니다.
IUnrestrictedPermission 인터페이스를 사용하려면 IsUnrestrictedPermission이라는 메서드 하나를 재정의하고 구현해야 합니다. IUnrestrictedPermission 인터페이스를 지원하려면 현재 개체의 제한 상태를 나타내는 부울 값과 같은 항목을 구현하여 권한의 현재 인스턴스에 제한이 없는지 여부를 정의해야 합니다.
다음 코드 조각에서는 사용자 지정 권한 클래스를 정의하는 방법을 보여 줍니다. PermissionState 열거형을 받아 들이는 생성자와 unrestricted라는 부울 값이 모두 생성됩니다. PermissionState 열거형의 값은 Unrestricted 또는 None입니다. 전달된 열거형의 값이 Unrestricted이면 생성자는 unrestricted를 true로 설정합니다. 그렇지 않으면, unrestricted는 false로 설정됩니다. 모든 코드 액세스 권한(CodeAccessPermission에서 상속된 권한)은 사용자 지정 권한에 고유한 생성자뿐 아니라 PermissionState 열거형만 사용하는 생성자도 지원해야 합니다.
다음 예제에 나타난 코드 이외에도, IsUnrestricted 메서드를 구현하고 Copy, Intersect, IsSubsetOf, ToXML, FromXML 메서드를 재정의해야 합니다. 이러한 단계를 완료하는 방법에 대한 정보는 예제 다음 부분을 참조하십시오.
Option Strict
Option Explicit
Imports System
Imports System.Security
Imports System.Security.Permissions
<SerializableAttribute()> NotInheritable Public Class CustomPermission
Inherits CodeAccessPermission
Implements IUnrestrictedPermission
Private unrestricted As Boolean
Public Sub New(state As PermissionState)
If state = PermissionState.Unrestricted Then
unrestricted = True
Else
unrestricted = False
End If
End Sub
'Define the rest of your custom permission here. You must
'implement IsUnrestricted and override the Copy, Intersect,
'IsSubsetOf, ToXML, and FromXML methods.
End Class
using System;
using System.Security;
using System.Security.Permissions;
[SerializableAttribute()]
public sealed class CustomPermission: CodeAccessPermission, IUnrestrictedPermission
{
private bool unrestricted;
public CustomPermission(PermissionState state)
{
if(state == PermissionState.Unrestricted)
{
unrestricted = true;
}
else
{
unrestricted = false;
}
}
//Define the rest of your custom permission here. You must
//implement IsUnrestricted and override the Copy, Intersect,
//IsSubsetOf, ToXML, and FromXML methods.
}
위 예제에서 클래스는 SerializableAttribute로 표시되어 있습니다. 클래스를 SerializableAttribute로 표시해야 특성을 사용하여 선언적 구문을 지원할 수 있습니다. 사용자 지정 보안 개체를 사용하는 사용자 지정 특성을 만드는 방법에 대한 정보는 선언적 보안 지원 추가를 참조하십시오.
IsUnrestricted 메서드 구현
IsUnrestricted 메서드는 IUnrestrictedPermission 인터페이스에서 필요하며 권한의 현재 인스턴스가 권한으로 보호된 리소스를 제한 없이 액세스할 수 있는지 여부를 나타내는 부울 값을 반환합니다. 이 메서드를 구현하려면 unrestricted의 값을 반환하기만 하면 됩니다.
다음 코드 예제는 IsUnrestricted 메서드를 구현합니다.
Public Function IsUnrestricted() As Boolean Implements IUnrestrictedPermission.IsUnrestricted
Return unrestricted
End Function
public bool IsUnrestricted()
{
return unrestricted;
}
Copy 메서드 재정의
copy 메서드는 CodeAccessPermission 클래스에서 필요하며 현재 권한 클래스의 복사본을 반환합니다.
다음 코드는 Copy 메서드를 재정의하는 방법을 보여 줍니다.
Public Overrides Function Copy() As IPermission
Dim myCopy As New CustomPermission(PermissionState.None)
If Me.IsUnrestricted() Then
myCopy.unrestricted = True
Else
myCopy.unrestricted = False
End If
Return myCopy
End Function
public override IPermission Copy()
{
CustomPermission copy = new CustomPermission(PermissionState.None);
if(this.IsUnrestricted())
{
copy.unrestricted = true;
}
else
{
copy.unrestricted = false;
}
return copy;
}
Intersect 및 IsSubsetOf 메서드 재정의
모든 권한은 Intersect 및 IsSubsetOf 메서드를 구현해야 합니다. 이들 작업은 다음과 같이 작동되도록 구현되어야 합니다.
X가 허용하는 모든 작업이 권한 Y에 포함되어 있으면 X.IsSubsetOf(Y)는 true입니다.
X.Intersect(Y)는 모든 작업 및 X와 Y 권한으로 허용되는 작업만 허용하는 권한을 만듭니다.
다음 예제는 Intersect 메서드를 재정의하고 구현하는 방법을 보여 줍니다. 이 메서드는 IPermission에서 파생된 클래스를 받아 들이고 이 클래스를 CustomPermisison 개체의 새 인스턴스로 초기화합니다. 이 경우 현재 개체와 전달된 개체의 값이 "unrestricted"이면 이 두 개체의 교집합이 "unrestricted" 값을 갖는 최종 개체가 됩니다. 그러나, 두 개체 중 한 개체의 값이 "unrestricted"에 대해 false이면 최종 개체의 값도 "unrestricted"에 대해 false입니다. 이 코드는 두 개체 모두 "unrestricted"인 경우에만 제한 없는 개체를 반환합니다.
Public Overrides Function Intersect(target As IPermission) As IPermission
If Nothing Is target Then
Return Nothing
End If
Try
Dim PassedPermission As CustomPermission = CType(target, CustomPermission)
If Not PassedPermission.IsUnrestricted() Then
Return PassedPermission
End If
Return Me.Copy()
Catch InvalidCastException As Exception
Throw New ArgumentException("Argument_WrongType", Me.GetType().FullName)
End Try
End Function
public override IPermission Intersect(IPermission target)
{
try
{
if(null == target)
{
return null;
}
CustomPermission PassedPermission = (CustomPermission)target;
if(!PassedPermission.IsUnrestricted())
{
return PassedPermission;
}
return this.Copy();
}
catch (InvalidCastException)
{
throw new ArgumentException("Argument_WrongType", this.GetType().FullName);
}
}
다음 예제에서는 IsSubsetOf 메서드를 재정의합니다. 이 메서드가 true를 반환하도록 하려면 현재 인스턴스와 전달된 인스턴스에서 동일한 일련의 작업이 허용되어야 합니다. 이 경우, 재정의된 메서드는 CustomPermission 개체의 새 인스턴스를 전달된 권한 개체로 초기화합니다. unrestricted 값이 서로 동일하면 이 메서드는 true를 반환합니다. 그렇지 않으면 이 메서드는 false를 반환합니다.
Public Overrides Function IsSubsetOf(target As IPermission) As Boolean
If Nothing Is target Then
Return Not Me.unrestricted
End If
Try
Dim passedpermission As CustomPermission = CType(target, CustomPermission)
If Me.unrestricted = passedpermission.unrestricted Then
Return True
Else
Return False
End If
Catch InvalidCastException As Exception
Throw New ArgumentException("Argument_WrongType", Me.GetType().FullName)
End Try
End Function
public override bool IsSubsetOf(IPermission target)
{
if(null == target)
{
return !this.unrestricted;
}
try
{
CustomPermission passedpermission = (CustomPermission)target;
if(this.unrestricted == passedpermission.unrestricted)
{
return true;
}
else
{
return false;
}
}
catch (InvalidCastException)
{
throw new ArgumentException("Argument_WrongType", this.GetType().FullName);
}
}
ToXml 및 FromXml 메서드 재정의
권한이 XML 인코딩을 지원하므로 권한 개체를 XML로 저장할 수 있으며, 이 XML 파일을 사용하여 다른 권한 개체는 원래 값으로 복원될 수 있습니다. XML 인코딩을 지원하려면 사용자 지정 권한에서 ToXml 및 FromXml 메서드를 정의하는 ISecurityEncodable 인터페이스를 구현해야 합니다. 두 메서드 모두 CodeAccessPermission에 의해 구현되므로 사용자 지정 권한 클래스가 CodeAccessPermission에서 파생된 경우 이들 메서드를 재정의해야 합니다.
개체 상태를 나타내는 XML 요소의 콘텐츠는 개체 자체에 의해 결정됩니다. FromXML 메서드는 ToXML이 해석하여 동일한 상태로 복원할 수 있는 XML 표현이라면 모두 사용할 수 있습니다. 그러나, 이를 포함하는 Permission 요소는 표준 형식이어야 합니다. 예를 들어, CustomPermission의 형식은 다음과 같을 수 있습니다.
<IPermission class="CustomPermissions.CustomPermission, CustomPermissionAssembly " version="1" Unrestricted="True">
IPermission 요소에는 다음과 같은 세 가지 특성이 있습니다.
class: 이 클래스가 포함된 어셈블리 이름으로 명확하게 나타낸 형식 이름을 포함합니다.
version: 클래스의 어셈블리 버전이 아니라 XML 인코딩 버전을 지정합니다.
Unrestricted: 권한이 제한되지 않은 권한인지 여부를 지정합니다.
모든 권한은 IPermission이라는 XML 요소에서 인코딩되어야 공용 언어 런타임 보안 시스템에서 사용될 수 있습니다.
권한 개체의 새 버전은 이전 버전의 XML에 있는 정보와 호환되어야 합니다. 버전 태그를 사용하여 데이터를 처음 인코딩한 버전에 대한 정보를 권한 개체에 제공할 수 있습니다.
SecurityElement 클래스는 XML로 인코딩된 권한 개체를 만들어 이 개체와 상호 작용하기 위해 필요한 기본 기능을 캡슐화합니다. 그러나, .NET Framework 보안에 사용하는 XML 개체 모델이 다른 XML 개체 모델과 다르므로 SecurityElement 클래스를 사용하여 다른 형식의 XML 파일을 작성해서는 안 됩니다. SecurityElement 클래스의 멤버 목록 전체를 보려면 이 클래스에 대한 설명을 참조하십시오.
다음 코드 조각은 XML Permission 요소를 만듭니다.
Public Overrides Function ToXml() As SecurityElement
Dim element As New SecurityElement("IPermission")
Dim type As Type = Me.GetType()
Dim AssemblyName As New StringBuilder(type.Assembly.ToString())
AssemblyName.Replace(ControlChars.Quote, "'"c)
element.AddAttribute("class", type.FullName & ", " & AssemblyName.ToString)
element.AddAttribute("version", "1")
element.AddAttribute("Unrestricted", unrestricted.ToString())
Return element
End Function
public override SecurityElement ToXml()
{
SecurityElement element = new SecurityElement("IPermission");
Type type = this.GetType();
StringBuilder AssemblyName = new StringBuilder(type.Assembly.ToString());
AssemblyName.Replace('\"', '\'');
element.AddAttribute("class", type.FullName + ", " + AssemblyName);
element.AddAttribute("version", "1");
element.AddAttribute("Unrestricted", unrestricted.ToString());
return element;
}
앞의 예제에서는 StringBuilder.Replace 메서드를 사용합니다. SecurityElement 클래스의 특성에는 큰따옴표를 사용할 수 없지만, 일부 어셈블리 이름 정보에는 큰따옴표를 사용할 수 있습니다. 이런 문제를 처리하기 위해 Replace 메서드는 어셈블리 이름의 큰따옴표(")를 작은따옴표(')로 바꿉니다.
다음 메서드는 앞의 메서드가 생성한 SecurityElement 개체를 읽고 Unrestricted 속성의 현재 값을 전달된 개체가 지정한 값으로 설정합니다. 이 메서드는 ToXml 메서드가 저장한 모든 정보를 검색할 수 있어야 합니다.
Public Overrides Sub FromXml(PassedElement As SecurityElement)
Dim element As String = PassedElement.Attribute("Unrestricted")
If Not element Is Nothing Then
Me.unrestricted = Convert.ToBoolean(element)
End If
End Sub
public override void FromXml(SecurityElement PassedElement)
{
string element = PassedElement.Attribute("Unrestricted");
if(null != element)
{
this.unrestricted = Convert.ToBoolean(element);
}
}
사용자 지정 권한 예제
다음 코드 예제는 전체 사용자 지정 권한 클래스를 보여 줍니다.
Option Explicit
Option Strict
Imports System
Imports System.Text
Imports System.Security
Imports System.Security.Permissions
Imports Microsoft.VisualBasic
<Serializable()>NotInheritable Public Class CustomPermission
Inherits CodeAccessPermission
Implements IUnrestrictedPermission
Private unrestricted As Boolean
Public Sub New(state As PermissionState)
If state = PermissionState.Unrestricted Then
unrestricted = True
Else
unrestricted = False
End If
End Sub
Public Function IsUnrestricted() As Boolean Implements IUnrestrictedPermission.IsUnrestricted
Return unrestricted
End Function
Public Overrides Function Copy() As IPermission
'Create a new instance of CustomPermission with the current
'value of unrestricted.
Dim myCopy As New CustomPermission(PermissionState.None)
If Me.IsUnrestricted() Then
myCopy.unrestricted = True
Else
myCopy.unrestricted = False
End If
'Return the copy.
Return copy
End Function
Public Overrides Function Intersect(target As IPermission) As IPermission
'If nothing was passed, return null.
If Nothing Is target Then
Return Nothing
End If
Try
'Create a new instance of CustomPermission from the passed object.
Dim PassedPermission As CustomPermission = CType(target, CustomPermission)
'If one class has an unrestricted value of false, then the
'intersection will have an unrestricted value of false.
'Return the passed class with the unrestricted value of false.
If Not PassedPermission.unrestricted Then
Return target
End If
'Return a copy of the current class if the passed one has
'an unrestricted value of true.
Return Me.Copy()
'Catch an InvalidCastException.
'Throw ArgumentException to notify the user.
Catch InvalidCastException As Exception
Throw New ArgumentException("Argument_WrongType", Me.GetType().FullName)
End Try
End Function
Public Overrides Function IsSubsetOf(target As IPermission) As Boolean
'If nothing was passed and unrestricted is false,
' return true.
If Nothing Is target Then
Return Not Me.unrestricted
End If
Try
'Create a new instance of CustomPermission from the passed object.
Dim passedpermission As CustomPermission = CType(target, CustomPermission)
'If unrestricted has the same value in both objects, then
'one is the subset of the other.
If Me.unrestricted = passedpermission.unrestricted Then
Return True
Else
Return False
End If
'Catch an InvalidCastException.
'Throw ArgumentException to notify the user.
Catch InvalidCastException As Exception
Throw New ArgumentException("Argument_WrongType", Me.GetType().FullName)
End Try
End Function
Public Overrides Sub FromXml(PassedElement As SecurityElement)
'Get the unrestricted value from the XML and initialize
'the current instance of unrestricted to that value.
Dim element As String = PassedElement.Attribute("Unrestricted")
If Not element Is Nothing Then
Me.unrestricted = Convert.ToBoolean(element)
End If
End Sub
Public Overrides Function ToXml() As SecurityElement
'Encode the current permission to XML using the
'SecurityElement class.
Dim element As New SecurityElement("IPermission")
Dim type As Type = Me.GetType()
Dim AssemblyName As New StringBuilder(type.Assembly.ToString())
AssemblyName.Replace(ControlChars.Quote, "'"c)
element.AddAttribute("class", type.FullName & ", " & AssemblyName.ToString)
element.AddAttribute("version", "1")
element.AddAttribute("Unrestricted", unrestricted.ToString())
Return element
End Function
End Class
using System;
using System.Text;
using System.Security;
using System.Security.Permissions;
[Serializable()]
public sealed class CustomPermission: CodeAccessPermission , IUnrestrictedPermission
{
private bool unrestricted;
public CustomPermission(PermissionState state)
{
if(state == PermissionState.Unrestricted)
{
unrestricted = true;
}
else
{
unrestricted = false;
}
}
public bool IsUnrestricted()
{
return unrestricted;
}
public override IPermission Copy()
{
//Create a new instance of CustomPermission with the current
//value of unrestricted.
CustomPermission copy = new CustomPermission(PermissionState.None);
if(this.IsUnrestricted())
{
copy.unrestricted = true;
}
else
{
copy.unrestricted = false;
}
//Return the copy.
return copy;
}
public override IPermission Intersect(IPermission target)
{
//If nothing was passed, return null.
if(null == target)
{
return null;
}
try
{
//Create a new instance of CustomPermission from the passed object.
CustomPermission PassedPermission = (CustomPermission)target;
//If one class has an unrestricted value of false, then the
//intersection will have an unrestricted value of false.
//Return the passed class with the unrestricted value of false.
if(!PassedPermission.unrestricted)
{
return target;
}
//Return a copy of the current class if the passed one has
//an unrestricted value of true.
return this.Copy();
}
//Catch an InvalidCastException.
//Throw ArgumentException to notify the user.
catch (InvalidCastException)
{
throw new ArgumentException("Argument_WrongType", this.GetType().FullName);
}
}
public override bool IsSubsetOf(IPermission target)
{
//If nothing was passed and unrestricted is false,
//then return true.
if(null == target)
{
return !this.unrestricted;
}
try
{
//Create a new instance of CustomPermission from the passed object.
CustomPermission passedpermission = (CustomPermission)target;
//If unrestricted has the same value in both objects, then
//one is the subset of the other.
if(this.unrestricted == passedpermission.unrestricted)
{
return true;
}
else
{
return false;
}
}
//Catch an InvalidCastException.
//Throw ArgumentException to notify the user.
catch (InvalidCastException)
{
throw new ArgumentException("Argument_WrongType", this.GetType().FullName);
}
}
public override void FromXml(SecurityElement PassedElement)
{
//Get the unrestricted value from the XML and initialize
//the current instance of unrestricted to that value.
string element = PassedElement.Attribute("Unrestricted");
if(null != element)
{
this.unrestricted = Convert.ToBoolean(element);
}
}
public override SecurityElement ToXml()
{
//Encode the current permission to XML using the
//SecurityElement class.
SecurityElement element = new SecurityElement("IPermission");
Type type = this.GetType();
StringBuilder AssemblyName = new StringBuilder(type.Assembly.ToString());
AssemblyName.Replace('\"', '\'');
element.AddAttribute("class", type.FullName + ", " + AssemblyName);
element.AddAttribute("version", "1");
element.AddAttribute("Unrestricted", unrestricted.ToString());
return element;
}
}