Skip to content

Instantly share code, notes, and snippets.

@gromanev
Last active June 22, 2017 12:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gromanev/4da63142825798927375a3da342e65b8 to your computer and use it in GitHub Desktop.
Save gromanev/4da63142825798927375a3da342e65b8 to your computer and use it in GitHub Desktop.
IdentityServer4
public class AuthConstants
{
public const string ApiSecret = "asdf753asdf";
public const string ApiV1Scope = "api1";
public static string AuthServerLocation
{
get
{
#if DEBUG
return "http://localhost:5000";
#endif
#if RELEASE
return "http://production.mydomain.com";
#endif
}
}
}
public static class IdentityServerConfiguration
{
/// <summary>
/// Возвращает список API - ресурсов, доступ к которым предоставляет IdentityServer4.
/// </summary>
/// <param name="apiSecret">API-Secret.</param>
/// <returns></returns>
public static IEnumerable<ApiResource> GetApiResources(string apiSecret)
{
if (string.IsNullOrEmpty(apiSecret))
throw new ArgumentNullException(nameof(apiSecret));
var result = new[]
{
new ApiResource(AuthConstants.ApiV1Scope, "Lynx MRP System API")
{
ApiSecrets = {new Secret(apiSecret.Sha256())},
UserClaims = new List<string>
{
"role",
"email",
"name"
}
}
};
return result;
}
/// <summary>
/// Возвращает список API-клиентов, которым предоставляет доступ IdentityServer4.
/// </summary>
/// <param name="frontEndLocations">Все расположения Front-end для корректной работы CORS.</param>
/// <returns></returns>
public static IEnumerable<Client> GetClients()
{
return new[]
{
new Client
{
ClientId = "client",
ClientSecrets ={new Secret(AuthConstants.ApiSecret.Sha256())},
AllowedScopes = {GetApiResources(AuthConstants.ApiSecret).First().Name},
RequireClientSecret = false,
AllowedGrantTypes = GrantTypes.ResourceOwnerPassword,
AllowOfflineAccess = true,
AllowAccessTokensViaBrowser = true,
UpdateAccessTokenClaimsOnRefresh = true,
//AllowedCorsOrigins = frontEndLocations,
RefreshTokenUsage = TokenUsage.OneTimeOnly,
AccessTokenType = AccessTokenType.Jwt,
AccessTokenLifetime = 10, // время жизни токена в секндах
AbsoluteRefreshTokenLifetime = 2592000
}
};
}
/// <summary>
/// Возвращает сертификат для подписи токенов.
/// </summary>
/// <exception cref="ConfigurationException">Выбрасывается при отсутствии настройки, либо при некорректной настройке.</exception>
/// <returns>Всегда возвращает экземпляр <see cref="X509Certificate2"/>.</returns>
public static X509Certificate2 GetSigningCertificate()
{
var location = "myCert.pfx";
var password = "asdf753asdf123";
//var tmp = env.ContentRootPath;
if (!string.IsNullOrEmpty(location) && !string.IsNullOrEmpty(password))
{
var certFileInfo = new FileInfo(location);
if (certFileInfo.Exists)
{
var cert = new X509Certificate2(
certFileInfo.FullName,
password,
X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet);
return cert;
}
}
throw new Exception("MISSING OR WRONG SIGNING CERTIFICATE CONFIGURATION!!!");
}
public static IEnumerable<IdentityResource> GetIdentityResources()
{
return new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
};
}
public static List<TestUser> GetUsers()
{
return new List<TestUser>
{
new TestUser
{
SubjectId = "1",
Username = "alice",
Password = "password"
},
new TestUser
{
SubjectId = "2",
Username = "bob",
Password = "password"
}
};
}
}
public class LynxProfileService: IProfileService
{
private readonly IUserSevice _userService;
public LynxProfileService(IUserSevice userService)
{
if (userService == null)
throw new ArgumentNullException(nameof(userService));
_userService = userService;
}
public async Task GetProfileDataAsync(ProfileDataRequestContext context)
{
var id = int.Parse(context.Subject?.GetSubjectId() ?? "0");
if (id > 0)
{
var user = await _userService.GetUserByIdAsync(id);
if (user != null)
{
context.AddFilteredClaims(UserToClaims(user));
}
}
else
{
throw new Exception("USER NOT FOUND!!!");
}
}
public async Task IsActiveAsync(IsActiveContext context)
{
var id = int.Parse(context.Subject?.GetSubjectId() ?? "0");
Users user = null;
if (id > 0)
user = await _userService.GetUserByIdAsync(id);
context.IsActive = user != null;
}
/// <summary>
/// Преобразует свойства пользователя в массив <see cref="Claim"/>.
/// </summary>
/// <returns></returns>
private Claim[] UserToClaims(Users user)
{
var result = new List<Claim>
{
new Claim(
"name",
$"{user.FirstName} {user.SecondName} {user.Patronymic}",
"string"),
new Claim(
"email",
user.Email,
"string"),
new Claim(
"role",
user.Role?.RoleName.ToLower() ?? "user",
"string")
};
return result.ToArray();
}
}
public class LynxResourceOwnerPasswordValidator: IResourceOwnerPasswordValidator
{
private readonly IUserSevice UserService;
public LynxResourceOwnerPasswordValidator(IUserSevice userService)
{
if (userService == null)
throw new ArgumentNullException(nameof(userService));
UserService = userService;
}
public async Task ValidateAsync(ResourceOwnerPasswordValidationContext context)
{
var userId = await UserService.FindUserIdAsync(context.UserName, context.Password);
if (userId > 0)
{
context.Result = new GrantValidationResult(
userId.ToString(),
OidcConstants.AuthenticationMethods.Password);
}
else
{
context.Result = new GrantValidationResult(TokenRequestErrors.InvalidGrant);
}
}
}
public class Startup
{
...
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentityServer()
.AddProfileService<LynxProfileService>() // вытаскивание профиля пользователя
.AddResourceOwnerValidator<LynxResourceOwnerPasswordValidator>() // управление проверкой пароля
.AddSigningCredential(IdentityServerConfiguration.GetSigningCertificate()) // регистрация сертификата
.AddInMemoryPersistedGrants() // ?
.AddInMemoryApiResources(IdentityServerConfiguration.GetApiResources(AuthConstants.ApiSecret)) // ресурсы-апи
.AddInMemoryClients(IdentityServerConfiguration.GetClients()); // контроль клиентов
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IServiceProvider serviceProvider)
{
...
app.UseIdentityServer();
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
{
Authority = AuthConstants.AuthServerLocation,
AllowedScopes = { AuthConstants.ApiV1Scope },
RequireHttpsMetadata = false,
AutomaticAuthenticate = true,
AutomaticChallenge = true,
NameClaimType = "email",
RoleClaimType = "role"
});
...
}
...
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment