IdentityServer4 заменяет Asp.net 4.5 MVC5 SimpleMembership для аутентификации - PullRequest
1 голос
/ 27 июня 2019

У меня есть приложение Asp.net 4.5 MVC5, использующее SimpleMembership для аутентификации и авторизации в приложении.Теперь мне нужно интегрировать, чтобы использовать внешний IdentityServer4 для аутентификации.Я попытался добавить файл запуска OWIN в проект и отключить стандартную аутентификацию IIS в web.config.Теперь я могу быть перенаправлен на IDServer для входа и согласия.

Произошла ошибка при получении доступа к представлению:

Сообщение об ошибке:

Не найдено ни одного пользователя с именем "",Описание: во время выполнения текущего веб-запроса произошло необработанное исключение.Пожалуйста, просмотрите трассировку стека для получения дополнительной информации об ошибке и о том, где она возникла в коде.

Сведения об исключении: System.InvalidOperationException: не найдено ни одного пользователя с именем "".

Ошибка источника:

Строка 15: @if (Model! = Null) Строка 16: {Строка 17:
foreach (утверждение var в модели) Строка 18: {Строка 19:

@claim.Type

Исходный файл: e: \GitHub \ CRURepoPostBR20190607_IS4 \ CRU_Build \ Suite \ Views \ Home \ IS4Auth.cshtml Строка: 17

Трассировка стека: [InvalidOperationException: Не найдено ни одного пользователя с именем "".] *
WebMatrix.WebData.SimpleRoleProvider.GetRolesForUser (имя пользователя String) +498 System.Web.Security.RolePrincipal.GetRoles () +215 System.Web.Security.d__4.MoveNext () + 58
System.Security.Claims.d__51.MoveNext (253
System.Security.Claims.d__37.MoveNext () + 209

Мой IdentityServer является клоном примера быстрого запуска IdentityServer4.Мое приложение MVC5 устарело и использует SimpleMembership для аутентификации и авторизации ролей.Я вручную добавил OWIN Startup.cs, см. Код ниже.

Я попытался использовать IdentityServer https://demo.identityserver.io в качестве IDServer и получил ту же проблему.Это доказало, что у моего IDServer нет проблем.

Я пытался создать простой отдельный проект Asp.net 4.5 MVC5 без SimpleMembership, он не получил ошибку.

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = "Cookies"
        });
        app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
        {
            AuthenticationType = "oidc",
            SignInAsAuthenticationType = "Cookies",
            ClientSecret = "secret",

            //Authority = "http://localhost:5000", //ID Server
            Authority = "https://demo.identityserver.io", //ID Server
            RequireHttpsMetadata = false,
            RedirectUri = "http://localhost:58018/signin-oidc",
            //RedirectUri = "http://localhost:58018/",
            //ClientId = "myOldMvc",
            ClientId = "server.hybrid",

            ResponseType = "id_token code",
            Scope = "openid profile",
        });
        AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
    }
}

Вот представление для отображения претензии:

@model IEnumerable<System.Security.Claims.Claim>

@{
    ViewBag.Title = "IS4Auth";
}

<h2>IS4Auth</h2>

<dl>

    @if (Model != null)
    {
        foreach (var claim in Model)
        {
            <dt>@claim.Type</dt>
            <dd>@claim.Value</dd>
        }
    }
</dl>

здесь моя часть, связанная с конфигом для system.web и system.webServer

<system.web>
    <httpModules>
      <add name="ar.sessionscope" type="Castle.ActiveRecord.Framework.SessionScopeWebModule, Castle.ActiveRecord.web" />
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" />
      <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" />
      <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" />
    </httpModules>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" maxRequestLength="1048576" />
    <!--Change for IS4Authentication-->
    <authentication mode="None" />
    <!--<authentication mode="Forms">
      <forms loginUrl="~/Account/Login" timeout="2880" />
    </authentication>-->
    <!--<roleManager enabled="true" defaultProvider="simple">
      <providers>
        <clear />
        <add name="simple" type="WebMatrix.WebData.SimpleRoleProvider,WebMatrix.WebData" />
      </providers>
    </roleManager>
    <membership defaultProvider="simple">
      <providers>
        <clear />
        <add name="simple" type="WebMatrix.WebData.SimpleMembershipProvider,WebMatrix.WebData" enablePasswordReset="true" requiresQuestionAndAnswer="false" />
      </providers>
    </membership>-->
    <pages>
      <namespaces>
        <add namespace="System.Web.Helpers" />
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Optimization" />
        <add namespace="System.Web.Routing" />
        <add namespace="System.Web.WebPages" />
      </namespaces>
    </pages>
    <httpHandlers>
      <add verb="*" path="routes.axd" type="AttributeRouting.Web.Logging.LogRoutesHandler, AttributeRouting.Web" />
      <add verb="POST,GET,HEAD" path="elmah" type="Elmah.ErrorLogPageFactory, Elmah" />
    </httpHandlers>
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <handlers>
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
      <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
      <add name="Elmah" verb="POST,GET,HEAD" path="elmah" type="Elmah.ErrorLogPageFactory, Elmah" />
    </handlers>
    <modules>
      <!--Change for IS4Authentication-->
      <remove name="FormsAuthentication" />
      <add name="ErrorLog" type="Elmah.ErrorLogModule, Elmah" preCondition="managedHandler" />
      <add name="ErrorMail" type="Elmah.ErrorMailModule, Elmah" preCondition="managedHandler" />
      <add name="ErrorFilter" type="Elmah.ErrorFilterModule, Elmah" preCondition="managedHandler" />
    </modules>
    <httpProtocol>
      <customHeaders>
        <clear />
        <add name="X-UA-Compatible" value="IE=Edge" />
      </customHeaders>
    </httpProtocol>

  </system.webServer>

Вот код уведомлений, добавленный в OpenIdConnectAuthenticationOptions

    Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    AuthorizationCodeReceived = async n =>
                    {
                        // use the code to get the access and refresh token
                        var tokenClient = new TokenClient(
                            "http://localhost:5000/connect/token",
                            //"server.hybrid",
                            "myApp",
                            "secret");

                        var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(n.Code, n.RedirectUri);

                        if (tokenResponse.IsError)
                        {
                            //throw new Exception(tokenResponse.Error);
                            throw new AuthenticationException(tokenResponse.Error);
                        }

                        // use the access token to retrieve claims from userinfo
                        var userInfoClient = new UserInfoClient("http://localhost:5000/connect/userinfo");
                        var userInfoResponse = await userInfoClient.GetAsync(tokenResponse.AccessToken);

                        // create new identity
                        var id = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType);
                        id.AddClaims(userInfoResponse.Claims);
                        var Name = userInfoResponse.Claims.FirstOrDefault(c => c.Type.Equals("Name", StringComparison.CurrentCultureIgnoreCase)).Value;
                        id.AddClaim(new Claim("access_token", tokenResponse.AccessToken));
                        id.AddClaim(new Claim("expires_at", DateTime.Now.AddSeconds(tokenResponse.ExpiresIn).ToLocalTime().ToString()));
                        id.AddClaim(new Claim("refresh_token", tokenResponse.RefreshToken));
                        id.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
                        id.AddClaim(new Claim("sid", n.AuthenticationTicket.Identity.FindFirst("sid").Value));

                        n.AuthenticationTicket = new AuthenticationTicket(
                            new ClaimsIdentity(id.Claims, n.AuthenticationTicket.Identity.AuthenticationType, JwtClaimTypes.Name, JwtClaimTypes.Role),
                            n.AuthenticationTicket.Properties
                        );

                        List<Claim> _claims = new List<Claim>();
                        _claims.AddRange(new List<Claim>
                        {
                            new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", Name),
                            new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider",Name)
                        });
                    },

                    RedirectToIdentityProvider = n =>
                    {
                        if (n.ProtocolMessage.RequestType != OpenIdConnectRequestType.Logout)
                        {
                            return Task.FromResult(0);
                        }

                        var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");

                        if (idTokenHint != null)
                        {
                            n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
                        }

                        return Task.FromResult(0);
                    }
         }  

1 Ответ

0 голосов
/ 02 июля 2019

Спасибо за помощь d_f, моя проблема решена. Решение состоит в том, чтобы использовать Уведомления для явного извлечения претензий из userInfo EndPoint и добавления их в новую личность. Посмотрите код выше в Уведомлениях = новый OpenIdConnectAuthenticationNotifications {}

...