在 WinForms 中对用户进行身份验证(与 ASP.Net 无关) [英] Authenticate user in WinForms (Nothing to do with ASP.Net)

查看:28
本文介绍了在 WinForms 中对用户进行身份验证(与 ASP.Net 无关)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

注意:交叉发布到 ServerFault,基于评论.

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

I need to password protect some actions in my application, such as loading/saving files, clicking check-boxes, etc. This is a standard C# .Net 4.0, WinForms application which will run on Windows 7 in a corporate network.

我正准备使用包含用户/密码/权限(散列和加盐)的文本文件来推出我自己的非常基本的系统(阅读大开后门的混淆),直到经过一番搜索,我发现看起来像非常简单的方法,但我很难找到关于不是的角色的好教程> 关于 ASP.NET.

I was about to roll my own very basic system (read obfuscation with wide open backdoors) with a text file of users/passwords/permissions (hashed and salted) until after some searching I found what looks like a tantalizingly simple approach , but I'm having trouble finding a good tutorial on Roles that isn't about ASP.NET.

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

So does anyone know of one or more tutorials that show me how to:

  1. 创建一个 Windows 用户/组并为该用户/组授予一个角色或权限.
    • 请注意,我正在公司的联网笔记本电脑上进行测试,但会将其部署在客户的公司网络上(不确定这是否是一个问题,或者这会变得多么棘手).

背景

- read if interested, but not required to answer question

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

Just to make sure I'm going in the right direction here, basically I need/want to test this on my development PC to make sure it's going to have a good end-user experience for my customer. The problem is that currently they run an Auto-login script for each computer that runs my application and there are several different operators that use my application throughout the day. The customer wants password protection on certain features of my app and only provide that to certain operators. I have no problem fitting this in, as I've expected the request for a while, I just haven't ever programmed authentication before.

我认为说服我的客户为每个运营商提供他们自己的网络帐户并为该运营商或组分配他们想要的任何权限是值得的,以防他们需要解雇某人,更改权限等.这也意味着我只是打开他们有几个选项,他们可以根据内部公司政策对这些权限进行分组,但他们认为合适,我真的不必担心(但如果我必须自己动手,他们会担心,因为他们是 IT 部门知道的)几乎没有我的应用程序).

I think it's worthwhile to convince my customer to give each operator their own network account and assign whatever permissions they want to that operator or group, in case they need to fire somebody, change permissions, etc. It also means I just open several options for them and they can group those permissions however they see fit based on internal corporate policies, which I really shouldn't have to be worried about (but will be if I have to roll my own, as they're IT department knows almost nothing of my application).

据我所知,它也让我的生活变得更轻松,因为不必处理散列密码和加密等问题,只需处理点击这个或那个按钮所需的角色.

From what I can tell it also makes my life a lot easier by not having to deal with hashing passwords and encryption, etc. and just handle which Role is required to click this or that button.

推荐答案

首先,您必须确定,您是否真的想要一个简单的基于角色的身份验证(您可能需要阅读:http://lostechies.com/derickbailey/2011/05/24/dont-do-role-based-authorization-checks-do-activity-based-checks/)

First of all, you'd have to determine, if you really want a simple role-based-authentication (you may want to read: 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)

If you're sure it's absolutely sufficient, you're already on the right way with the SO link you provided in your question. It's kind of confusing that there is no support of 'roles' by default in Windows, but there are groups. Groups can be local or remote (e.g. ActiveDirectory), so an admin could assign users to certain groups, that are specific for your application (for an example look here: http://msdn.microsoft.com/en-us/library/ms731200(v=vs.110).aspx)

一个关键是:您必须准备应用程序的中心主体,从而为其填充当前用户支持的角色.

One key is: You have to prepare your application's central principal, hence fill it with roles, supported for the current user.

因此,在您的应用程序启动时,您会检查当前的活动用户并设置您的应用程序范围的主体和角色.这可能看起来像这样(只是一个非常简单的例子):

Therefore, On the very startup of your application you then check the current active user and set your application wide principal and role(s). This may look like this (just a very simple example):

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";
    }
}

然后您的应用程序主体就设置好了.现在您可以像这样在代码中检查访问权限:

Then your Application-Principal is set up. Now you could check access in your code like this:

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 中可以知道的甚至是声明性的:

what is possible even declarative, as known from ASP.NET:

[PrincipalPermission(SecurityAction.Demand, Role=MyRoles.Admin)]
public void DoSomethingMoreCritical()
{
    // do stuff
}

后两个示例的丑陋之处在于,当没有命中正确的角色时,它们会抛出异常.

The ugly thing with the latter two examples is, that they throw exceptions, when the right role isn't hit.

因此,根据您要使用的系统(本地组、AD 组、LDAP 组等),您必须在应用开始时完成角色和组之间的映射.

So the mapping between roles and groups you have to do quite at the start of your app, according to the systems you want to use (local groups, AD groups, LDAP groups etc.).

但是,如果您更喜欢使用操作和角色进行身份验证,请查看 Windows Identity Foundation 和基于声明的授权!已经有一些现成的框架(例如 https://github.com/thinktecture/Thinktecture.身份模型).

If you, however, prefer authentication with actions and roles, after all, have a look at Windows Identity Foundation and Claims Based Authorization! There are already some ready-to-use frameworks out there (e.g. https://github.com/thinktecture/Thinktecture.IdentityModel).

更新:

当涉及到基于活动并因此基于声明的授权时,我将尝试简而言之,如何通过使用 Thinktecture 的 IdentityModel 来实现它.

When it comes to activity based and thereby claims based authorization, I will try in short, how you could achieve it, by using Thinktecture's IdentityModel.

一般来说,这种方法仍然在内部使用角色,但中间有一种翻译层.Thinktecture 已经封装了许多所需的东西.然后通过声明权限完成代码中的授权检查.它们在技术上是一种访问特定资源的请求.为简单起见,我将示例限制为仅用于操作,通过使用一个默认资源(因为 ClaimPermission 不接受空资源).如果要使用 action@resource 对,则需要分别修改代码.

Generally that approach still uses roles internally, but has a kind of translation layer in between. Thinktecture already encapsulates many things needed. Authorization checks in code are then done via claim permissions. They are technically kind of request for an access to a certain resource. For the sake of simplicity I limit my example for actions only, by using one single default resource (since ClaimPermission doesn't accept an empty resource). If you want to use action@resource pairs, you'd have to modify the code respectively.

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

As you may have guessed, IActivityRoleMapper is an interface for a class, that returns the names of all roles, that include permission for a given action. This class is very individual and I guess you'll find your way implementing it, because it's not the point here. You could do it by hardcoding, loading from xml or from a database. Also you would have to change/extend it, if you wanted to you action@resource pairs for permission requests.

然后您必须将 main() 方法中的代码更改为:

Then you'd have to change the code in main() method to:

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.");
        }
    }

最后你可以通过这种方式检查访问:

Finally you can check access this way:

    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
    }

希望这会有所帮助.

这篇关于在 WinForms 中对用户进行身份验证(与 ASP.Net 无关)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆