Я бы хотел использовать Identity Server 3 в качестве кэширующей аутентификации для внешнего провайдера идентификации. Я пытаюсь объединить 2 примера предоставленных примеров отсюда> https://github.com/IdentityServer/IdentityServer3.Samples
Моя цель - перенаправить пользователя из приложения MVC 5 на внешний адрес для сделать его / ее логин там (локальный логин отключен). Мы можем изменить поведение прослушивающего приложения MVC, поэтому я могу добавить необходимые изменения результата Cookie / HttpPost, чтобы это работало. Я застрял с. NET 4.6.2 tho. При успешном входе в систему я хотел бы запросить внешний источник для утверждений и ролей. Поэтому я копирую части CustomUserService
, MVC Authentication
примеров.
Когда у меня будет первый логин пользователя на внешнем сайте, я сохраню экземпляр InMemoryUser
в измененном UserServiceBase
, поэтому второй вход в систему за время существования памяти не должен go к внешнему ресурсу. Остальные обрабатываются с Bearer
аутентификацией, идентификация подается из пользовательского UserServiceBase
. Всякий раз, когда аннотируется [Authorize(Roles = "SomeRole")]
, внешний сайт также запрашивается для проверки с помощью пользовательского токена, указывающего c для внешнего сайта (вызов Web api к нему). Я даже не могу добраться до этой части, потому что частичный вход в систему и перенаправление, которые я не могу объединить.
Нет значимых scope
требований. Внешний сайт дает все для создания Claims
для пользователя. Пока в разработке нет ни сертификата, ни требования https.
Полагаю, это будет PartialLogin
. Я не могу заставить его работать, поэтому данная конечная точка externalregistration
не дает мне 404, или бесконечное перенаправление, или пропускает частичную информацию для входа.
В данный момент мой код выдает 404, хотя указанные места Мне нужно Map
, где мой сервер сопоставлен с .
Startup.cs
public void Configuration(IAppBuilder app)
{
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
Authority = "http://localhost:20000/identity",
ClientId = "aa",
ClientSecret = "secret",
Scope = "openid profile roles sampleApi",
ResponseType = "id_token token",
RedirectUri = "http://localhost:20000/",
SignInAsAuthenticationType = "idsrv",
UseTokenLifetime = false,
Notifications = new OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated = async n =>
{
// I don't get there, so it doesn't really matter.
var nid = new ClaimsIdentity(
n.AuthenticationTicket.Identity.AuthenticationType,
Constants.ClaimTypes.GivenName,
Constants.ClaimTypes.Role);
// get userinfo data
var userInfoClient = new UserInfoClient(
new Uri(n.Options.Authority + "/connect/userinfo"),
n.ProtocolMessage.AccessToken);
var userInfo = await userInfoClient.GetAsync();
userInfo.Claims.ToList().ForEach(ui => nid.AddClaim(new Claim(ui.Item1, ui.Item2)));
// keep the id_token for logout
nid.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
// add access token for sample API
nid.AddClaim(new Claim("access_token", n.ProtocolMessage.AccessToken));
// keep track of access token expiration
nid.AddClaim(new Claim("expires_at", DateTimeOffset.Now.AddSeconds(int.Parse(n.ProtocolMessage.ExpiresIn)).ToString()));
// add some other app specific claim
nid.AddClaim(new Claim("app_specific", "some data"));
n.AuthenticationTicket = new AuthenticationTicket(
nid,
n.AuthenticationTicket.Properties);
},
RedirectToIdentityProvider = n =>
{
if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
{
var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");
if (idTokenHint != null)
{
n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
}
}
return Task.FromResult(0);
}
}
});
app.Map("/identity", idsrvApp =>
{
var factory = new IdentityServerServiceFactory()
.UseInMemoryClients(Clients.Get())
.UseInMemoryScopes(Scopes.Get());
factory.UserService = new Registration<IUserService, ExternalRegistrationUserService>();
var options = new IdentityServerOptions
{
RequireSsl = false,
EnableWelcomePage = false,
//SigningCertificate = LoadCertificate(),
Factory = factory,
AuthenticationOptions = new IdentityServer3.Core.Configuration.AuthenticationOptions
{
EnableLocalLogin = false
},
LoggingOptions = new LoggingOptions
{
EnableWebApiDiagnostics = true,
WebApiDiagnosticsIsVerbose = true,
EnableHttpLogging = true,
EnableKatanaLogging = true
}
};
idsrvApp.UseIdentityServer(options);
});
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
Clients.cs
public static class Clients
{
public static IEnumerable<Client> Get()
{
return new[]
{
new Client
{
ClientName = "MVC Client",
ClientId = "aa",
Flow = Flows.Implicit,
ClientSecrets = new List<Secret>
{
new Secret("secret".Sha256())
},
RedirectUris = new List<string>
{
"http://localhost:20000/"
},
PostLogoutRedirectUris = new List<string>
{
"http://localhost:20000/"
},
AllowedScopes = new List<string>
{
"openid",
"profile",
"roles",
"sampleApi"
}
}
};
}
}
ExternalRegistrationUserService.cs
using AuthenticateResult = IdentityServer3.Core.Models.AuthenticateResult;
public class ExternalRegistrationUserService : UserServiceBase
{
private readonly OwinContext _ctx;
public ExternalRegistrationUserService(OwinEnvironmentService owinEnv)
{
_ctx = new OwinContext(owinEnv.Environment);
}
public static List<InMemoryUser> Users = new List<InMemoryUser>();
public override Task PreAuthenticateAsync(PreAuthenticationContext context)
{
var id = _ctx.Request.Query.Get("signin");
// I get there, and the id is a generated code/token/whatever.
context.AuthenticateResult = new AuthenticateResult("/identity/externalregistration", id, "Alma",
identityProvider: "idsrv", authenticationMethod: Constants.PartialSignInAuthenticationType);
return Task.FromResult(0);
}
public override Task AuthenticateExternalAsync(ExternalAuthenticationContext context)
{
// I don't get there.
var id = _ctx.Request.Query.Get("signin");
context.AuthenticateResult = new AuthenticateResult("/identity/externalregistration", id, "Alma",
identityProvider: "idsrv", authenticationMethod: Constants.PartialSignInAuthenticationType);
return Task.FromResult(0);
}
public override Task GetProfileDataAsync(ProfileDataRequestContext context)
{
// issue the claims for the user
var user = Users.SingleOrDefault(x => x.Subject == context.Subject.GetSubjectId());
if (user != null)
{
context.IssuedClaims = user.Claims.Where(x => context.RequestedClaimTypes.Contains(x.Type));
}
return Task.FromResult(0);
}
}
AuthenticationController.cs
public class AuthenticationController : Controller
{
[Route("identity/externalregistration")]
[HttpGet]
public ActionResult Index()
{
// I don't get there.
var ctx = Request.GetOwinContext();
// If I don't route it below identity/externalregistration, than the variables below are empty.
var authentication = ctx.Authentication.AuthenticateAsync(Constants.PartialSignInAuthenticationType).GetAwaiter().GetResult();
var dummy = ctx.Environment.GetIdentityServerPartialLoginAsync().GetAwaiter().GetResult();
var resumeUrl = ctx.Environment.GetPartialLoginResumeUrlAsync().GetAwaiter().GetResult();
// external login page
return Redirect("http://localhost:30000/Account/Login");
}
// there will be a Post version, where the 30000 port endpoint Redirects to.
...
}
Журналы