Ostatni tydzień spędziłem na tworzeniu interfejsu API dla istniejącej aplikacji MVC, a teraz próbuję zabezpieczyć interfejs API wraz z ponownym opracowaniem zabezpieczeń bocznych MVC w razie potrzeby .Żądanie POV MVC traci nagłówek autoryzacji - sposób użycia znacznika właściciela API po odzyskaniu
Obecnie aplikacja MVC jest skonfigurowana do używania pliku cookie aplikacji za pośrednictwem OWIN/OAuth/Identity. Próbowałem włączyć token na okaziciela, który jest skonfigurowany w interfejsie API sieci Web do generowania połączeń z ograniczonymi metodami API, ale dotychczas nie przyniósł sporego sukcesu - żądania GET działają dobrze, ale żądania POST tracą nagłówek autoryzacji po odebraniu przez API.
Utworzyłem klienta SDK, który jest używany przez aplikację MVC do wykonywania wywołań interfejsu API i próbowałem w sumie trzech metod ustawiania nagłówka autoryzacji dla dowolnego wywołania interfejsu API, z których wszystkie wydaje się działać dobrze dla żądań gET, ale całkowicie nie do jakichkolwiek żądań POST muszę zrobić ...
mogę ustawić nagłówek żądania w kontroler MVC:
HttpContext.Request.Headers. Dodaj ("Authorization", "Bearer" + response.AccessToken);
(gdzie response.AccessToken jest znak wcześniej pobierane z API)
mogę ustawić nagłówek żądania poprzez metodę rozszerzenia na Client SDK:
_apiclient.SetBearerAuthentication (token.AccessToken)
czy mogę ręcznie ustawić nagłówek żądania od Klienta SDK:
_apiClient.Authentication = new AuthenticationHeaderValue ("Nośnik, accessToken);
(gdzie accessToken jest tokenem pobranym wcześniej, przekazanym do wywoływanej metody Client).
Mam bardzo niewiele do omówienia z tego punktu, co jest przyczyną problemu. Jedyne, co udało mi się zebrać do tej pory, to to, że ASP.NET powoduje, że wszystkie żądania POST muszą najpierw wysłać żądanie z nagłówkiem Expect dla odpowiedzi HTTP 100-Continue, po czym zakończy on faktyczne żądanie POST. Wydaje się jednak, że gdy robi to drugie żądanie, nagłówek Authorization nie jest już obecny, a więc atrybut Authorize API spowoduje 401-Nieautoryzowaną odpowiedź, zamiast faktycznie uruchomić metodę API.
Więc, jak wziąć token na okaziciela, który mogę pobrać z interfejsu API i użyć go na kolejnych żądaniach,, w tym różne żądania POST, które będę musiał wykonać?
Co jest najlepszym sposobem na przechowywanie tego tokena w aplikacji MVC? Wolałabym uniknąć omijania łańcucha z każdą metodą w aplikacji, która mogłaby go potrzebować, ale ja też czytałem, że przechowywanie jej w ciasteczku to bardzo zły pomysł ze względów bezpieczeństwa.
kilka dodatkowych punktów, które będą interesujące natychmiast po tym, jak przejdzie ten problem:
Czy przy użyciu protokołu OAuth okaziciela Żetony znaczy, że nie może już używać ApplicationCookies dla aplikacji MVC?I/lub uczyni poniższy kod bezużyteczny w całej aplikacji?
User.Identity.GetUserId()
Obecnie jestem zmuszony do komentowania mój API [Autoryzacja] atrybutów w celu kontynuowania mojej pracy, co oczywiście nie jest idealne, ale to nie pozwalają mi chwilowo zajmować się rzeczami.
pliki startowe:
MVC:
public class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
private void ConfigureAuth(IAppBuilder app)
{
app.CreatePerOwinContext(ADUIdentityDbContext.Create);
app.CreatePerOwinContext<ADUUserManager>(ADUUserManager.Create);
app.UseOAuthBearerTokens(new OAuthAuthorizationServerOptions
{
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
//This should be set to FALSE before we move to production.
AllowInsecureHttp = true,
ApplicationCanDisplayErrors = true,
TokenEndpointPath = new PathString("/api/token"),
});
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ExternalBearer,
CookieName = "ADU",
ExpireTimeSpan = TimeSpan.FromHours(2),
LoginPath = new PathString("/Account/Login"),
SlidingExpiration = true,
});
}
}
API
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
config.DependencyResolver = new NinjectResolver(new Ninject.Web.Common.Bootstrapper().Kernel);
WebApiConfig.Register(config);
ConfigureOAuth(app);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
public void ConfigureOAuth(IAppBuilder app)
{
app.CreatePerOwinContext(ADUIdentityDbContext.Create);
app.CreatePerOwinContext<ADUUserManager>(ADUUserManager.Create);
OAuthAuthorizationServerOptions oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/api/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider(),
};
//token generation
app.UseOAuthAuthorizationServer(oAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
}
public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider
{
private IUserBusinessLogic _userBusinessLogic;
/// <summary>
/// Creates the objects necessary to initialize the user business logic field and initializes it, as this cannot be done by dependency injection in this case.
/// </summary>
public void CreateBusinessLogic()
{
IUserRepository userRepo = new UserRepository();
IGeneratedExamRepository examRepo = new GeneratedExamRepository();
IGeneratedExamBusinessLogic examBLL = new GeneratedExamBusinessLogic(examRepo);
_userBusinessLogic = new UserBusinessLogic(userRepo, examBLL);
}
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) { context.Validated(); }
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
//create a claim for the user
ClaimsIdentity identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim("sub", user.Id));
context.Validated(identity);
}
}