Maison > Article > développement back-end > Explication détaillée de l'exemple de conception d'authentification unique ASP.NET MVC SSO
Cet article présente principalement la conception et la mise en œuvre de l'authentification unique ASP.NET MVC SSO. Il a une certaine valeur de référence. Ceux qui sont intéressés peuvent en savoir plus.
Configuration de l'environnement expérimental
La configuration du fichier HOST est la suivante :
127.0.0.1 app.com
127.0.0.1 sso.com
La configuration IIS est la suivante :
Le pool d'applications utilise .Net Framework 4.0
Faites attention aux noms de domaine liés à IIS, deux noms de domaine complètement différents.
La configuration du site app.com est la suivante :
La configuration du site sso.com est la suivante :
memcachedCache :
Configuration de la base de données :
La base de données utilise EntityFramework 6.0, la base de données et la structure de table correspondantes seront automatiquement créées lors de la première exécution.
Démonstration du processus de vérification de l'autorisation :
Visitez : http://app.com dans la barre d'adresse du navigateur Si l'utilisateur ne s'est pas connecté, le site Web s'ouvrira automatiquement. redirect Accédez à : http://sso.com/passport et transmettez l'ID d'application AppKey correspondant via les paramètres QueryString. La capture d'écran en cours d'exécution est la suivante :
Adresse URL : http://sso.com/passport. ?appkey=670b14728ad9902aecba32e22fa4f6bd&username=
Après avoir entré le compte de connexion et le mot de passe corrects, cliquez sur le bouton de connexion et le système sera automatiquement redirigé vers l'application et la page d'accueil disparaîtra après. la destruction est réussie, comme indiqué ci-dessous :
Étant donné que la connexion par autorisation SSO est effectuée sous différents domaines, la méthode QueryString est utilisée pour renvoyer l'ID d'autorisation. Les cookies peuvent être utilisés sur des sites Web du même domaine. Puisque la demande de redirection 301 est envoyée par le navigateur, si l'identifiant d'autorisation est placé dans Handers, il sera perdu lors de la redirection du navigateur. Une fois la redirection réussie, le programme écrit automatiquement la marque d'autorisation dans le cookie. Lorsque vous cliquez sur d'autres adresses de page, les informations de la marque d'autorisation ne seront plus visibles dans la barre d'adresse URL. Les paramètres des cookies sont les suivants :
Vérification ultérieure de l'autorisation après une connexion réussie (accès à d'autres pages nécessitant une autorisation) :
Adresse de vérification : http:// sso.com/api/passport?sessionkey=xxxxxx&remark=xxxxxx
Résultats de retour : vrai, faux
Le client peut choisir de demander à l'utilisateur une autorisation en fonction de la situation commerciale réelle est perdue et doit être réautorisée. Par défaut, il est automatiquement redirigé vers la page de connexion SSO, à savoir : http://sso.com/passport?appkey=670b14728ad9902aecba32e22fa4f6bd&username=seo@ljja.cn. En même temps, la zone de texte de l'adresse e-mail sur la page de connexion s'affichera. Complétez automatiquement le compte de connexion de l'utilisateur. Il suffit à l'utilisateur de saisir le mot de passe de connexion. Après une autorisation réussie, la période de validité de la session sera automatiquement prolongée d'un an.
Journal de vérification de la base de données SSO :
Journal de vérification de l'autorisation de l'utilisateur :
Session d'autorisation de l'utilisateur Session :
Compte utilisateur de la base de données et informations sur l'application :
Code principal de la page de vérification de la connexion à l'autorisation de l'application :
/// <summary> /// 公钥:AppKey /// 私钥:AppSecret /// 会话:SessionKey /// </summary> public class PassportController : Controller { private readonly IAppInfoService _appInfoService = new AppInfoService(); private readonly IAppUserService _appUserService = new AppUserService(); private readonly IUserAuthSessionService _authSessionService = new UserAuthSessionService(); private readonly IUserAuthOperateService _userAuthOperateService = new UserAuthOperateService(); private const string AppInfo = "AppInfo"; private const string SessionKey = "SessionKey"; private const string SessionUserName = "SessionUserName"; //默认登录界面 public ActionResult Index(string appKey = "", string username = "") { TempData[AppInfo] = _appInfoService.Get(appKey); var viewModel = new PassportLoginRequest { AppKey = appKey, UserName = username }; return View(viewModel); } //授权登录 [HttpPost] public ActionResult Index(PassportLoginRequest model) { //获取应用信息 var appInfo = _appInfoService.Get(model.AppKey); if (appInfo == null) { //应用不存在 return View(model); } TempData[AppInfo] = appInfo; if (ModelState.IsValid == false) { //实体验证失败 return View(model); } //过滤字段无效字符 model.Trim(); //获取用户信息 var userInfo = _appUserService.Get(model.UserName); if (userInfo == null) { //用户不存在 return View(model); } if (userInfo.UserPwd != model.Password.ToMd5()) { //密码不正确 return View(model); } //获取当前未到期的Session var currentSession = _authSessionService.ExistsByValid(appInfo.AppKey, userInfo.UserName); if (currentSession == null) { //构建Session currentSession = new UserAuthSession { AppKey = appInfo.AppKey, CreateTime = DateTime.Now, InvalidTime = DateTime.Now.AddYears(1), IpAddress = Request.UserHostAddress, SessionKey = Guid.NewGuid().ToString().ToMd5(), UserName = userInfo.UserName }; //创建Session _authSessionService.Create(currentSession); } else { //延长有效期,默认一年 _authSessionService.ExtendValid(currentSession.SessionKey); } //记录用户授权日志 _userAuthOperateService.Create(new UserAuthOperate { CreateTime = DateTime.Now, IpAddress = Request.UserHostAddress, Remark = string.Format("{0} 登录 {1} 授权成功", currentSession.UserName, appInfo.Title), SessionKey = currentSession.SessionKey }); 104 var redirectUrl = string.Format("{0}?SessionKey={1}&SessionUserName={2}", appInfo.ReturnUrl, currentSession.SessionKey, userInfo.UserName); //跳转默认回调页面 return Redirect(redirectUrl); } } Memcached会话标识验证核心代码: public class PassportController : ApiController { private readonly IUserAuthSessionService _authSessionService = new UserAuthSessionService(); private readonly IUserAuthOperateService _userAuthOperateService = new UserAuthOperateService(); public bool Get(string sessionKey = "", string remark = "") { if (_authSessionService.GetCache(sessionKey)) { _userAuthOperateService.Create(new UserAuthOperate { CreateTime = DateTime.Now, IpAddress = Request.RequestUri.Host, Remark = string.Format("验证成功-{0}", remark), SessionKey = sessionKey }); return true; } _userAuthOperateService.Create(new UserAuthOperate { CreateTime = DateTime.Now, IpAddress = Request.RequestUri.Host, Remark = string.Format("验证失败-{0}", remark), SessionKey = sessionKey }); return false; } }
Attribut des filtres de vérification d'autorisation client
public class SSOAuthAttribute : ActionFilterAttribute { public const string SessionKey = "SessionKey"; public const string SessionUserName = "SessionUserName"; public override void OnActionExecuting(ActionExecutingContext filterContext) { var cookieSessionkey = ""; var cookieSessionUserName = ""; //SessionKey by QueryString if (filterContext.HttpContext.Request.QueryString[SessionKey] != null) { cookieSessionkey = filterContext.HttpContext.Request.QueryString[SessionKey]; filterContext.HttpContext.Response.Cookies.Add(new HttpCookie(SessionKey, cookieSessionkey)); } //SessionUserName by QueryString if (filterContext.HttpContext.Request.QueryString[SessionUserName] != null) { cookieSessionUserName = filterContext.HttpContext.Request.QueryString[SessionUserName]; filterContext.HttpContext.Response.Cookies.Add(new HttpCookie(SessionUserName, cookieSessionUserName)); } //从Cookie读取SessionKey if (filterContext.HttpContext.Request.Cookies[SessionKey] != null) { cookieSessionkey = filterContext.HttpContext.Request.Cookies[SessionKey].Value; } //从Cookie读取SessionUserName if (filterContext.HttpContext.Request.Cookies[SessionUserName] != null) { cookieSessionUserName = filterContext.HttpContext.Request.Cookies[SessionUserName].Value; } if (string.IsNullOrEmpty(cookieSessionkey) || string.IsNullOrEmpty(cookieSessionUserName)) { //直接登录 filterContext.Result = SsoLoginResult(cookieSessionUserName); } else { //验证 if (CheckLogin(cookieSessionkey, filterContext.HttpContext.Request.RawUrl) == false) { //会话丢失,跳转到登录页面 filterContext.Result = SsoLoginResult(cookieSessionUserName); } } base.OnActionExecuting(filterContext); } public static bool CheckLogin(string sessionKey, string remark = "") { var httpClient = new HttpClient { BaseAddress = new Uri(ConfigurationManager.AppSettings["SSOPassport"]) }; var requestUri = string.Format("api/Passport?sessionKey={0}&remark={1}", sessionKey, remark); try { var resp = httpClient.GetAsync(requestUri).Result; resp.EnsureSuccessStatusCode(); return resp.Content.ReadAsAsync<bool>().Result; } catch (Exception ex) { throw ex; } } private static ActionResult SsoLoginResult(string username) { return new RedirectResult(string.Format("{0}/passport?appkey={1}&username={2}", ConfigurationManager.AppSettings["SSOPassport"], ConfigurationManager.AppSettings["SSOAppKey"], username)); } }
Exemple d'utilisation de la fonctionnalité de vérification SSO :
[SSOAuth] public class HomeController : Controller { public ActionResult Index() { return View(); } public ActionResult About() { ViewBag.Message = "Your application description page."; return View(); } public ActionResult Contact() { ViewBag.Message = "Your contact page."; return View(); } }
Résumé :
À partir du brouillon d'exemple de code, vous pouvez voir qu'il existe encore de nombreux domaines d'optimisation pour le code performances. Il existe également une série de messages d'invite tels que le compte utilisateur sur la page de connexion d'autorisation de l'application SSO n'existe pas, le mot de passe est incorrect, etc. À un stade ultérieur, lorsque le code métier s'exécute fondamentalement correctement, vous pouvez envisager d'optimiser davantage de niveaux de sécurité, par exemple en activant la vérification de la signature de clé privée AppSecret, la vérification de la plage IP, l'attaque par demande de session fixe et le code de vérification du Interface de connexion d'autorisation SSO, reconstruction automatique du cache de session, expansion horizontale du serveur SSo, du cache, etc.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!