웹 및 모바일용 ASP.NET 웹 API 소셜 인증
저의 질문은 좀 복잡하기 때문에 제가 어려움을 겪고 있는 것을 잘 표현하려고 노력하는 만큼 참아주세요.
골
ASP를 받습니다.사용자 이름/비밀번호 또는 소셜(Facebook, Twitter, Google 등)을 통해 사용자 등록 및 로그인이 가능한 NET 웹사이트.는 ΔAPI Δ Δ Δ Δ 로 잠금이 합니다.[Authorize]
는 사용자 이름 소셜등을할 수 있는 클라이언트가 접근할 수 API는 사용자 이름/비밀번호 또는 소셜(페이스북, 트위터, 구글 등)을 통해 로그인할 수 있는 모바일 클라이언트(안드로이드, iOS 등)가 접근할 수 있어야 합니다.
배경
그래서 저는 제 목표에서 한두 가지 일을 할 수는 있지만 다 같이 할 수는 없는 사이트를 해봤습니다.사용자가 소셜 앱을 통해 등록하고 로그인하는 방법을 보여주는 VS 프로젝트에는 온라인 및 예제에 포함된 좋은 예가 있지만 웹 사이트용일 뿐 모바일용은 아닙니다.Android 앱에서 사용자 이름/비밀번호를 사용하여 해당 API로 인증하는 웹 사이트를 실행했지만 OAuth 또는 Social 자격 증명은 실행하지 않았습니다.
저는 이 페이지를 참고 자료로 사용하기 시작했지만 웹 사이트 로그인 및 모바일 앱 로그인에 어떻게 활용해야 할지 모르겠습니다.
이 사람은 말을 쉽게 하지만 코드를 보여주지 않습니다.
질문.
목표에 도달할 수 있는 튜토리얼이나 GitHub 예제가 있습니까?저는 기본적으로 사람들이 사용자 이름/비밀번호를 등록하거나 소셜 계정을 사용할 수 있는 웹사이트를 원합니다. 그리고 사용자가 모바일 기기를 통해 같은 작업(등록 및 로그인)을 할 수 있는 웹사이트를 원합니다.모바일 기기는 기본적으로 API를 사용하여 데이터를 푸시/풀하지만, 소셜 로그인을 제 API에 어떻게 통합해야 할지 잘 모르겠습니다.OAuth를 사용하고 그 경로로 가야 한다고 생각하지만 웹과 모바일 모두에서 이를 수행하는 방법을 보여주는 좋은 예를 찾을 수 없습니다.
아니면 웹페이지를 쿠키 인증으로 만들고 API를 별도의 "웹 사이트"로 만들고 토큰 인증으로 둘 다 동일한 데이터베이스에 연결하는 것이 올바른 해결책일까요?
저는 제 ASP 안에서 바로 이 일을 성공적으로 해냈습니다.ASP를 이용한 NET MVC 적용NET Identity는 언급한 문제를 해결합니다.제 모바일 앱이 자연스럽게 상호 작용할 수 있도록 웹 API를 사용하여 작동하려면 이것이 필요합니다.
링크해주신 기사에 대해서는 생소했지만, 이를 통해 많은 작업과 코드가 필요하지 않고 ASP 내에 이미 존재하는 기능이 복잡하다는 것을 알게 되었습니다.NET 아이덴티티.
여기 제가 추천하는 사항이 있고, ASP를 사용하고 있다고 가정합니다.MVC5를 둘러싼 패키지와 동일한 NET Identity V2(새로운 MVC6 vNext가 아님).이렇게 하면 웹 사이트와 API를 통한 모바일 애플리케이션 모두가 웹 사이트의 MVC 웹 보기 및 모바일 애플리케이션의 웹 API 호출을 통해 로컬 로그인(사용자 이름/비밀번호) 및 외부 OAuth 공급자로 인증할 수 있습니다.
1단계. 프로젝트를 작성할 때 MVC와 Web API에 필요한 패키지가 모두 포함되어 있는지 확인합니다.ASP에서.NET Project Selection(넷 프로젝트 선택) 대화상자에서 MVC와 Web API가 모두 선택되어 있는지 확인하는 확인란을 선택할 수 있습니다.프로젝트를 만들 때 아직 이 작업을 수행하지 않았다면 새 프로젝트를 만들고 기존 코드를 마이그레이션하는 것과 종속성 및 템플릿 코드를 검색하고 수동으로 추가하는 것을 권장합니다.
2단계. 스타트업 내부.Auth.cs 파일에서 OWIN에게 쿠키 인증을 사용하고 쿠키에서 외부 서명을 허용하며 OAuth 베어러 토큰을 지원하도록 알려주는 코드가 필요합니다(이것이 웹 API 호출의 인증 방법입니다).제 작업 프로젝트 코드베이스에서 발췌한 내용입니다.
스타트업.Auth.cs
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/account/login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/token"),
Provider = new ApplicationOAuthProvider(PublicClientId),
AuthorizeEndpointPath = new PathString("/api/account/externallogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
//AllowInsecureHttp = false
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
app.UseTwitterAuthentication(
consumerKey: "Twitter API Key",
consumerSecret: "Twitter API Secret");
app.UseFacebookAuthentication(
appId: "Facebook AppId",
appSecret: "Facebook AppSecret");
위 코드에서 저는 현재 트위터와 페이스북을 외부 인증 제공자로 지원합니다. 그러나 앱으로 외부 제공자를 추가할 수 있습니다.사용자 XYZProvider 호출 및 추가 라이브러리를 통해 내가 여기에 제공하는 코드를 플러그 앤 플레이 할 것입니다.
3단계. WebApiConfig.cs 파일 내에서 기본 호스트 인증을 금지하고 OAuth 베어러 토큰을 지원하도록 HttpConfiguration을 구성해야 합니다.예를 들어, 이것은 MVC와 웹 API 사이의 인증 유형을 구별하도록 응용 프로그램에 알려줍니다. 이렇게 하면 웹 사이트에 대한 일반적인 쿠키 흐름을 사용할 수 있습니다. 한편, 응용 프로그램은 웹 API로부터 OAuth 형태의 베어러 토큰을 불평이나 다른 문제 없이 받습니다.
WebApiConfig.cs
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
4단계. MVC와 Web API 모두를 위해 AccountController(또는 동등한 용도의 컨트롤러)가 필요합니다.제 프로젝트에는 두 개의 AccountController 파일, 한 개의 MVC Controller가 기본 Controller 클래스에서 상속되고 다른 하나의 AccountController가 Controller에 있는 ApiController에서 상속됩니다.API 네임스페이스로 사물을 깨끗하게 유지할 수 있습니다.웹 API 및 MVC 프로젝트의 표준 템플릿 AccountController 코드를 사용하고 있습니다.Account Controller의 API 버전은 다음과 같습니다.
AccountController.cs (컨트롤러.API 네임스페이스)
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Web.Http.ModelBinding;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OAuth;
using Disco.Models.API;
using Disco.Providers;
using Disco.Results;
using Schloss.AspNet.Identity.Neo4j;
using Disco.Results.API;
namespace Disco.Controllers.API
{
[Authorize]
[RoutePrefix("api/account")]
public class AccountController : ApiController
{
private const string LocalLoginProvider = "Local";
private ApplicationUserManager _userManager;
public AccountController()
{
}
public AccountController(ApplicationUserManager userManager,
ISecureDataFormat<AuthenticationTicket> accessTokenFormat)
{
UserManager = userManager;
AccessTokenFormat = accessTokenFormat;
}
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
public ISecureDataFormat<AuthenticationTicket> AccessTokenFormat { get; private set; }
// GET account/UserInfo
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("userinfo")]
public UserInfoViewModel GetUserInfo()
{
ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
return new UserInfoViewModel
{
Email = User.Identity.GetUserName(),
HasRegistered = externalLogin == null,
LoginProvider = externalLogin != null ? externalLogin.LoginProvider : null
};
}
// POST account/Logout
[Route("logout")]
public IHttpActionResult Logout()
{
Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
return Ok();
}
// GET account/ManageInfo?returnUrl=%2F&generateState=true
[Route("manageinfo")]
public async Task<ManageInfoViewModel> GetManageInfo(string returnUrl, bool generateState = false)
{
IdentityUser user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
if (user == null)
{
return null;
}
List<UserLoginInfoViewModel> logins = new List<UserLoginInfoViewModel>();
foreach (UserLoginInfo linkedAccount in await UserManager.GetLoginsAsync(User.Identity.GetUserId()))
{
logins.Add(new UserLoginInfoViewModel
{
LoginProvider = linkedAccount.LoginProvider,
ProviderKey = linkedAccount.ProviderKey
});
}
if (user.PasswordHash != null)
{
logins.Add(new UserLoginInfoViewModel
{
LoginProvider = LocalLoginProvider,
ProviderKey = user.UserName,
});
}
return new ManageInfoViewModel
{
LocalLoginProvider = LocalLoginProvider,
Email = user.UserName,
Logins = logins,
ExternalLoginProviders = GetExternalLogins(returnUrl, generateState)
};
}
// POST account/ChangePassword
[Route("changepassword")]
public async Task<IHttpActionResult> ChangePassword(ChangePasswordBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword,
model.NewPassword);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
// POST account/SetPassword
[Route("setpassword")]
public async Task<IHttpActionResult> SetPassword(SetPasswordBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result = await UserManager.AddPasswordAsync(User.Identity.GetUserId(), model.NewPassword);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
// POST account/AddExternalLogin
[Route("addexternallogin")]
public async Task<IHttpActionResult> AddExternalLogin(AddExternalLoginBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
AuthenticationTicket ticket = AccessTokenFormat.Unprotect(model.ExternalAccessToken);
if (ticket == null || ticket.Identity == null || (ticket.Properties != null
&& ticket.Properties.ExpiresUtc.HasValue
&& ticket.Properties.ExpiresUtc.Value < DateTimeOffset.UtcNow))
{
return BadRequest("External login failure.");
}
ExternalLoginData externalData = ExternalLoginData.FromIdentity(ticket.Identity);
if (externalData == null)
{
return BadRequest("The external login is already associated with an account.");
}
IdentityResult result = await UserManager.AddLoginAsync(User.Identity.GetUserId(),
new UserLoginInfo(externalData.LoginProvider, externalData.ProviderKey));
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
// POST account/RemoveLogin
[Route("removelogin")]
public async Task<IHttpActionResult> RemoveLogin(RemoveLoginBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result;
if (model.LoginProvider == LocalLoginProvider)
{
result = await UserManager.RemovePasswordAsync(User.Identity.GetUserId());
}
else
{
result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(),
new UserLoginInfo(model.LoginProvider, model.ProviderKey));
}
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
// GET account/ExternalLogin
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalCookie)]
[AllowAnonymous]
[Route("externallogin", Name = "ExternalLoginAPI")]
public async Task<IHttpActionResult> GetExternalLogin(string provider, string error = null)
{
if (error != null)
{
return Redirect(Url.Content("~/") + "#error=" + Uri.EscapeDataString(error));
}
if (!User.Identity.IsAuthenticated)
{
return new ChallengeResult(provider, this);
}
ExternalLoginData externalLogin = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
if (externalLogin == null)
{
return InternalServerError();
}
if (externalLogin.LoginProvider != provider)
{
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
return new ChallengeResult(provider, this);
}
ApplicationUser user = await UserManager.FindAsync(new UserLoginInfo(externalLogin.LoginProvider,
externalLogin.ProviderKey));
bool hasRegistered = user != null;
if (hasRegistered)
{
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(UserManager,
OAuthDefaults.AuthenticationType);
ClaimsIdentity cookieIdentity = await user.GenerateUserIdentityAsync(UserManager,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = ApplicationOAuthProvider.CreateProperties(user.UserName);
Authentication.SignIn(properties, oAuthIdentity, cookieIdentity);
}
else
{
IEnumerable<Claim> claims = externalLogin.GetClaims();
ClaimsIdentity identity = new ClaimsIdentity(claims, OAuthDefaults.AuthenticationType);
Authentication.SignIn(identity);
}
return Ok();
}
// GET account/ExternalLogins?returnUrl=%2F&generateState=true
[AllowAnonymous]
[Route("externallogins")]
public IEnumerable<ExternalLoginViewModel> GetExternalLogins(string returnUrl, bool generateState = false)
{
IEnumerable<AuthenticationDescription> descriptions = Authentication.GetExternalAuthenticationTypes();
List<ExternalLoginViewModel> logins = new List<ExternalLoginViewModel>();
string state;
if (generateState)
{
const int strengthInBits = 256;
state = RandomOAuthStateGenerator.Generate(strengthInBits);
}
else
{
state = null;
}
foreach (AuthenticationDescription description in descriptions)
{
ExternalLoginViewModel login = new ExternalLoginViewModel
{
Name = description.Caption,
Url = Url.Route("ExternalLogin", new
{
provider = description.AuthenticationType,
response_type = "token",
client_id = Startup.PublicClientId,
redirect_uri = new Uri(Request.RequestUri, returnUrl).AbsoluteUri,
state = state
}),
State = state
};
logins.Add(login);
}
return logins;
}
// POST account/Register
[AllowAnonymous]
[Route("register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
// POST account/RegisterExternal
[OverrideAuthentication]
[HostAuthentication(DefaultAuthenticationTypes.ExternalBearer)]
[Route("registerexternal")]
public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var info = await Authentication.GetExternalLoginInfoAsync();
if (info == null)
{
return InternalServerError();
}
var user = new ApplicationUser() { UserName = model.Email, Email = model.Email };
IdentityResult result = await UserManager.CreateAsync(user);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
result = await UserManager.AddLoginAsync(user.Id, info.Login);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
protected override void Dispose(bool disposing)
{
if (disposing && _userManager != null)
{
_userManager.Dispose();
_userManager = null;
}
base.Dispose(disposing);
}
#region Helpers
private IAuthenticationManager Authentication
{
get { return Request.GetOwinContext().Authentication; }
}
private IHttpActionResult GetErrorResult(IdentityResult result)
{
if (result == null)
{
return InternalServerError();
}
if (!result.Succeeded)
{
if (result.Errors != null)
{
foreach (string error in result.Errors)
{
ModelState.AddModelError("", error);
}
}
if (ModelState.IsValid)
{
// No ModelState errors are available to send, so just return an empty BadRequest.
return BadRequest();
}
return BadRequest(ModelState);
}
return null;
}
private class ExternalLoginData
{
public string LoginProvider { get; set; }
public string ProviderKey { get; set; }
public string UserName { get; set; }
public IList<Claim> GetClaims()
{
IList<Claim> claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.NameIdentifier, ProviderKey, null, LoginProvider));
if (UserName != null)
{
claims.Add(new Claim(ClaimTypes.Name, UserName, null, LoginProvider));
}
return claims;
}
public static ExternalLoginData FromIdentity(ClaimsIdentity identity)
{
if (identity == null)
{
return null;
}
Claim providerKeyClaim = identity.FindFirst(ClaimTypes.NameIdentifier);
if (providerKeyClaim == null || String.IsNullOrEmpty(providerKeyClaim.Issuer)
|| String.IsNullOrEmpty(providerKeyClaim.Value))
{
return null;
}
if (providerKeyClaim.Issuer == ClaimsIdentity.DefaultIssuer)
{
return null;
}
return new ExternalLoginData
{
LoginProvider = providerKeyClaim.Issuer,
ProviderKey = providerKeyClaim.Value,
UserName = identity.FindFirstValue(ClaimTypes.Name)
};
}
}
private static class RandomOAuthStateGenerator
{
private static RandomNumberGenerator _random = new RNGCryptoServiceProvider();
public static string Generate(int strengthInBits)
{
const int bitsPerByte = 8;
if (strengthInBits % bitsPerByte != 0)
{
throw new ArgumentException("strengthInBits must be evenly divisible by 8.", "strengthInBits");
}
int strengthInBytes = strengthInBits / bitsPerByte;
byte[] data = new byte[strengthInBytes];
_random.GetBytes(data);
return HttpServerUtility.UrlTokenEncode(data);
}
}
#endregion
}
}
5단계. 응용프로그램을 생성해야 합니다.서버가 OAuth 토큰을 생성하고 유효성을 검사할 수 있도록 OAuthProvider.이는 WebAPI 샘플 프로젝트에서 제공됩니다.이것이 제 파일 버전입니다.
어플OAuthProvider.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OAuth;
using Butler.Models;
using Schloss.AspNet.Identity.Neo4j;
namespace Butler.Providers
{
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
private readonly string _publicClientId;
public ApplicationOAuthProvider(string publicClientId)
{
if (publicClientId == null)
{
throw new ArgumentNullException("publicClientId");
}
_publicClientId = publicClientId;
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
OAuthDefaults.AuthenticationType);
ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = CreateProperties(user.UserName);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
{
context.AdditionalResponseParameters.Add(property.Key, property.Value);
}
return Task.FromResult<object>(null);
}
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
// Resource owner password credentials does not provide a client ID.
if (context.ClientId == null)
{
context.Validated();
}
return Task.FromResult<object>(null);
}
public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
{
if (context.ClientId == _publicClientId)
{
//Uri expectedRootUri = new Uri(context.Request.Uri, "/");
//if (expectedRootUri.AbsoluteUri == context.RedirectUri)
//{
context.Validated();
//}
}
return Task.FromResult<object>(null);
}
public static AuthenticationProperties CreateProperties(string userName)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
{ "userName", userName }
};
return new AuthenticationProperties(data);
}
}
}
또한 ChallengeResult도 포함되어 있습니다. 이 결과는 응용프로그램의 Web API 암이 사용자를 인증하기 위해 외부 로그인 공급자가 제공하는 문제를 처리하는 데 사용됩니다.
ChallengeResult.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http;
namespace Butler.Results
{
public class ChallengeResult : IHttpActionResult
{
public ChallengeResult(string loginProvider, ApiController controller)
{
LoginProvider = loginProvider;
Request = controller.Request;
}
public string LoginProvider { get; set; }
public HttpRequestMessage Request { get; set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
Request.GetOwinContext().Authentication.Challenge(LoginProvider);
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
response.RequestMessage = Request;
return Task.FromResult(response);
}
}
}
이 코드 세트를 사용하면 계정 컨트롤러의 API 버전에 경로를 HTTP GET 및 HTTP POST하여 사용자를 등록하고, 사용자 이름과 비밀번호를 사용하여 로그인하여 베어러 토큰을 수신하고, 외부 로그인을 추가/제거하고, 외부 로그인을 관리할 수 있으며, 가장 중요한 문제는사용자 응용프로그램에 대한 OAuth 베어러 토큰의 교환으로 외부 로그인 토큰을 전달하여 인증합니다.
다음과 같은 일련의 기사를 통해 목표를 달성했는지 여부를 확인할 수 있습니다.
ASP를 사용한 토큰 기반 인증.NET 웹 API 2, Owin 및 Identity Taiseer Joudeh (SO에 대한 질문에도 자주 답함)
기사내용은 OWIN을 이용한 토큰 기반 인증 서비스 작성 및 외부 로그인(Facebook, Google+ 등)을 이용한 부품커버 작성에 관한 것입니다.예는 주로 웹 서비스의 소비자로서 웹 애플리케이션을 중심으로 하지만 모바일 애플리케이션에서도 작동해야 합니다.기사에는 GitHub 프로젝트가 연관되어 있고 매우 활발한 댓글 섹션이 있는데, 어떤 질문도 답을 찾지 못합니다.
이것이 당신의 목표로 이끌 수 있기를 바랍니다.
질문의 두 번째 부분에 대한 별도의 답변으로 이 내용을 추가합니다. 예, 두 개의 프로젝트를 동일한 데이터베이스에 연결하고 MVC/Web Forms 웹 사이트 프로젝트에서 모든 쿠키 인증을 사용한 다음 토큰 인증인 별도의 Web API 프로젝트를 사용할 수 있습니다.
소스 코드 예제를 사용하여 제가 기본적으로 수행한 것은 두 개의 개별 프로젝트를 하나의 프로젝트로 결합하여 중복 모델 코드와 컨트롤러 코드를 방지하는 것입니다.제 경우에는 이것이 더 합리적이었지만, 웹사이트와 웹 API 엔드포인트 두 개의 개별 프로젝트를 유지할 것인지, 아니면 그것들을 결합할 것인지는 개인의 선호와 프로젝트의 요구에 달려 있다고 말하고 싶습니다.
ASP.NET은 미들웨어로서 매우 유연하고 플러그 앤 플레이가 가능하도록 설계되었으며, 저는 제 프로젝트가 두 개의 개별 프로젝트에서 코드 의도대로 정확히 존재하고 기능했으며, 이제는 하나의 결합 프로젝트로 기능했음을 증명할 수 있습니다.
언급URL : https://stackoverflow.com/questions/30444137/asp-net-web-api-social-authentication-for-web-and-mobile
'programing' 카테고리의 다른 글
SQL: Oracle - 쿼리 중인 매개 변수 (0) | 2023.09.14 |
---|---|
MySQL에서 보기를 만들려면 어떻게 해야 합니까? (0) | 2023.09.14 |
.ready() 중에 문서 제목을 변경하려면 어떻게 해야 합니까? (0) | 2023.09.14 |
Wordpress/PHP/Ajax 게시물 추가 로드 (0) | 2023.09.14 |
코드를 통해 요소 또는 팝업을 트리거하는 방법 (0) | 2023.09.14 |