这个问题已解决,是绑定设置的问题,主要还是因为我自己没有深入理解WCF绑定的安全机制。在这篇博客里面我来说说怎么解决的。

下载了Artech的wcf petshop源码(博文链接)并调试运行成功后,打算在其之上增加授权功能,但是遇到了问题。

环境:windows8.1 企业版,VS2012, SQLExpress2008, IIS Express

首先我在原文中求助A大关于通过RoleManager获取角色是否可行,得到了A大的答复可行,于是我就在原来的项目的Common中增加了一个静态类用于获取角色并设置到当前线程的CurrentPrincipal,和还原CurrentPrincipal。代码如下:

 namespace Artech.PetShop.Common
{
/// <summary>
/// 根据当前用户名设置当前线程的Principal的类
/// </summary>
public static class SetThreadPrincipal
{
/// <summary>
/// 用于保存修改之前的Principal
/// </summary>
private static IPrincipal _oldPrincipal; /// <summary>
/// 设置当前线程的Principal,根据ApplicationContext里面的UserName是否存在来判断。
/// 通过Roles来获取对应UserName的角色。并将其设置到当前线程的CurrentPrincipal
/// </summary>
public static void SetThreadPrincipalToCurrentUser()
{
string username = ApplicationContext.Current.UserName;
if (!string.IsNullOrEmpty(username))
{
// 如果用户名为空,则说明不可能有用户信息,那就不用去取角色并放到线程中。
IIdentity identity;
identity = new GenericIdentity(username, Membership.Provider.Name); // TODO: Get Roles
string[] roles = Roles.GetRolesForUser(identity.Name);
IPrincipal principal = new GenericPrincipal(identity, roles); // Place user's principal on the thread
_oldPrincipal = Thread.CurrentPrincipal;
Thread.CurrentPrincipal = principal;
}
else
{// 如果用户名为空,则说明不可能有用户信息,那就不用去取角色并放到线程中。
// 这时候就不用设置oldPrincipal的值了。
_oldPrincipal = null;
}
} /// <summary>
/// 恢复线程的Principal
/// </summary>
public static void ResumeThreadPrincipal()
{
if (_oldPrincipal != null)
Thread.CurrentPrincipal = _oldPrincipal;
}
}
}

从代码中可以看到,如果取到上下文中的用户名之后就可以用户名对应的角色(关于Roles类的使用请微软搜索“角色提供”)。

然后我在ContextReceivalCallContextInitializer类的BeforeInvoke方法和AfterInvoke方法里面增加了对上面类的使用,代码如下:

ContextReceivalCallContextInitializer类在Infrastructure项目的WCF Extensions文件夹下。

     public class ContextReceivalCallContextInitializer : ICallContextInitializer
{
private IPrincipal _oldPrincipal;
#region ICallContextInitializer Members public void AfterInvoke(object correlationState)
{
// 恢复Principal
SetThreadPrincipal.ResumeThreadPrincipal();
} public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message)
{
ApplicationContext.Current = message.Headers.GetHeader<ApplicationContext>(
ApplicationContext.ContextHeaderLocalName,
ApplicationContext.ContextHeaderNamespace);
// 设置Principal
SetThreadPrincipal.SetThreadPrincipalToCurrentUser();
return null;
} #endregion
}

以上代码添加完成后,就可以见证奇迹了。点击启动调试(前提是已经配置成功可以运行)

登录、浏览pet信息、放入购物车略过,不用说了。看下面的图,已经放入购物车。

图:已经放入购物车

下一步,点击结账后,页面调用wcf,会进入ContextReceivalCallContextInitializer类的BeforeInvoke方法:

图:进入BeforeInvoke断点

按下F10,单步执行到return。

图:设置当前Principal结束

从监视窗口可以看到,线程的CurrentPrincipal已经成功设置。用户名和角色都OK的。

图:设置成功

这时,我们按下F5让程序继续进行,来到业务处理的断点处,奇迹就发生了:

图:来到业务处理

查看监视窗口,现成的当前Principal变了!

图:他竟然变成了我的windowsPrincipal!

然后继续执行,来到ContextReceivalCallContextInitializer的AfterInvoke方法时,又变回来了。

图:Principal回来了。

我反复尝试了多次都是这样!抓狂了。

如果我加上权限限制的代码,就会告诉我权限不对。

图:加上限制

再次执行就会在AuditCallHandler的Invoke方法里面看到异常:

图:异常

页面上也会告诉你,访问失败。

我无法理解这个问题到底是为什么,只好找个变通的方法来解决,把设置线程Principal的代码放到了OrderService里面:

        [OperationBehavior(TransactionScopeRequired= true)]
[AuditCallHandler("提交订单")]
public void Submit(Order order)
{
// 设置Principal
SetThreadPrincipal.SetThreadPrincipalToCurrentUser();
this.BusinessComponent.Submit(order);
// 恢复Principal
SetThreadPrincipal.ResumeThreadPrincipal();
}

并将限制代码放到BusinessComponent的Submit里面:

        // 限制权限
[PrincipalPermission(SecurityAction.Demand, Role = "User")]
public void Submit(Order order)
{
this.ValidateInventory(order);
this.DataAccess.Submit(order);
}

这样,再次进行订单结账操作就能成功了。

这个问题到底是为什么呢。我真的百思不得其解啊。

【已解决】谁动了我的CurrentPrincipal?求助我在给Artech的wcf petshop增加授权机制的时候遇到的问题。的更多相关文章

  1. 【已解决】[求助] 求虚拟机防检测代码-VM虚拟机防游戏检测(虚拟机躲避游戏检测工具)

    [已解决][求助] 求虚拟机防检测代码 虚拟机如何躲过游戏等软件的检测,并能用vmware tools: 先把vmtools安装好后!   然后用这代码 monitor_control.restric ...

  2. WPF不明内存泄露已解决,白头发也没了

    原文:WPF不明内存泄露已解决,白头发也没了 在使用OpenExpressApp进行WPF应用开发过程中遇到多个内存泄漏的地方,在上一篇中求助了一个内存泄露问题[WPF不明内存泄露原因,头发都白了几根 ...

  3. Microsoft.Office.Interop.Excel, Version=12.0.0.0版本高于引用的程序集(已解决)

    Microsoft.Office.Interop.Excel, Version=12.0.0.0版本高于引用的程序集(已解决) 论坛里的帮助:http://bbs.csdn.net/topics/39 ...

  4. 使用Notepad++编码编译时报错(已解决?)

    使用Notepad++编码编译时报错(已解决?) 使用Notepad++编码,编译的时候经常会报错,说什么GBK编码啥啥啥~~~但同样的编码用ECLIPSE就没有问题.再有,用记事本把他保存成ANSI ...

  5. 已解决】Sublime中运行带input或raw_input的Python代码出错:EOFError: EOF when reading a line(转)

    [问题] 在折腾: [已解决]Sublime Text 2中运行Python程序出错:The system cannot find the file specified 的过程中,虽然解决了找不到py ...

  6. 【已解决】Android ADT中增大AVD内存后无法启动:emulator failed to allocate memory 8

    [问题] 折腾: [已解决]Android ADT中增大AVD内存后无法启动:emulator failed to allocate memory 8 过程中,增大对应AVD的内存为2G后,结果无法启 ...

  7. 【已解决】BeautifulSoup已经获得了Unicode的Soup但是print出来却是乱码

    [问题] 某人遇到的问题: 关于BeautifulSoup抓取表格及SAE数据库导入的问题(跪求大神帮忙) 简单说就是: 用如下代码: ? 1 2 3 4 5 6 7 import re,urllib ...

  8. Access中出现改变字段“自己主动编号”类型,不能再改回来!(已解决)

    Access中出现改变字段"自己主动编号"类型,不能再改回来! (已解决) 一次把access中的自增字段改成了数值,再改回自增时,提示:在表中输入了数据之后,则不能将不论什么字段 ...

  9. sqlserver,执行生成脚本时“引发类型为“System.OutOfMemoryException”的异常”(已解决)

    sqlserver,执行生成脚本时“引发类型为“System.OutOfMemoryException”的异常”(已解决) 出现此错误主要是因为.sql的脚本文件过大(一般都超过100M)造成内存无法 ...

随机推荐

  1. Linux各个发行版本的介绍, 以及VirtualBox+CentOS的安装步骤

    Linux和Unix系统有哪些主要的发行版本 Unix: (非开源传统商业操作系统) IBM AIX, HP HP-UX, Sun Solaris,等 各家硬件厂商的发行版本, 往往是和自家的硬件设备 ...

  2. JQuery中serialize() 序列化

    更多2014/8/24 来源:jquery学习浏览量:1671 学习标签: serialize 本文导读:在jQuery中,当我们使用ajax时,常常需要拼装input数据以键值对(Key/Value ...

  3. Notes常用事件整理

    ①      ボタンのクリック事件: Sub Click(Source As Button) Dim ws As New NotesUIWorkspace Dim uidoc As NotesUIDo ...

  4. JSWING小工具

    项目中需要一个发送指令到指定服务端,取得设备ID及检测数据的小工具,就利用jswing开发了一个简单小组件,最终效果如下: 代码很简单,具体片段如下: Window.java import java. ...

  5. 1501 二叉树最大宽度和高度 (BFS+树的遍历)

    题目:http://www.wikioi.com/problem/1501/ 给你一颗二叉树,求该数的宽和高, 首先求出树的高,直接进行二叉树遍历,能够得到二叉树的高 然后是得到宽,本人采用的是一层一 ...

  6. d指针在Qt上的应用及实现(d指针能实现二进制兼容)

    Qt为了使其动态库最大程度上实现二进制兼容,引入了d指针的概念.那么为什么d指针能实现二进制兼容呢?为了回答这个问题,首先弄清楚什么是二进制兼容?所谓二进制兼容动态库,指的是一个在老版本库下运行的程序 ...

  7. 如何使用 Android Studio 的 git hub 功能

    How to use GitHub with Android Studio This article will explain how to use GitHub with Android Studi ...

  8. Google浏览器调试js

    1.进入source找到js位置 一般js文件就到js目录下找,tpl中的就到tpl中找. 我这次写在tpl中的,就到list中找,它就把list中的js单独显示出来了. 2.设置断点,进行排错.刷新 ...

  9. 跨浏览器resize事件分析

    resize事件 原生事件分析 window一次resize事件: IE7 触发3次, IE8 触发2次, IE9 触发1次, IE10 触发1次 Chrome 触发1次 FF 触发2次 Opera ...

  10. Android应用开发基础篇(1)-----Button

    Android应用开发基础篇(1)-----Button   一.概述        Button,顾名思义就是按钮的意思,它主要的功能是响应用户按下按钮时的动作. 二.应用      新建一个工程, ...