Cross-origin Web Api Logon
Recently, the project tried to use web APIs for the first time and copied the common mvc Forms login method. When it was connected to the front-end, a problem occurred:
The front-end uses ajax to call the logon interface to complete the logon, and then calls another interface, which is determined to be not logged on.
If you directly access the logon interface and other interfaces in the browser, you can identify it as logged on.
I don't know much about asp.net's mechanisms, so I guess that cross-origin causes inconsistent http context of two calls, at that time, we solved the cross-origin problem by configuring the system in the server. add the following content to a webServer node:
<HttpProtocol>
<CustomHeaders>
<Add name = "Access-Control-Allow-Origin" value = "*"/>
<Add name = "Access-Control-Allow-Headers" value = "Content-Type"/>
<Add name = "Access-Control-Allow-Methods" value = "GET, POST, PUT, DELETE, OPTIONS"/>
</CustomHeaders>
</HttpProtocol>
I thought this solution was not perfect, so I began to search for and try various cross-domain solutions online. The most serious attempt was to put my. upgrade the web api of net4.0. net4.5 web api2 to use Microsoft ASP. NET Web API 2 Cross-Origin Suppor supports Cross-Origin. The results show that this method is only fine-grained, and there is no essential difference from the simple and crude method we first used, other methods are similar.
Now I want to define a simple logon. The specific implementation is:
1. create a ticket upon logon, and save a set of key-value pairs of the ticket and user information on the server. The ticket is returned to the client, which must be included when the client accesses the interface to be logged on.
2. add a custom AuthorizeAttribute to the interface for login verification. In this attribute, obtain the ticket passed by the client to verify whether the ticket exists or expires. If the ticket is valid, add the corresponding user information to the http context. If the ticket is invalid, a message indicating that the user has not logged on is returned.
Due to my limited skill, and because the project involves Fund operations such as recharge and withdrawal, I have decided to use SSL. Therefore, questions about tampering, reuse, and other transmission security issues are not taken into account.
The following code is used:
User Information Model (this information will be returned to the client upon logon ):
Public class MemberTicket
{
Public string ID {get; set ;}
Public string LoginName {get; set ;}
Public string Token {get; set ;}
Public DateTime LoginDate {get; set ;}
}
Logon processing class:
/// <Summary>
/// Custom logon
/// </Summary>
Public class LoginHelper
{
/// <Summary>
/// User information set
/// </Summary>
Private static Dictionary <string, MemberTicket> Members = new Dictionary <string, MemberTicket> ();
/// <Summary>
/// Log on
/// </Summary>
/// <Param name = "ticket"> User Information </param>
Public static void Login (MemberTicket ticket)
{
If (Members. Keys. Contains (ticket. Token ))
Members [ticket. Token] = ticket;
Else
Members. Add (ticket. Token, ticket );
}
/// <Summary>
/// Log out
/// </Summary>
/// <Param name = "Token"> ticket </param>
Public static void SignOut (string Token)
{
If (Members. Keys. Contains (Token ))
Members. Remove (Token );
}
/// <Summary>
/// Check whether the ticket is valid Based on the ticket
/// </Summary>
/// <Param name = "Token"> ticket </param>
/// <Returns> </returns>
Public static MemberTicket Check (string Token)
{
If (! String. IsNullOrEmpty (Token) & Members. Keys. Contains (Token ))
{
MemberTicket ticket = Members [Token];
If (ticket! = Null & ticket. LoginDate. AddMinutes (CommonData. TimeOut)> CommonData. TimeNow ())
Return ticket;
}
Return null;
}
}
Define user objects (structures that can be stored in http context ):
Public class MemberPrincipal: IPrincipal
{
Private string loginname;
Public string Loginname
{
Get {return loginname ;}
Set {loginname = value ;}
}
Private IIdentity _ Identity;
Public IIdentity Identity
{
Get {return _ Identity ;}
Set {_ Identity = value ;}
}
Public bool IsInRole (string role)
{
Return false;
}
Public MemberPrincipal (string Name)
{
Loginname = Name;
_ Identity = new GenericIdentity (loginname, "Forums ");
Bool isok = _ Identity. IsAuthenticated;
}
}
Save User information to http context:
Public class PrincipalHelper
{
Public static void SetPrincipal (IPrincipal principal)
{
Thread. CurrentPrincipal = principal;
If (HttpContext. Current! = Null)
{
HttpContext. Current. User = principal;
}
}
}
Key part: custom logon policy:
Public class LoginAuthorize: AuthorizeAttribute
{
Public override void OnAuthorization (HttpActionContext httpContext)
{
MemberTicket ticket = LoginHelper. Check (GetToken (httpContext. Request. RequestUri. Query ));
If (ticket = null)
{
HttpResponseMessage response = new HttpResponseMessage (HttpStatusCode. OK );
ResponseMessage <string> result = new ResponseMessage <string> ();
Result. Header = new ResponseHeader ();
Result. Header. State = (int) ResponseHeaderState. SignOut;
Result. Header. Message = "the user has not logged on ";
Response. Content = new StringContent (JsonConvert. SerializeObject (result ));
HttpContext. Response = response;
}
Else
PrincipalHelper. SetPrincipal (new MemberPrincipal (ticket. LoginName ));
}
Public string GetToken (string Query)
{
If (! Query. Contains ("Token "))
Return null;
String [] Param = Query. Split ('&');
If (Param. Length = 0)
Return null;
Foreach (var item in Param)
{
If (! Item. Contains ("Token "))
Continue;
String [] value = item. Split ('= ');
If (value. Length = 0)
Return null;
Return value [1];
}
Return null;
}
}
Returned message structure:
Public class ResponseMessage <T>
{
/// <Summary>
/// Message Header
/// </Summary>
Public ResponseHeader Header {get; set ;}
/// <Summary>
/// Message Body
/// </Summary>
Public T Body {get; set ;}
}
Public class ResponseHeader
{
/// <Summary>
/// Execution status
/// </Summary>
Public int State {get; set ;}
/// <Summary>
/// Message
/// </Summary>
Public string Message {get; set ;}
}
Add this property to the Controller or method that requires logon verification.
After that, I have achieved my expectation, but my expectation is too low, so I feel very low ...... I hope you can kindly advise me in what direction should I optimize the login mechanism?