Почему Thread.CurrentPrincipal.Identity.IsAuthenticated всегда ложно?
У меня есть этот сервис WCF, и я пытаюсь применить механизм аутентификации и авторизации в нем.
Я впервые это делаю, у меня есть этот web.config serviceModel
тег для сервиса:
<system.serviceModel>
<services>
<service name="RoleBasedServices.SecureServiceExternal" behaviorConfiguration="externalServiceBehavior">
<endpoint contract="AuthService.IService1" binding="wsHttpBinding" bindingConfiguration="wsHttpUsername" />
</service>
</services>
<bindings>
<wsHttpBinding>
<binding name="wsHttpUsername">
<security mode="Message">
<message clientCredentialType="UserName" negotiateServiceCredential="false" establishSecurityContext="false" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<!--To avoid disclosing metadata information, set the values below to false before deployment-->
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<!--To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information-->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
<behavior name="externalServiceBehavior">
<serviceAuthorization principalPermissionMode="UseAspNetRoles" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="MembershipProvider" />
<serviceCertificate findValue="RPKey" x509FindType="FindBySubjectName" storeLocation="LocalMachine" storeName="My"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="basicHttpsBinding" scheme="https" />
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
То, что я хочу сделать, очень просто, я не знаю, нужны ли мне все эти теги, которые я просто пробую. То, что я хочу сделать, это добавить со стороны клиента ссылку на службу и сначала вызвать MyLogin
:
AuthService.Service1Client s = new AuthService.Service1Client();
s.Login();
Затем вызовите другой ограниченный метод и пусть он будет GetData
:
s.GetData()
На сервисной стороне в Login
метод, и только для целей тестирования, я делаю это:
public void Login()
{
Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity("Bob"), new[] { "Admin" });
FormsAuthentication.SetAuthCookie("BobUserName", false);
}
Ограниченный метод будет:
[PrincipalPermission(SecurityAction.Demand, Role = "Admin")]
public void GetData()
{
return "Hello";
}
Это все, что у меня есть на службе и клиенте, чего мне не хватает? Каждый раз в отладке проверяю Thread.CurrentPrincipal
в Login
метод, который я нашел Thread.CurrentPrincipal.Identity.IsAuthenticated
равняется true
но даже если клиент вызывает GetData()
метод это Access Denied
,
PS: я использую консольное приложение для моих тестов.
Спасибо
2 ответа
Вот очень хорошая статья, которая может привести к решению.
Общая идея заключается в том, что у вас есть 2 объекта для принципала.HttpContext.Current.User
а также Thread.CurrentPrincipal
, Вы устанавливаете Thread.CurrentPrincipal
в это время HttpContext.Current.User
уже создан, и его роль оставлена по умолчанию.
Вы можете попробовать что-то вроде:
HttpContext.Current.User = new GenericPrincipal(new GenericIdentity("Bob"), new[] { "Admin" });
Причина звонков GetData()
отказано потому, что WCF ничего не знает о cookie-файлах проверки подлинности с помощью форм Login()
,
Не имеет значения, что вы используете консольное приложение. Вы можете попробовать следующий подход.
Установите печенье в Login()
:
var cookie = FormsAuthentication.GetAuthCookie(username, true);
var ticket = FormsAuthentication.Decrypt(cookie.Value);
HttpContext.Current.User = new GenericPrincipal(new FormsIdentity(ticket), null);
FormsAuthentication.SetAuthCookie(HttpContext.Current.User.Identity.Name, true);
Затем в вашем консольном приложении:
public static void TestLoginAndGetData()
{
var sharedCookie = string.Empty;
using (var client = new YourClient())
using (new OperationContextScope(client.InnerChannel))
{
client.Login("username", "password");
// get the cookie from the response
HttpResponseMessageProperty response = (HttpResponseMessageProperty)
OperationContext.Current.IncomingMessageProperties[
HttpResponseMessageProperty.Name];
sharedCookie = response.Headers["Set-Cookie"];
// add it to the request
HttpRequestMessageProperty request = new HttpRequestMessageProperty();
request.Headers["Cookie"] = sharedCookie;
OperationContext.Current.OutgoingMessageProperties[
HttpRequestMessageProperty.Name] = request;
var result = client.GetData();
Console.WriteLine(result);
}
}
Вы также можете рассмотреть возможность изменения типа возвращаемого значения GetData()
в string
,