上一个章节提到了数据持久化

下面说一说自定义登录界面,Idr3提供了很多服务接口,其中一个就是 ViewService,我们只需要去注册 IViewService 这个接口的实现

提供了一个泛型视图服务类继承了IViewService,网上能找到这个类我这里也贴出来

 public class IdSvrMvcViewService<TController> : IViewService
where TController : ControllerBase
{
/// <summary>
/// We will use the DefaultViewService to do the brunt of our work
/// </summary>
private readonly DefaultViewService defaultViewService; private readonly DefaultViewServiceOptions config; private readonly ResourceCache cache = new ResourceCache(); private readonly HttpContextBase httpContext; private readonly IControllerFactory controllerFactory; private readonly ViewEngineCollection viewEngineCollection; #region Constructors public IdSvrMvcViewService(HttpContextBase httpContext)
: this(
httpContext,
new DefaultViewServiceOptions(),
new FileSystemWithEmbeddedFallbackViewLoader(),
ControllerBuilder.Current.GetControllerFactory(),
ViewEngines.Engines)
{
} public IdSvrMvcViewService(
HttpContextBase httpContext,
DefaultViewServiceOptions config,
IViewLoader viewLoader,
IControllerFactory controllerFactory,
ViewEngineCollection viewEngineCollection)
{
this.httpContext = httpContext;
this.config = config;
this.defaultViewService = new DefaultViewService(this.config, viewLoader);
this.controllerFactory = controllerFactory;
this.viewEngineCollection = viewEngineCollection;
} #endregion #region Override public Task<Stream> Login(LoginViewModel model, SignInMessage message)
{
return this.GenerateStream(
model,
message,
"login",
() => this.defaultViewService.Login(model, message));
} public Task<Stream> Logout(LogoutViewModel model, SignOutMessage message)
{
return this.GenerateStream(
model,
"logout",
() => this.defaultViewService.Logout(model, message));
} public Task<Stream> LoggedOut(LoggedOutViewModel model, SignOutMessage message)
{
return this.GenerateStream(
model,
"loggedOut",
() => this.defaultViewService.LoggedOut(model, message));
} public Task<Stream> Consent(ConsentViewModel model, ValidatedAuthorizeRequest authorizeRequest)
{
return this.GenerateStream(
model,
"consent",
() => this.defaultViewService.Consent(model, authorizeRequest));
} public Task<Stream> ClientPermissions(ClientPermissionsViewModel model)
{
// For some reason, this is referred to as "Permissions" instead of "ClientPermissions" in Identity Server.
// This is hardcoded into their CSS so cannot be changed (unless you are overriding all their CSS)
// This must also be in lower case for the same reason
return this.GenerateStream(
model,
"permissions",
() => this.defaultViewService.ClientPermissions(model));
} public Task<Stream> Error(ErrorViewModel model)
{
return this.GenerateStream(
model,
"error",
() => this.defaultViewService.Error(model));
} #endregion #region Generate Stream private Task<Stream> GenerateStream<TViewModel, TMessage>(
TViewModel model,
TMessage message,
string actionName,
Func<Task<Stream>> fallbackFunc)
where TViewModel : CommonViewModel
where TMessage : Message
{
var result = this.GenerateHtml(actionName, model, message); // If we've not been able to generate the HTML, use the fallbackFunc to do so
if (string.IsNullOrWhiteSpace(result))
{
if (fallbackFunc != null)
{
return fallbackFunc();
} return Task.FromResult(this.StringToStream(string.Empty));
} return this.Render(model, actionName, result);
} private Task<Stream> GenerateStream<TViewModel>(
TViewModel model,
string actionName,
Func<Task<Stream>> fallbackFunc)
where TViewModel : CommonViewModel
{
return GenerateStream<TViewModel, Message>(model, null, actionName, fallbackFunc);
} private string GenerateHtml(
string actionName,
object model = null,
object message = null)
{
// We want to use Razor to render the HTML since that will allow us to reuse components accross the IdentityServer & root website
// This is based on code found here:
// http://weblog.west-wind.com/posts/2012/May/30/Rendering-ASPNET-MVC-Views-to-String // Find the controller in question
var controllerName = typeof(TController).Name.ToLower().Replace("controller", String.Empty);
var controller = this.FindController(controllerName) as TController; // If we were unable to find one
if (controller == null)
{
// Stop processing
return null;
} // Create storage for the Html result
var generatedContent = string.Empty; // Find the Action in Question
var actionDescriptor = this.FindAction(controller, actionName, model, message); // If we were able to find one
if (actionDescriptor != null)
{
// Try to initiate an Action to generate the HTML
// this is never cached since the Action may render different HTML based on the model/message
generatedContent = this.ExecuteAction(controller, actionDescriptor, model, message);
} // If we either haven't found an action that was useable,
// or the action did not return something we can use
// try rendering the Razor view directly
if (string.IsNullOrWhiteSpace(generatedContent))
{
// If caching is disabled, generate every time
if (!this.config.CacheViews)
{
generatedContent = this.LoadRazorViewDirect(controller, actionName);
}
else
{
// Otherwise, load the Razor view from the cache
generatedContent = this.cache.Read(actionName); // If we've not found this in the cache...
if (string.IsNullOrWhiteSpace(generatedContent))
{
// generate now
generatedContent = this.LoadRazorViewDirect(controller, actionName); // And store in the cache for next time
this.cache.Write(actionName, generatedContent);
}
}
} // Regardless, release the controller now we're done
ControllerBuilder.Current.GetControllerFactory().ReleaseController(controller); // And return any HTML we might have generated
return generatedContent;
} /// <summary>
/// Locate a Controller with the given name in the current MVC context
/// </summary>
/// <param name="controllerName"></param>
/// <returns></returns>
private ControllerBase FindController(string controllerName)
{
// Create the appropriate Route Data
var routeData = new RouteData();
routeData.Values.Add("controller", controllerName); // FUTURE: Fake HttpContext
// We need to to generate a different httpContext every time so that when we execute
// the controller, it cannot accidentally manipulate or close this current (outer) request.
// However, by creating a new empty request we loose all the context information that
// the Controller will need to make its decisions.
// There are therefore only 2 options:
// (1) Uses a fake HttpContext
// THEN
// Calls to controller.Execute are always OK
// BUT
// Anything that requires context information, such as
// context.GetOverriddenUserAgent() OR
// fakeHttpContext.GetOwinContext()
// fails since the fake Request has lost all the info of the genuine Request
// (2) Use the current (real) HttpContext
// THEN
// All Headers, User Agents, Session etc can be accessed by the controller
// BUT
// If anything doesn't work during the Controller.Execute (i.e. the authentication
// fails with a wrong password) then the UserService does something that closes the
// Request (presumably because it's controller thinks it has completed the request
// and issues a redirect to the Error page). This results in the following error
// when the Error page tries to process:
// "This method or property is not supported after HttpRequest.GetBufferlessInputStream has been invoked."
// For now, we'll use a fake HttpContext for now, and copy all the
// the pertinent information from the genuine Request into the fake one.
// It's worth noting that (A) it uses reflection and will
// therefore be slow, and (B) only the information I know that we need has been
// copied accross - making it not future proof. What if we change the code and
// need access to a different Request property that we haven't copied to our fake context?
Debug.Assert(this.httpContext.Request.Url != null, "httpContext.Request.Url != null");
var fakeHttpRequest = new HttpRequest(
null,
this.httpContext.Request.Url.ToString(),
this.httpContext.Request.Url.Query);
var fakeHttpResponse = new HttpResponse(null);
var fakeHttpContext = new HttpContext(fakeHttpRequest, fakeHttpResponse);
var fakeHttpContextWrapper = new HttpContextWrapper(fakeHttpContext);
var fakeRequestContext = new RequestContext(fakeHttpContextWrapper, routeData); // Needed for authentication
foreach (var key in this.httpContext.Request.Cookies.AllKeys)
{
var cookie = this.httpContext.Request.Cookies[key];
if (cookie != null)
{
fakeHttpRequest.Cookies.Set(cookie);
}
} // Needed for "owin.environment"
foreach (var key in this.httpContext.Items.Keys)
{
fakeHttpContext.Items[key] = this.httpContext.Items[key];
} // Needed for "User-Agent" in out DisplayModeProvider
// From: http://stackoverflow.com/a/13307238
var t = this.httpContext.Request.Headers.GetType();
t.InvokeMember(
"MakeReadWrite",
BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
null,
fakeHttpRequest.Headers,
null);
t.InvokeMember(
"InvalidateCachedArrays",
BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
null,
fakeHttpRequest.Headers,
null);
foreach (var key in this.httpContext.Request.Headers.AllKeys)
{
var item = new ArrayList { this.httpContext.Request.Headers[key] };
t.InvokeMember(
"BaseAdd",
BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
null,
fakeHttpRequest.Headers,
new object[] { key, item });
} t.InvokeMember(
"MakeReadOnly",
BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
null,
fakeHttpRequest.Headers,
null); // Use the Controller Factory to find the relevant controller
var controller = this.controllerFactory.CreateController(fakeRequestContext, controllerName) as ControllerBase; if (controller != null)
{
// Setup the context
controller.ControllerContext = new ControllerContext(fakeHttpContextWrapper, routeData, controller);
} return controller;
} /// <summary>
/// Find a specific Action in the located Controller based on the name supplied.
/// Where multiple Actions of that name exist, use the version that matches the maximum number of available/applicable parameters.
/// </summary>
/// <param name="controller">The controller containing the action</param>
/// <param name="actionName">The Action to find in the controller</param>
/// <param name="model">The Model that should be passed to the Action if possible</param>
/// <param name="message">The Message that should be passed to the Action if possible</param>
/// <returns></returns>
private ActionDescriptor FindAction(
ControllerBase controller,
string actionName,
object model = null,
object message = null)
{
// Now get the Metadata about the controller
var controllerDescriptor = new ReflectedControllerDescriptor(controller.GetType()); // List all matching actions
var actionDescriptor = controllerDescriptor.GetCanonicalActions()
.Where(
ad => // that have the correct name AND
ad.ActionName.ToLower() == actionName.ToLower() &&
this.HasAcceptableParameters(ad, model, message)) // Now put the largest number of parameters first
.OrderByDescending(ad => ad.GetParameters().Count()) // And that the top one
.FirstOrDefault(); // If we were able to find it
if (actionDescriptor != null)
{
// Add the action name into the RouteData
controller.ControllerContext.RouteData.Values.Add("action", actionName);
} return actionDescriptor;
} /// <summary>
/// Inject the Model &amp; Message into the parameters that will be passed to this Action (if appropriate parameters are available).
/// </summary>
/// <param name="controller">The controller that contains this action</param>
/// <param name="actionDescriptor">The Action in the Controller that is going to be executed</param>
/// <param name="model">The Model that should be passed to the Action if possible</param>
/// <param name="message">The Message that should be passed to the Action if possible</param>
private void PopulateActionParameters(
ControllerBase controller,
ActionDescriptor actionDescriptor,
object model = null,
object message = null)
{
if (actionDescriptor.ControllerDescriptor.ControllerType != controller.GetType())
{
throw new ArgumentException("actionDescriptor does not describe a valid action for the controller supplied");
} if (!this.HasAcceptableParameters(actionDescriptor, model, message))
{
throw new ArgumentException("actionDescriptor does not have valid parameters that can be populated");
} // Extract the Actions Parameters
var parameters = actionDescriptor.GetParameters(); // Extract the parameters we're likely to be filling in
var firstParam = actionDescriptor.GetParameters().FirstOrDefault();
var lastParam = actionDescriptor.GetParameters().LastOrDefault(); // If we're expecting 1, assign either the model or message
if (parameters.Count() == && (model != null || message != null) && firstParam != null)
{
// If it's assignable from Model
if (model != null && firstParam.ParameterType.IsAssignableFrom(model.GetType()))
{
controller.ControllerContext.RouteData.Values[firstParam.ParameterName] = model;
}
else if (message != null) // Don't need to double check this because the HasAcceptableParameters method has already done this
/* if (message != null && firstParam.ParameterType.IsAssignableFrom(message.GetType())) */
{
controller.ControllerContext.RouteData.Values[firstParam.ParameterName] = message;
}
} // If we're expecting 2, assign both the correct way round
else if (parameters.Count() == && model != null && message != null && firstParam != null &&
lastParam != null)
{
if (
firstParam.ParameterType.IsAssignableFrom(model.GetType()) &&
lastParam.ParameterType.IsAssignableFrom(message.GetType()))
{
controller.ControllerContext.RouteData.Values[firstParam.ParameterName] = model;
controller.ControllerContext.RouteData.Values[lastParam.ParameterName] = message;
}
else // Don't need to double check this because the HasAcceptableParameters method has already done this
/*
if (
firstParam.ParameterType.IsAssignableFrom(message.GetType()) &&
lastParam.ParameterType.IsAssignableFrom(model.GetType()))
*/
{
controller.ControllerContext.RouteData.Values[firstParam.ParameterName] = message;
controller.ControllerContext.RouteData.Values[lastParam.ParameterName] = model;
}
}
} /// <summary>
/// Execute this Action (injecting appropriate parameters are available).
/// </summary>
/// <param name="controller">
/// The controller that contains this action
/// </param>
/// <param name="actionDescriptor">
/// The Action in the Controller that is going to be executed
/// </param>
/// <param name="model">
/// The Model that should be passed to the Action if possible
/// </param>
/// <param name="message">
/// The Message that should be passed to the Action if possible
/// </param>
/// <returns>
/// The <see cref="string"/>.
/// </returns>
private string ExecuteAction(
ControllerBase controller,
ActionDescriptor actionDescriptor,
object model = null,
object message = null)
{
// Populate the Action Parameters
this.PopulateActionParameters(controller, actionDescriptor, model, message); // Whilst Capturing the output ...
using (var it = new ResponseCapture(controller.ControllerContext.RequestContext.HttpContext.Response))
{
// Execute the Action (this will automatically invoke any attributes)
(controller as IController).Execute(controller.ControllerContext.RequestContext); // Check for valid status codes
// EDFUTURE: For now, we only accept methods that produce standard HTML,
// 302 Redirects and other possibly valid responses are ignored since we
// don't need them at the moment and aren't coding to cope with them
if ((HttpStatusCode)controller.ControllerContext.RequestContext.HttpContext.Response.StatusCode == HttpStatusCode.OK)
{
// And return the generated HTML
return it.ToString();
} return null;
} // FUTURE: Fake HttpContext (continued...)
// The code above assumes that a fake HttpContext is in use for this controller
// (controller as IController).Execute(controller.ControllerContext.RequestContext);
// otherwise we have the problem described in my initial "Fake HttpContext" comments.
//
// It possible instead to execute the Action directly to avoid the problem
// of filter performing unexpected manipulations to the Response and Request,
// by using this code:
// actionDescriptor.Execute(controller.ControllerContext, parameters);
// but of course, this means that our filters (such as our [SetDisplayMode] attribute
// are never run and thus, the result is not as expected.
//
// As an alternative to, it may be possible to recreate the (controller as IController).Execute(...)
// ourselves, but bypass the specific filters that cause unexpected manipulations to the Response and Request.
//
// from Controller.Execute:
// ActionInvoker.InvokeAction(ControllerContext, actionName)
// from ControllerActionInvoker.InvokeAction:
// FilterInfo filterInfo = GetFilters(controllerContext, actionDescriptor);
//
// // Check no authentication issues
// AuthenticationContext authenticationContext = InvokeAuthenticationFilters(controllerContext, filterInfo.AuthenticationFilters, actionDescriptor);
// if (authenticationContext.Result == null)
// {
//
// // Check no authorization issues
// AuthorizationContext authorizationContext = InvokeAuthorizationFilters(controllerContext, filterInfo.AuthorizationFilters, actionDescriptor);
// if (authorizationContext.Result == null)
// {
//
// // Validate the Request
// if (controllerContext.Controller.ValidateRequest)
// {
// ValidateRequest(controllerContext);
// }
//
// // Run the Action
// IDictionary<string, object> parameters = GetParameterValues(controllerContext, actionDescriptor);
// ActionExecutedContext postActionContext = InvokeActionMethodWithFilters(controllerContext, filterInfo.ActionFilters, actionDescriptor, parameters);
//
// // The action succeeded. Let all authentication filters contribute to an action result (to
// // combine authentication challenges; some authentication filters need to do negotiation
// // even on a successful result). Then, run this action result.
// AuthenticationChallengeContext challengeContext = InvokeAuthenticationFiltersChallenge(controllerContext, filterInfo.AuthenticationFilters, actionDescriptor, postActionContext.Result);
// InvokeActionResultWithFilters(controllerContext, filterInfo.ResultFilters, challengeContext.Result ?? postActionContext.Result);
//
// ...
} /// <summary>
/// Check that the Action has parameters that are acceptable, i.e. one of these:
/// No parameter
/// 1 parameter that matches the model
/// 1 parameter that matches the message
/// 2 parameters matching the model &amp; message (or vice versa)
/// </summary>
/// <param name="actionDescriptor">The Action in the Controller that is going to be executed</param>
/// <param name="model">The Model that should be passed to the Action if possible</param>
/// <param name="message">The Message that should be passed to the Action if possible</param>
/// <returns></returns>
[System.Diagnostics.Contracts.Pure]
private bool HasAcceptableParameters(
ActionDescriptor actionDescriptor,
object model = null,
object message = null)
{
var parameters = actionDescriptor.GetParameters(); // Has either no parameters OR
if (!parameters.Any())
{
return true;
} // Has 1 parameter ...
if (parameters.Count() ==
&& ( // ...that accepts either the Model or the Message (and we have a model or a message)
(model != null && parameters.First().ParameterType.IsAssignableFrom(model.GetType())) ||
(message != null && parameters.First().ParameterType.IsAssignableFrom(message.GetType()))))
{
return true;
} // Has 2 parameters ...
if (parameters.Count() == && model != null && message != null
&& (( // ... where one accepts the Model and the other accepts the Message
parameters.First().ParameterType.IsAssignableFrom(model.GetType())
&& parameters.Last().ParameterType.IsAssignableFrom(message.GetType()))
|| (parameters.Last().ParameterType.IsAssignableFrom(model.GetType())
&& parameters.First().ParameterType.IsAssignableFrom(message.GetType()))))
{
return true;
} return false;
} /// <summary>
/// Temporarily replace the Response.Output with a StringWriter for the duration of the ResponseCaptures lifetime
/// Usage:
/// using (var rc = new ResponseCapture(controller.ControllerContext.RequestContext.HttpContext.Response))
/// {
/// ...
/// return rc.ToString();
/// }
/// From: http://approache.com/blog/render-any-aspnet-mvc-actionresult-to/
/// </summary>
private class ResponseCapture : IDisposable
{
private readonly HttpResponseBase response; private readonly TextWriter originalWriter; private StringWriter localWriter; public ResponseCapture(HttpResponseBase response)
{
this.response = response;
this.originalWriter = response.Output;
this.localWriter = new StringWriter();
response.Output = this.localWriter;
} public override string ToString()
{
this.localWriter.Flush();
return this.localWriter.ToString();
} public void Dispose()
{
if (this.localWriter != null)
{
this.localWriter.Dispose();
this.localWriter = null;
this.response.Output = this.originalWriter;
}
}
} #endregion #region Load Razor view direct /// <summary>
/// Renders the "/views/controllername/actionname.cshtml" view (if it exists)
/// using the Razor ViewEngine but without passing it through the Controller action
/// </summary>
/// <param name="controller"></param>
/// <param name="viewName"></param>
/// <returns></returns>
private string LoadRazorViewDirect(ControllerBase controller, string viewName)
{
// Find the appropriate View
var viewResult = this.viewEngineCollection.FindView(controller.ControllerContext, viewName, null); // If we've been able to find one
if (viewResult != null && viewResult.View != null)
{
// Store the result in a StringWriter
using (var sw = new StringWriter())
{
// Setup the ViewContext
var viewContext = new ViewContext(
controller.ControllerContext,
viewResult.View,
controller.ViewData,
controller.TempData,
sw); // Render the View
viewResult.View.Render(viewContext, sw); // Dispose of the View
viewResult.ViewEngine.ReleaseView(controller.ControllerContext, viewResult.View); // Output the resultant HTML string
return sw.GetStringBuilder().ToString();
}
} return null;
} #endregion #region Taken from IdentityServer3.Core.Services.Default.DefaultViewService /// <summary>
/// Render the Html in the same way that the DefaultViewService does
/// </summary>
/// <param name="model"></param>
/// <param name="page"></param>
/// <param name="html"></param>
/// <param name="clientName"></param>
/// <returns></returns>
private Task<Stream> Render(
CommonViewModel model,
string page,
string html,
string clientName = null)
{
Uri uriSiteUrl;
var applicationPath = string.Empty;
if (Uri.TryCreate(model.SiteUrl, UriKind.RelativeOrAbsolute, out uriSiteUrl))
{
if (uriSiteUrl.IsAbsoluteUri)
{
applicationPath = uriSiteUrl.AbsolutePath;
}
else
{
applicationPath = uriSiteUrl.OriginalString;
if (applicationPath.StartsWith("~/"))
{
applicationPath = applicationPath.TrimStart('~');
}
} if (applicationPath.EndsWith("/"))
{
applicationPath = applicationPath.Substring(, applicationPath.Length - );
}
} var json = JsonConvert.SerializeObject(
model,
Formatting.None,
new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() }); var additionalStylesheets = this.BuildTags(
"<link href='{0}' rel='stylesheet'>",
applicationPath,
this.config.Stylesheets);
var additionalScripts = this.BuildTags("<script src='{0}'></script>", applicationPath, this.config.Scripts); var variables = new
{
siteName = Encoder.HtmlEncode(model.SiteName),
applicationPath,
model = Encoder.HtmlEncode(json),
page,
stylesheets = additionalStylesheets,
scripts = additionalScripts,
clientName
}; html = Replace(html, variables); return Task.FromResult(this.StringToStream(html));
} /// <summary>
/// A helper method to repeat the generation of a formatted string for every value supplied
/// </summary>
/// <param name="tagFormat"></param>
/// <param name="basePath"></param>
/// <param name="values"></param>
/// <returns></returns>
private string BuildTags(
string tagFormat,
string basePath,
IEnumerable<string> values)
{
if (values == null)
{
return String.Empty;
} var enumerable = values as string[] ?? values.ToArray();
if (!enumerable.Any())
{
return String.Empty;
} var sb = new StringBuilder();
foreach (var value in enumerable)
{
var path = value;
if (path.StartsWith("~/"))
{
path = basePath + path.Substring();
} sb.AppendFormat(tagFormat, path);
sb.AppendLine();
} return sb.ToString();
} #endregion #region Modified from SampleApp.CustomViewService
// More helper methods to allow placeholders in the rendered Html /// <summary>
/// Replace placeholders in the string that correspond to the keys in the dictionary with the values of those keys.
/// </summary>
/// <param name="value"></param>
/// <param name="values"></param>
/// <returns></returns>
private static string Replace(string value, IDictionary<string, object> values)
{
foreach (var key in values.Keys)
{
var val = values[key];
val = val ?? String.Empty;
if (val != null)
{
value = value.Replace("{" + key + "}", val.ToString());
}
} return value;
} /// <summary>
/// Replace placeholders in the string that correspond to the names of properties in the object with the values of those properties.
/// </summary>
/// <param name="value"></param>
/// <param name="values"></param>
/// <returns></returns>
private string Replace(string value, object values)
{
return Replace(value, this.Map(values));
} /// <summary>
/// Convert an object into a Dictionary by enumerating and listing its properties
/// </summary>
/// <param name="values"></param>
/// <returns></returns>
private IDictionary<string, object> Map(object values)
{
var dictionary = values as IDictionary<string, object>; if (dictionary == null)
{
dictionary = new Dictionary<string, object>();
foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(values))
{
dictionary.Add(descriptor.Name, descriptor.GetValue(values));
}
} return dictionary;
} /// <summary>
/// Convert a stringto a Stream (containing the string)
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
private Stream StringToStream(string s)
{
var ms = new MemoryStream();
var sw = new StreamWriter(ms);
sw.Write(s);
sw.Flush();
ms.Seek(, SeekOrigin.Begin);
return ms;
} #endregion
}

接下来就是定义我们自己的Controller了

我们新建了一个LoginController登录控制器,这个控制器就是普通的控制器,主要是Action参数需要注意,这里的Action参数都是与Idr3相关

 public class LoginController : Controller
{
public LoginController()
{
} #region Login public ActionResult Login(LoginViewModel model, SignInMessage message)
{
return this.View(model);
} #endregion #region Logout public ActionResult Logout(LogoutViewModel model)
{ return this.View(model);
} #endregion #region LoggedOut public ActionResult LoggedOut(LoggedOutViewModel model)
{ return this.View(model);
} #endregion #region Consent public ActionResult Consent(ConsentViewModel model)
{
return this.View(model);
} #endregion #region Permissions public ActionResult Permissions(ClientPermissionsViewModel model)
{
return this.View(model);
} #endregion #region Error public virtual ActionResult Error(ErrorViewModel model)
{
return this.View(model);
} #endregion
}

LoginController

Idr3提供了相关的视图模型,针对每个步骤 LoginViewModel 、LogoutViewModel、LoggedOutViewModel、ConsentViewModel、ClientPermissionsViewModel、ErrorViewModel 进一步了解可以看下里面每个字段的作用

  factory.ViewService = new Registration<IViewService, IdrConfig.IdSvrMvcViewService<Controllers.LoginController>>();

这样自定义视图就搞定了,不光是登录,授权允许页 退出等等,只需要加入相对应的cshtml mvc 页面就ok了,了解每个模型知道里面字段作用对相关交互很重要

一步一步学习IdentityServer3 (6)的更多相关文章

  1. 一步一步学习IdentityServer3 (1)

    学习之初: IdentityServer3我自己最开始了解到的就是做一个SSO单点登录,后面发现还有单独的认证服务功能,其实它还可以做APIs的访问控制,资源授权,另外还可以为提供第三方登录,其他的自 ...

  2. 一步一步学习IdentityServer3 (2)

    下面就来做一个例子:IdentityServer3服务端的配置 VS2015创建一个MVC项目 IdrOAuth 用来授权的认证的站点

  3. 一步一步学习IdentityServer3 (4)

    其实上述例子 很多都很找到 但是在实际生态环境中给例子有很多不一样的地方 比如自定已登录界面怎么做? 怎么访问自己的用户数据库实现登录? 怎么在接口中使用,在接口中又怎么实现与Idr3结合授权? 等等 ...

  4. 12.Linux软件安装 (一步一步学习大数据系列之 Linux)

    1.如何上传安装包到服务器 有三种方式: 1.1使用图形化工具,如: filezilla 如何使用FileZilla上传和下载文件 1.2使用 sftp 工具: 在 windows下使用CRT 软件 ...

  5. (转) 一步一步学习ASP.NET 5 (四)- ASP.NET MVC 6四大特性

    转发:微软MVP 卢建晖 的文章,希望对大家有帮助.原文:http://blog.csdn.net/kinfey/article/details/44459625 编者语 : 昨晚写好的文章居然csd ...

  6. (转) 一步一步学习ASP.NET 5 (二)- 通过命令行和sublime创建项目

    转发:微软MVP 卢建晖 的文章,希望对大家有帮助. 注:昨天转发之后很多朋友指出了vNext的命名问题,原文作者已经做出了修改,后面的标题都适用 asp.net 5这个名称. 编者语 : 昨天发了第 ...

  7. 一步一步学习SignalR进行实时通信_1_简单介绍

    一步一步学习SignalR进行实时通信\_1_简单介绍 SignalR 一步一步学习SignalR进行实时通信_1_简单介绍 前言 SignalR介绍 支持的平台 相关说明 OWIN 结束语 参考文献 ...

  8. 一步一步学习SignalR进行实时通信_8_案例2

    原文:一步一步学习SignalR进行实时通信_8_案例2 一步一步学习SignalR进行实时通信\_8_案例2 SignalR 一步一步学习SignalR进行实时通信_8_案例2 前言 配置Hub 建 ...

  9. 一步一步学习SignalR进行实时通信_9_托管在非Web应用程序

    原文:一步一步学习SignalR进行实时通信_9_托管在非Web应用程序 一步一步学习SignalR进行实时通信\_9_托管在非Web应用程序 一步一步学习SignalR进行实时通信_9_托管在非We ...

  10. 一步一步学习SignalR进行实时通信_7_非代理

    原文:一步一步学习SignalR进行实时通信_7_非代理 一步一步学习SignalR进行实时通信\_7_非代理 SignalR 一步一步学习SignalR进行实时通信_7_非代理 前言 代理与非代理 ...

随机推荐

  1. Redis+Sentinel 实现redis集群高可用

    1.sentinel作用及实现原理: https://my.oschina.net/u/172871/blog/596976?p={{currentPage-1}}

  2. unicode utf8 学习记录

    显示器- unicode -系统- utf8 -存储设备 Unicode是一套复杂的字符编码标准,简单来说就是将人类使用的每个所谓字符与一个非负整数对应,并且保证不同的字符对应的整数一定不同.UTF- ...

  3. Matlab修改背景颜色

    步骤: 1, 在matlab命令行中运行prefdir, 获取matlab.prf文件所在路径 2, 打开matlab.prf所在路径, 找到matlab.prf文件, 作备份 3, 将以下内容添加到 ...

  4. Redis学习十:Redis的复制(Master/Slave)【重要】

    一.是什么 官网 行话:也就是我们所说的主从复制,主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主 二.能干嘛 读写分离  容灾恢 ...

  5. spring-boot Test for Controller

    spring-boot  controller 测试示例: 单元测试类 package com.zzhi; import com.fasterxml.jackson.databind.ObjectMa ...

  6. 新的玩具:Windows上的awesome

    平铺式窗口管理器 基于xwindow(Linux/Unix采用的图形系统)有成千上百种窗口管理器.其中有一类窗口管理器很古怪,所有应用程序的窗口没有互相遮挡,而是平铺到屏幕上,这类窗口管理器叫 平铺式 ...

  7. Bzoj1939 [Croatian2010] Zuma

    Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 43  Solved: 31 Description 有一行 N 个弹子,每一个都有一个颜色.每次可以让超过 ...

  8. 让老版本IE支持HTML5

    一直想入手C3和H5,但因为所开发的项目一直要求兼容IE7,IE8.而这两个浏览器并不支持html5,所以一直都在观望而未真正的投入太多精力去学习.尽管我知道h5和c3是主流. 在最近的项目开发中,偶 ...

  9. js延迟几秒执行

    var t=setTimeout("location.reload()",5000);

  10. Anaconda+django写出第一个web app(五)

    今天开始学习网页风格和设计,就像python有Web框架一样,也有一些CSS框架.对于CSS框架,我们可以使用默认的样式,也可以在原基础上编辑修改.本教程使用的是materialize这个CSS框架[ ...