在WinForms中验证用户(与ASP.Net无关)
注意:
Cross-posted to ServerFault,基于评论.
介绍 我需要密码保护我的应用程序中的某些操作,例如加载/保存文件,单击复选框等.这是一个标准的C#.Net 4.0,WinForms应用程序,它将在企业网络中的Windows 7上运行. 我正打算使用用户/密码/权限(哈希和盐渍)的文本文件滚动我自己的非常基本的系统(使用大开后门进行混淆)直到经过一些搜索后我发现了什么看起来像 题 所以有人知道一个或多个教程,告诉我如何: >创建Windows用户/组并为该用户/组授予角色或权限. >请注意,我正在使用我公司的联网笔记本电脑进行测试,但是会将其部署在客户的公司网络上(不确定这是否是一个问题,或者这将是多么棘手). >创建winforms / console app示例甚至只有一个方法打印“Hello World”如果我已经过身份验证,或者如果我不是则会抛出异常? 背景 - read if interested,but not required to answer question 为了确保我在这里朝着正确的方向前进,基本上我需要/想要在我的开发PC上测试它,以确保它能为我的客户提供良好的最终用户体验.问题是,目前他们为运行我的应用程序的每台计算机运行自动登录脚本,并且有几个不同的运算符在一天中使用我的应用程序.客户希望我的应用程序的某些功能受到密码保护,并且只向某些操作符提供.我没有问题,因为我已经预料到请求一段时间了,我以前从未编程过身份验证. 我认为说服我的客户为每个操作符提供他们自己的网络帐户并为他们分配他们想要的任何权限是值得的,以防他们需要解雇某人,更改权限等.这也意味着我只需打开几个选项他们可以根据内部公司政策对这些权限进行分组,但我真的不应该担心这些权限(但如果我必须自己动手,因为他们的IT部门几乎一无所知)我的应用程序). 从我所知道的,它还可以通过不必处理散列密码和加密等使我的生活变得更加轻松,并且只需处理单击此按钮或该按钮所需的角色. 解决方法
首先,您必须确定,如果您真的想要一个简单的基于角色的身份验证(您可能需要阅读:
http://lostechies.com/derickbailey/2011/05/24/dont-do-role-based-authorization-checks-do-activity-based-checks/)
如果您确定这绝对足够,那么您已经使用您在问题中提供的SO链接以正确的方式进行了操作.有点令人困惑的是,Windows中默认不支持“角色”,但有些组.组可以是本地的或远程的(例如ActiveDirectory),因此管理员可以将用户分配给特定于您的应用程序的特定组(例如,查看此处:http://msdn.microsoft.com/en-us/library/ms731200(v=vs.110).aspx) 一个关键是:您必须准备应用程序的中心主体,因此需要为当前用户支持角色. 因此,在应用程序启动时,您可以检查当前活动用户并设置应用程序范围内的主体和角色.这可能看起来像这样(只是一个非常简单的例子): using System; using System.Collections.Generic; using System.Linq; using System.Security; using System.Security.Principal; using System.Text; using System.Threading; namespace WindowsPrincipalTrial { public class Program { // you could also move these definitions to a config file private static IDictionary<string,string> _groupRoleMappings = new Dictionary<string,string>() { {"MYAPPUSERGRP",MyRoles.Standard},{"MYAPPSUPPORTGRP",MyRoles.Extended},{"MYAPPADMINGRP",MyRoles.Admin},}; private static void Main(string[] args) { var windowsId = WindowsIdentity.GetCurrent(); if (windowsId != null) { var allRoleNames = getGroupCorrespondingRoles(windowsId); var newPrincipal = new GenericPrincipal(windowsId,allRoleNames); Thread.CurrentPrincipal = newPrincipal; } else { throw new NotSupportedException("There must be a logged on Windows User."); } } private static string[] getGroupCorrespondingRoles(WindowsIdentity id) { // you also could do this more elegant with LINQ var allMappedRoleNames = new List<string>(); string roleName; foreach (var grp in id.Groups) { var groupName = grp.Translate(typeof(NTAccount)).Value.ToUpper(); if (_groupRoleMappings.TryGetValue(groupName,out roleName)) { allMappedRoleNames.Add(roleName); } } return allMappedRoleNames.ToArray(); } } public static class MyRoles { public const string Standard = "standard_role"; public const string Extended = "extended_role"; public const string Admin = "admin_role"; } } 然后设置您的Application-Principal. public void DoSomethingSpecial() { if (Thread.CurrentPrincipal.IsInRole(MyRoles.Extended)) { // do your stuff } else { // maybe display an error } } 或者更彻底地: public void DoSomethingCritical() { var adminPermission = new PrincipalPermission(null,MyRoles.Admin); adminPermission.Demand(); // do stuff } 从ASP.NET中可以看出,即使是声明也是可能的: [PrincipalPermission(SecurityAction.Demand,Role=MyRoles.Admin)] public void DoSomethingMoreCritical() { // do stuff } 后两个例子的丑陋之处在于,当正确的角色没有被击中时,它们会抛出异常. 因此,根据您要使用的系统(本地组,AD组,LDAP组等),您必须在应用程序开始时完成角色和组之间的映射. 但是,如果您更喜欢使用操作和角色进行身份验证,那么请查看Windows Identity Foundation和基于声明的授权!那里已经有一些现成的框架(例如https://github.com/thinktecture/Thinktecture.IdentityModel). 更新: 当涉及基于活动并因此基于声明的授权时,我将通过使用Thinktecture的IdentityModel来尝试如何实现它. 通常,该方法仍然在内部使用角色,但在它们之间有一种转换层. Thinktecture已经封装了许多所需的东西.然后通过声明权限完成代码中的授权检查.它们在技术上是对访问某种资源的请求.为了简单起见,我通过使用一个默认资源限制了我的动作示例(因为ClaimPermission不接受空资源). 首先,您需要一个ClaimsAuthorizationManager public class MyClaimsAuthorizationManager : ClaimsAuthorizationManager { private IActivityRoleMapper _actionToRolesMapper; public MyClaimsAuthorizationManager(IActivityRoleMapper mapper) { _actionToRolesMapper = mapper; } public override bool CheckAccess(AuthorizationContext context) { if (context == null) { throw new ArgumentNullException("context"); } try { var action = getActionNameFromAuthorizationContext(context); var sufficientRoles = _actionToRolesMapper.GetRolesForAction(action) .Select(roleName => roleName.ToUpper()); var principal = context.Principal; return CheckAccessInternal(sufficientRoles,principal); } catch (Exception ex) { return false; } } protected virtual bool CheckAccessInternal(IEnumerable<string> roleNamesInUpperCase,IClaimsPrincipal principal) { var result = principal.Identities.Any(identity => identity.Claims .Where(claim => claim.ClaimType.Equals(identity.RoleClaimType)) .Select(roleClaim => roleClaim.Value.ToUpper()) .Any(roleName => roleNamesInUpperCase.Contains(roleName))); return result; } // I'm ignoring resources here,modify this,if you need'em private string getActionNameFromAuthorizationContext(AuthorizationContext context) { return context.Action .Where(claim => claim.ClaimType.Equals(ClaimPermission.ActionType)) .Select(claim => claim.Value) .FirstOrDefault(); } } 您可能已经猜到,IActivityRoleMapper是一个类的接口,它返回所有角色的名称,包括给定操作的权限. 然后你必须将main()方法中的代码更改为: using Thinktecture.IdentityModel; using Thinktecture.IdentityModel.Claims; using Microsoft.IdentityModel.Web; private static void Main(string[] args) { var windowsId = WindowsIdentity.GetCurrent(); if (windowsId != null) { var rolesAsClaims = getGroupCorrespondingRoles(windowsId) .Select(role => new Claim(ClaimTypes.Role,role)) .ToList(); // just if you want,remember the username rolesAsClaims.Add(new Claim(ClaimTypes.Name,windowsId.Name)); var newId = new ClaimsIdentity(rolesAsClaims,null,ClaimTypes.Name,ClaimTypes.Role); var newPrincipal = new ClaimsPrincipal(new ClaimsIdentity[] { newId }); AppDomain.CurrentDomain.SetThreadPrincipal(newPrincipal); var roleMapper = new ActivityRoleMapper(); // you have to implement // register your own authorization manager,so IdentityModel will use it per default FederatedAuthentication.ServiceConfiguration.ClaimsAuthorizationManager = new MyClaimsAuthorizationManager(roleMapper); } else { throw new NotSupportedException("There must be a logged on Windows User."); } } 最后你可以通过这种方式检查访问: public const string EmptyResource = "myapplication"; public void DoSomethingRestricted() { if (!ClaimPermission.CheckAccess("something_restricted",EmptyResource)) { // error here } else { // do your really phat stuff here } } 或者,除了例外: private static ClaimPermission RestrictedActionPermission = new ClaimPermission(EmptyResource,"something_restricted"); public void DoSomethingRestrictedDemand() { RestrictedActionPermission.Demand(); // play up,from here! } 声明: [ClaimPermission(SecurityAction.Demand,Operation = "something_restricted",Resource = EmptyResource)] public void DoSomethingRestrictedDemand2() { // dostuff } 希望这可以帮助. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- 身份更改GUID为int
- asp.net-mvc – ASP.NET MVC 4 Web Api和REST经典服务之间的
- asp-classic – ASP会话变量:是否与IsEmpty相同?
- asp.net-mvc – ASP.NET MVC在新窗口中打开pdf文件
- ASP.NET ReportViewer在本地模式下非常慢
- asp.net-mvc-3 – 造型ASP.NET MVC验证错误?
- C# 之 DataReader 和 DataSet 的区别
- 如何使用ASP.net C#将SQL select存储到gridview?
- asp.net – 如何使用kentico CMS获取GoogleNewsSitemap中的
- ASP.NET MVC实现简单的文件上传与下载
- asp.net-mvc-4 – URL以’/’结尾时的服务器错误
- asp.net – AJAX updatepanel给出错误
- 将mvc 5应用程序连接到Azure中的ACS?
- asp.net-mvc – Asp.Net MVC中设计师友好的视图
- asp.net – SQL Reporting Services可以与ASP成员
- asp.net-mvc – 如何实现基于信誉的用户权限,如S
- 在ASP.Net动态数据中使用Computed Property作为D
- asp.net-mvc – MVC ViewBag最佳实践
- iis – 在经典ASP / Javascript中将对象插入全局
- asp.net-mvc-3 – 实体框架4.1代码优先,需要延迟