2016-09-13 52 views
8

ScrenarioGdzie przechowywać okaziciela token w MVC z Web API

Mam ASP.NET Web API, który korzysta z OAuth Hasło przepływu w celu okaziciela tokeny aby uzyskać dostęp do jego zasobów.

Jestem teraz w trakcie tworzenia aplikacji MVC, która będzie musiała korzystać z tego interfejsu API.

Planuje się, że kontrolery MVC będą nawiązywać połączenia z interfejsem API w imieniu przeglądarki klienta.

Żądania ajax z przeglądarki trafią kontrolery MVC, a następnie wywołania interfejsu API. Wyniki są następnie przekazywane do klienta jako JSON i obsługiwane w skryptach Java.

Klient nigdy nie powinien komunikować się bezpośrednio z interfejsem API.

Uzyskanie uwierzytelnienia.

Muszę w porządku najlepiej obsłużyć token na okaziciela po jego otrzymaniu w aplikacji MVC poprzez udane połączenie z punktem końcowym tokenu aplikacji webowej.

Potrzebuję użyć tego znacznika okaziciela w kolejnych połączeniach do interfejsu API.

Mój plan jest przechowywanie go w System.Web.HttpContext.Current.Session["BearerToken"]

mogę następnie utworzyć niestandardowy AuthorizationAttribute że sprawdzi, czy BearerToken jest obecny w bieżącym HttpContext, jeśli jej nie ma, klient będzie musiał ponownie token to enpoint.

Czy wydaje się to wykonalne?

Proszę opinii ludzi o tym, ponieważ nie jestem przekonany, że to najlepsze rozwiązanie dla mojego projektu.

+0

okaziciela tokenu byłoby pójść w nagłówkach żądań. Wierzę, że uzyskujesz dostęp do Web API za pośrednictwem wywołania AJAX. Musisz więc odpowiednio utworzyć żądanie AJAX za pomocą tokena otrzymanego z Web API. Zrobiłem podobną rzecz tutaj, ale bez AJAX- http://stackoverflow.com/questions/38661090/token-based-authentication-in-web-api-w-out-any-user-interface/38670221#38670221 –

+0

Tworzę wywołanie api wep za pomocą obiektu HttpClient w aplikacji MVC – Derek

Odpowiedz

7

Udało mi się wymyślić coś, co moim zdaniem będzie działać całkiem dobrze.

Używam oprogramowania Owin Middleware do uwierzytelniania plików cookie.

W MVC Aplikacja Mam plik Owin startowego gdzie jest skonfigurowane uwierzytelnianie Cookie: -

public class Startup 
    { 
     public void Configuration(IAppBuilder app) 
     { 
      // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888 

      app.UseCookieAuthentication(new CookieAuthenticationOptions() 
      { 
       AuthenticationType = "ApplicationCookie", 
       LoginPath = new PathString("/Account/Login"), 

      }); 
     } 
    } 

Następnie wykonany AccountController z dwóch metod działania do logowania i wylogowania: -

Logowanie.

public ActionResult Login(LoginModel model,string returnUrl) 
     { 
      var getTokenUrl = string.Format(ApiEndPoints.AuthorisationTokenEndpoint.Post.Token, ConfigurationManager.AppSettings["ApiBaseUri"]); 

      using (HttpClient httpClient = new HttpClient()) 
      { 
       HttpContent content = new FormUrlEncodedContent(new[] 
       { 
        new KeyValuePair<string, string>("grant_type", "password"), 
        new KeyValuePair<string, string>("username", model.EmailAddress), 
        new KeyValuePair<string, string>("password", model.Password) 
       }); 

       HttpResponseMessage result = httpClient.PostAsync(getTokenUrl, content).Result; 

       string resultContent = result.Content.ReadAsStringAsync().Result; 

       var token = JsonConvert.DeserializeObject<Token>(resultContent); 

       AuthenticationProperties options = new AuthenticationProperties(); 

       options.AllowRefresh = true; 
       options.IsPersistent = true; 
       options.ExpiresUtc = DateTime.UtcNow.AddSeconds(int.Parse(token.expires_in)); 

       var claims = new[] 
       { 
        new Claim(ClaimTypes.Name, model.EmailAddress), 
        new Claim("AcessToken", string.Format("Bearer {0}", token.access_token)), 
       }; 

       var identity = new ClaimsIdentity(claims, "ApplicationCookie"); 

       Request.GetOwinContext().Authentication.SignIn(options, identity); 

      } 

      return RedirectToAction("Index", "Home"); 
     } 

wylogowywanie

public ActionResult LogOut() 
      { 
       Request.GetOwinContext().Authentication.SignOut("ApplicationCookie"); 

       return RedirectToAction("Login"); 
      } 

ochronę zasobów

[Authorize] 
    public class HomeController : Controller 
    { 

     private readonly IUserSession _userSession; 

     public HomeController(IUserSession userSession) 
     { 
      _userSession = userSession; 
     } 

     // GET: Home 
     public ActionResult Index() 
     { 

      ViewBag.EmailAddress = _userSession.Username; 
      ViewBag.AccessToken = _userSession.BearerToken; 

      return View(); 
     } 
    } 


public interface IUserSession 
    { 
     string Username { get; } 
     string BearerToken { get; } 
    } 

public class UserSession : IUserSession 
    { 

     public string Username 
     { 
      get { return ((ClaimsPrincipal)HttpContext.Current.User).FindFirst(ClaimTypes.Name).Value; } 
     } 

     public string BearerToken 
     { 
      get { return ((ClaimsPrincipal)HttpContext.Current.User).FindFirst("AcessToken").Value; } 
     } 

    } 
+1

Wielkie dzięki za to – Magrangs

+0

Otrzymuję obiekt userSession jako NULL na moim kontrolerze HomeController/Index – Velkumar

+0

userSession będzie null, jeśli nie używasz wtrysku zależności w aplikacji. – Derek

1

Od tego czasu wspomniałeś, że używasz HttpClient(). Zrobiłem coś podobnego, używając HttpClient() -

Get token-

static Dictionary<string, string> GetTokenDetails(string userName, string password) 
    { 
     Dictionary<string, string> tokenDetails = null; 
     try 
     { 
      using (var client = new HttpClient()) 
      { 
       var login = new Dictionary<string, string> 
        { 
         {"grant_type", "password"}, 
         {"username", userName}, 
         {"password", password}, 
        }; 

       var resp = client.PostAsync("http://localhost:61086/token", new FormUrlEncodedContent(login)); 
       resp.Wait(TimeSpan.FromSeconds(10)); 

       if (resp.IsCompleted) 
       { 
        if (resp.Result.Content.ReadAsStringAsync().Result.Contains("access_token")) 
        { 
         tokenDetails = JsonConvert.DeserializeObject<Dictionary<string, string>>(resp.Result.Content.ReadAsStringAsync().Result); 
        } 
       } 
      } 
     } 
     catch (Exception ex) 
     { 

     } 
     return tokenDetails; 
    } 

użycia znacznika do wysłania danych

static string PostData(string token, List<KeyValuePair<string, string>> lsPostContent) 
{ 
    string response = String.Empty; 
    try 
    { 
     using (var client = new HttpClient()) 
     { 
      FormUrlEncodedContent cont = new FormUrlEncodedContent(lsPostContent); 
      client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token); 
      var resp = client.PostAsync("https://localhost:61086/api/<your API controller>/", cont); 

      resp.Wait(TimeSpan.FromSeconds(10)); 

      if (resp.IsCompleted) 
      { 
       if (resp.Result.StatusCode == HttpStatusCode.Unauthorized) 
       { 
        Console.WriteLine("Authorization failed. Token expired or invalid."); 
       } 
       else 
       { 
        response = resp.Result.Content.ReadAsStringAsync().Result; 
        Console.WriteLine(response); 
       } 
      } 
     } 
    } 
    catch (Exception ex) 
    { 

    } 
    return response; 
} 

Nawet jeśli przechowywać token okaziciela HttpContext , musisz zadbać o czas wygaśnięcia tokena, który jest ustawiony w Web API. Sprawdzanie istnienia tokenu w trakcie sesji nie pomoże, ponieważ stary token będzie nieważny po upływie czasu wygaśnięcia.