Atis.Identity.Sso
2.0.0-preview.4
dotnet add package Atis.Identity.Sso --version 2.0.0-preview.4
NuGet\Install-Package Atis.Identity.Sso -Version 2.0.0-preview.4
<PackageReference Include="Atis.Identity.Sso" Version="2.0.0-preview.4" />
<PackageVersion Include="Atis.Identity.Sso" Version="2.0.0-preview.4" />
<PackageReference Include="Atis.Identity.Sso" />
paket add Atis.Identity.Sso --version 2.0.0-preview.4
#r "nuget: Atis.Identity.Sso, 2.0.0-preview.4"
#:package Atis.Identity.Sso@2.0.0-preview.4
#addin nuget:?package=Atis.Identity.Sso&version=2.0.0-preview.4&prerelease
#tool nuget:?package=Atis.Identity.Sso&version=2.0.0-preview.4&prerelease
Atis.Identity.Sso
ATIS MVC WebUI-lərini atis-service-user-in OpenIddict serverinə OIDC relying party (RP) kimi qoşan paket.
Servis protokolu görmür: bir qeydiyyat çağırışı + bir endpoint çağırışı.
// Program.cs
builder.ConfigureAtisSerilog();
builder.Services.AddAtisWebUiHost(builder.Configuration, Assembly.GetExecutingAssembly());
builder.Services.AddAtisSsoRelyingParty(builder.Configuration, o => o.AddPermissionPolicies(StaffPermissions.All));
var app = builder.Build();
app.UseAtisWebUiHost(); // routing → authentication → authorization → session
app.MapAtisSso(); // /account/login, /account/logout
app.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
app.Run();
"Sso": {
"Authority": "https://user.atis.edu.az",
"ClientId": "atis-staff",
"ClientSecret": "<secret store-dan — appsettings.json-a YAZILMIR>",
"DataProtection": { "ApplicationName": "atis-staff", "RedisConnection": "redis:6379" }
}
Nə qurulur
| Hissə | Dəyər | Niyə |
|---|---|---|
| Sxemlər | default/sign-in/sign-out = Cookies, challenge = OpenIdConnect |
Standart "cookie + oidc" RP: sessiya lokal cookie-dədir, [Authorize] OIDC axınını başladır |
| Cookie | Atis.Sso, HttpOnly, SameSite=Lax, Secure=SameAsRequest, sürüşən 60 dəq (CookieExpireMinutes) |
Proxy arxasında plain HTTP konteyner (ForwardedHeaders IsHttps-i düzəldir) |
| OIDC | authorization code + PKCE (S256), response_mode=query, SaveTokens=true, RequireHttpsMetadata=true |
Spec §5.1; token-lər HttpContext.GetTokenAsync("access_token") ilə servis API-lərinə ötürülür |
| Claim-lər | MapInboundClaims=false, NameClaimType="name", RoleClaimType="role" |
Atis.Identity.Token oxuyucuları xam OIDC adlarını gözləyir (sub, role, UserKey.*) |
| Userinfo | GetClaimsFromUserInfoEndpoint=true; permission[], role[], UserKey.* yalnız çatışmayanlar əlavə olunur |
Server permission-ı id token-ə YAZMIR (yalnız access token + userinfo); id token-dəki role təkrarlanmır |
| İcazə | AddAtisAuthorization(policies) → fail-closed PermissionAuthorizationHandler, ICurrentUser |
Policy-siz RP-də [Authorize(Policy=…)] ilk sorğuda sınardı — ona görə policies null → InvalidOperationException |
| Scope-lar | openid profile email roles atis (defolt) |
atis = UserKey.* id token-ə, permission userinfo-ya; offline_access lazımdırsa Sso:Scopes-da açıq yaz |
| Access denied | AccessDeniedPath boş → 403 status (redirect yox) |
RP-lərdə /Account/AccessDenied səhifəsi yoxdur |
| Callback xətası | log + RemoteFailurePath (/) ?ssoError=cancelled\|failed |
Ləğv edilmiş login / itmiş correlation cookie 500 səhifəsi verməsin; ləğv Warning, qalanı Error (konfiq səhvi alert-ə düşür). RemoteFailurePath anonim səhifə olmalıdır — [Authorize] səhifə hər dəfə sınan callback ilə redirect döngəsi yaradır |
Sso:Scopes yazılanda defoltu əvəz edir (ASP.NET Core binder-i massivə əlavə etdiyi üçün xassənin defoltu
boşdur; openid mütləqdir, validator yoxlayır).
Endpoint-lər (MapAtisSso)
GET /account/login?returnUrl=/staff— OIDC challenge, sondareturnUrl-ə qayıdır. Yalnız kökə nisbi lokal yol (/x) qəbul olunur;//evil, mütləq URL →/(open redirect yoxdur).GET|POST /account/logout— lokal cookie silinir, server-də/connect/logout(id_token_hintsaxlanılan id token-dən,post_logout_redirect_uri=SignedOutCallbackPath) →SignedOutRedirectPath(/).
OpenIddict tərəfində client belə qeyd olunur (atis-service-user OpenIddict:Clients[]): Type: code,
RedirectUris: ["https://staff.atis.edu.az/signin-oidc"], PostLogoutRedirectUris: ["https://staff.atis.edu.az/signout-callback-oidc"],
Scopes: ["openid","profile","email","roles","atis"].
Sso bölməsi
| Açar | Defolt | Qeyd |
|---|---|---|
Authority |
— | mütləq, mütləq http(s) URI; http yalnız RequireHttpsMetadata=false ilə |
ClientId / ClientSecret |
— | mütləq; secret yalnız secret store/env-dən |
Scopes[] |
openid profile email roles atis |
openid mütləq |
CookieName / CookieExpireMinutes |
Atis.Sso / 60 |
|
CallbackPath / SignedOutCallbackPath |
/signin-oidc / /signout-callback-oidc |
kökə nisbi, fərqli |
SignedOutRedirectPath / RemoteFailurePath |
/ / / |
kökə nisbi; RemoteFailurePath anonim olmalıdır (?ssoError= markeri gəlir) |
AccessDeniedPath |
boş (→ 403) | verilibsə cookie defolt redirect-i |
RequireHttpsMetadata / SaveTokens |
true / true |
|
DataProtection:ApplicationName |
boş | verilibsə SetApplicationName; Redis ilə mütləq |
DataProtection:RedisConnection |
boş | verilibsə açarlar Redis-də DataProtection-Keys:<ApplicationName>; bağlantı ilk açar istifadəsində açılır (start-da yox) |
Bütün açarlar ValidateOnStart() ilə host qalxanda yoxlanılır — səhv konfiq OptionsValidationException verir.
Testdə RP-ni qurmaq
Backchannel (discovery/jwks/token/userinfo) in-process serverə yönləndirilir — Configure ilə, PostConfigure ilə yox
(handler Backchannel HttpClient-i post-configure mərhələsində BackchannelHttpHandler-dən qurur):
services.Configure<OpenIdConnectOptions>(AtisSsoDefaults.OidcScheme, o => o.BackchannelHttpHandler = serverHandler);
Paketin öz testləri (tests/Atis.Identity.Sso.Tests) stub OIDC server (RS256, PKCE yoxlanır) ilə tam axını —
challenge parametrləri, id token + userinfo birləşməsi, fail-closed policy, ICurrentUser, logout id_token_hint,
userinfo xətası, AddAtisWebUiHost ilə kompozisiya — pin edir. Real OpenIddict serverinə qarşı eyni axın
atis-service-user-in tests/Services.Tests/Sso dəstində sübut olunub.
Bilinən məhdudiyyətlər və qaydalar
AddAtisSsoRelyingParty-dən sonraAddAuthentication(...)çağırma — tək-arqumentli overloadDefaultScheme-i dəyişir, cookie principal oxunmur və hər səhifə anonim olur.AddAtisApiHost(JWT bearer) ilə eyni prosesdə birləşdirmə: API və WebUI ayrı proseslərdir (spec §4); birləşdirsən eyniSsobölməsiAudiencetələb edib start-da sınar.SaveTokensvə token ömrü: cookie sürüşən (60 dəq), saxlanılanaccess_tokenisə server ömrü ilə (OpenIddict defoltu ~1 saat) bitir və defolt scope-larda refresh token yoxdur. Servis API-lərini cookie sessiyasından çağırırsansa yaSso:Scopes-aoffline_accessəlavə edib yeniləməni özün qur, ya daCookieExpireMinutes-i access token ömründən qısa saxla.- Logout GET-dir (ATIS Core ilə eyni): zərərli səhifədən top-level naviqasiya ilə məcburi çıxış mümkündür — təsiri yalnız narahatlıqdır (məlumat sızması/sessiya oğurluğu yoxdur). Təsdiq səhifəsi istəyən servis öz POST endpoint-ini map edir.
- Cookie ticket-i
permission[]claim-lərini daşıyır: çoxlu icazəsi olan istifadəçidə cookie chunk-lanır (ASP.NET Core bunu özü edir, 4 KB-lıq hissələr). Böyüklük problem olarsaITicketStore(server tərəfi sessiya) növbəti addımdır — paket hazırda qurmur. - İstifadəçi kimliyi (
sub,UserKey.UserId) yalnız imzalanmış id token-dən gəlir; userinfo onu dəyişə bilmir (frameworksub-u tutuşdurur,UserIduserinfo siyahısında deyil). - Userinfo çağırışı hər login-də bir dəfədir; cookie ömrü boyunca icazə dəyişikliyi görünmür (ATIS Core-un mövcud cookie davranışı ilə eyni). Anında ləğv lazımdırsa cookie ömrünü qısalt.
Eventsbütövlükdə əvəz edilsə (EventsType) paketinOnRemoteFailure-u itir — öz event sinfini ondan törət.- Redis key ring real Redis ilə yoxlanmayıb (test mühitində Redis yoxdur);
ApplicationNameqaydası, qeydiyyat və "əlçatmaz Redis host-un qalxmasına mane olmur" yoxlanıb. BağlantıAbortOnConnectFail=falseilə açılır və uğursuz cəhd keşlənmir — Redis qayıdan kimi açarlar oxunur (o vaxta qədər autentifikasiyalı sorğular 500 verir).
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Atis.Identity.Token (>= 2.0.0-preview.4)
- Microsoft.AspNetCore.Authentication.OpenIdConnect (>= 8.0.18)
- Microsoft.AspNetCore.DataProtection.StackExchangeRedis (>= 8.0.18)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 8.0.0)
- Microsoft.IdentityModel.Protocols.OpenIdConnect (>= 8.13.0)
- StackExchange.Redis (>= 2.8.16)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.0-preview.4 | 83 | 9/14/2026 |
2.0.0-preview.3: ilk buraxılış — legacy gRPC/Microsoft.Identity.Web fork-unu əvəz edir. AddAtisSsoRelyingParty (Sso bölməsi, start-da validasiya, cookie "Atis.Sso" + OIDC code+PKCE, MapInboundClaims=false, name/role claim tipləri, SaveTokens, userinfo-dan permission/role/UserKey.* claim-ləri), MapAtisSso (/account/login, /account/logout), opsional DataProtection tətbiq adı və Redis key ring.