gpt4 book ai didi

winforms - 在 WinForms 中验证用户身份(与 ASP.Net 无关)

转载 作者:行者123 更新时间:2023-12-02 22:03:19 24 4
gpt4 key购买 nike

注:Cross-posted to ServerFault ,基于评论。

简介

我需要用密码保护应用程序中的某些操作,例如加载/保存文件、单击复选框等。这是一个标准的 C# .Net 4.0、WinForms 应用程序,将在企业网络中的 Windows 7 上运行。

我本来打算用用户/密码/权限(散列和加盐)的文本文件来滚动我自己的非常基本的系统(通过敞开的后门读取混淆),直到经过一些搜索后,我发现了看起来像 tantalizingly simple approach ,但我很难找到关于 ASP.NET 的关于角色的优秀教程。

问题

有谁知道一个或多个教程可以告诉我如何:

  1. 创建一个 Windows 用户/组并为该用户/组授予角色或权限。
    • 请注意,我正在公司的联网笔记本电脑上对此进行测试,但会将其部署在客户的公司网络上(不确定这是否是一个问题,或者这会变得多么棘手)。
  2. 创建 winforms/console 应用程序示例,即使只有一个方法,如果我已通过身份验证,则打印“Hello World”;如果未通过身份验证,则抛出异常?
  3. 我从未做过网络管理或任何相关的工作,并且我一直在阅读有关 Active Directory 和本地用户与网络用户的内容...我希望找到一种可以构建界面的方法,并且只需询问 Windows 当前用户是否拥有 ABC 权限,而不必太关心 Windows 是如何计算出来的。然后我可以为每个本地/网络/ActiveDirectory/等进行具体的实现。根据需要使用案例(或者如果需要...因为我现在甚至不知道)。

背景

- read if interested, but not required to answer question

为了确保我在这里朝着正确的方向前进,基本上我需要/想要在我的开发 PC 上进行测试,以确保它能为我的客户提供良好的最终用户体验。问题是,目前他们为运行我的应用程序的每台计算机运行自动登录脚本,并且有几个不同的运算符(operator)全天使用我的应用程序。客户希望对我的应用程序的某些功能提供密码保护,并且只向某些运营商提供密码保护。我对此没有任何问题,因为我已经预料到这个请求有一段时间了,我只是以前从未编写过身份验证程序。

我认为说服我的客户为每个运算符(operator)提供自己的网络帐户并向该运算符(operator)或组分配他们想要的任何权限是值得的,以防他们需要解雇某人、更改权限等。这也意味着我只需打开为他们提供了多种选择,他们可以根据内部公司政策对这些权限进行分组,但他们认为合适,我真的不必担心(但如果我必须推出自己的政策,就会担心,因为他们的 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";
}
}

然后您的应用程序主体已设置完毕。现在您可以像这样检查代码中的访问权限:

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 不接受空资源)。如果您想使用action@resource对,则必须分别修改代码。

首先您需要一个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 是一个类的接口(interface),它返回所有角色的名称,其中包括给定操作的权限。这个类非常个性化,我想你会找到实现它的方法,因为这不是这里的重点。您可以通过硬编码、从 xml 或数据库加载来实现。此外,如果您想要使用 action@resource 对来请求权限,则必须更改/扩展它。

然后你必须将 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
}
}

或者再说一次,但有异常(exception):

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
}

希望这有帮助。

关于winforms - 在 WinForms 中验证用户身份(与 ASP.Net 无关),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22873717/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com