首页 文章 精选 留言 我的

精选列表

搜索[高度可定制],共10000篇文章
优秀的个人博客,低调大师

三星模仿苹果到新高度:复制了一个乔布斯

【大咖・来了 第7期】10月24日晚8点观看《智能导购对话机器人实践》 在与苹果的对抗中,三星一直扮演“模仿者”、“追随者”的角色。大家都知道三星模仿苹果,但到底模仿到什么地步了?——它在高管中复制出了一个乔布斯。 一直在模仿苹果软件、硬件和营销手段的三星从未“停步不前”,据美国科技博客 CultofMac 报道,三星***模仿苹果的举动是:公司营销副总裁乔治·罗泽尔模仿乔布斯的经典造型和姿势:黑衣,圆镜,摸下巴。 乔治·罗泽尔以往一贯以框形眼镜搭配一套商务西装的造型突然变成了乔布斯经典的黑衣加圆框眼镜。在最近的一张营销形象照中,他更是模仿了《乔布斯自传》封面上乔布斯的经典动作和姿势,唯一“创新”之处就是把乔布斯摸下巴的左手换成了右手。 左为乔布斯,右为乔治·罗泽尔***形象照 而乔治·罗泽尔以前的形象是这样的: Georg Rötzer 三星抓住一切机会模仿苹果,到什么地步了?——方方面面。 模仿苹果的产品。硬件、软件、配件、包装……不胜枚举。 Samsung Galaxy S6 和 iPhone Apple Touch ID 和 Samsung Pay Samsung Galaxy S6 和 iPhone 6 模仿苹果设计总管艾维的语气和腔调制作 S6Edge 的营销视频。 在一个 S6Edge 的营销视频中,三星特意模仿苹果设计主管艾维标志性的“英国腔”,来介绍其工艺设计,被媒体称为“最荒唐搞笑”的营销视频。 模仿苹果的天才吧。 三星不仅尝试设立的零售店和苹果零售店一样,它在百思买设立的迷你柜台,里面也是有经过训练的员工为用户解决平板和手机问题——这不就是苹果的天才吧? 模仿苹果的移动支付。 在苹果基于 NFC 技术的移动支付发布之后,为了快速与苹果支付对抗,三星与 PayPal 达成合作。在部分支持指纹扫描的三星手机上,可以支持 PayPal 的指纹支付。 模仿苹果的“勒索信”。 在 WWDC2015 上,Tim Cook 以一个有关“勒索信”的故事作为开场。他出示了一份Brandon Moss 收到的勒索信,上面提到他要是想要回第 100 个本垒打球的话,就要交换清单上的东西,而上面大多是苹果产品。 在 这之后,克利夫兰队投手 Trevor Bauer 收到了一封觊觎其手上另一颗球的“勒索信”,只是清单要求上的产品全换成了三星。信中写到:你好@Lindor12BC,你的球在我们手里哟。尽管 @indians Bullpen 从 Tim Cook 那里拿到了苹果的产品,但是我们要来一套“三星全家桶”。 如果要继续追溯三星的模仿,简直数也数不过来。但是人们在猜测接下来它要怎么做——三星是不是该让乔治·罗泽尔模仿乔布斯穿着 New Balance 运动鞋在办公室打转了? 【责任编辑: chenqingxiang TEL:(010)68476606】 【责任编辑: chenqingxiang TEL:(010)68476606】

优秀的个人博客,低调大师

2026年WordPress定制开发最佳公司:社交分享功能深度实战指南

很多人以为社交分享功能就是页面上放几个分享按钮,这个认知本身就是踩坑的起点。社交分享的核心,是结构化元数据的精准控制。当用户把链接粘贴到微信或其他社交平台时,平台爬虫会在0.5秒内抓取页面的Open Graph协议(OG标签)和Twitter Card元数据,然后渲染出一张"卡片"。这张卡片的质量,直接决定点击率。OG协议最关键的几个标签:

优秀的个人博客,低调大师

英伟达将为中国市场推出定制版 Blackwell 处理器

根据路透社的独家报道,英伟达公司正计划为中国市场量身设计一款新的旗舰人工智能芯片。 英伟达将与中国浪潮合作推出并销售这款代号为 B20 的芯片。浪潮是英伟达在中国的主要分销合作伙伴之一。 英伟达于今年 3 月发布了 Blackwell 芯片系列,预计将于今年晚些时候开始量产。 该系列中的 B200 芯片拥有强大的性能,能够以比上一代快 30 倍的速度完成聊天机器人响应任务。

优秀的个人博客,低调大师

SOTON私人定制:利用Python进行数据分析(学习pandas)

pandas基础 Pandas借鉴了Numpy绝大部分设计思想,但与Numpy不同的是它更适合于处理表格类、异质性数据,而Numpy则是处理同质的数值数组。Pandas还能无缝与Numpy, SciPy, statsmodels, scikit-learn, matplotlib等包联用,构建了Python数据分析生态系统。 Pandas最主要的两类数据结构:Series, DataFrame,可以对应R语言的vector和data.frame,脑图如下 DataFrame基础功能 学习笔记如下: pandas的索引对象用于存放轴标签和其他元数据信息,索引对象不可修改,目的是安全的将该索对象传递给其他数据结构。、 reindex并不是修改原来的索引,而会在原来的基础上增加新的索引。 对DataFrame或Series修改形状,删除数据的操作默认返回新的数据结构。可以用inplace=True避免返回新的数据,不过这也通常会摧毁原来的数据。 明确loc和iloc的区别。如果你创建Series或DataFrame的index存在整数,那么细细体会下obj[:1],obj.loc[:1],obj.iloc[:1] 排序和排名(sort and rank)看起来差不多,毕竟排名先要排序,排序之后分配位置,注意重复值的处理方法。 最重要的部分是描述性统计分析部分,这部分依赖于现有的函数 方法 说明 desribe 列计算汇总,列出四分位数等信息 max,min 最大值和最小值 idxmin, idxmax 最大值和最小值的索引位置 quantile 分位数 sum 求和 mean 平均数 median 中位数 mad 根据平均值计算平均离差 var 方差 std 标准差 skew 样本值的偏度(三阶矩) kurt 样本值的丰度(四阶矩) cumsum 样本的累积和 cummin,cummax 累计最大值和最小值 cumprod 累积积 diff 计算一阶差分 pct_change 计算百分比变化 官方文档的教程 此处翻译官方文档的10 Minutes to pandas,有任何问题欢迎留言交流。 本文主要简单的介绍了pandas,让新手能够了解pandas的一些功能,你可以在Cookbook中看到更详尽的内容。 在执行以下的操作前,请先导入相应的库: import pandas as pd import numpy as np import matplotlib.pyplot as plt 创建对象 通过传入一个包含多个值的列表创建一个Series对象,pands会默认为其创建一个整数索引。 s = pd.Series([1,3,5,np.nan,6,8]) 通过传入一个含有日期索引和标签列的numpy矩阵创建一个DataFrame对象 dates = pd.date_range('20130101', periods=6) df = pd.DataFrame(np.random.randn(6,4), index=dates, columns=list('ABCD')) 通过传递一个字典创建一个DataFrame df2 = pd.DataFrame({ 'A' : 1., 'B' : pd.Timestamp('20130102'), 'C' : pd.Series(1,index=list(range(4)),dtype='float32'), 'D' : np.array([3] * 4,dtype='int32'), 'E' : pd.Categorical(["test","train","test","train"]), 'F' : 'foo' }) DataFrame和Series具有许多属性,可以利用IPyton的自动补全功能查看: df2.<TAB> df2.A df2.boxplot df2.abs df2.C df2.add df2.clip df2.add_prefix df2.clip_lower df2.add_suffix df2.clip_upper df2.align df2.columns df2.all df2.combine df2.any df2.combineAdd df2.append df2.combine_first df2.apply df2.combineMult df2.applymap df2.compound df2.as_blocks df2.consolidate df2.asfreq df2.convert_objects df2.as_matrix df2.copy df2.astype df2.corr df2.at df2.corrwith df2.at_time df2.count df2.axes df2.cov df2.B df2.cummax df2.between_time df2.cummin df2.bfill df2.cumprod df2.blocks df2.cumsum df2.bool df2.D 查看数据 假设你有上w条数据,全部显示屏幕要爆炸,那么最好的方法就是只看前面几条或后面几条,验证创建的数据模型是否正确。 df.head() df.tail(3) 显示索引,列,和底层numpy的数据 df.index df.columns df.values 对数据进行快速的统计汇总,这里汇总的数据的数据类型是Int,float这类 df.describe() 统计性描述 数据转置 df.T 按轴排序(ascending:升序) df.sort_index(axis=1,ascending=False) 按值排序,类似于excel的排序 df.sort_value(by='B') 筛选 起步 选择单列,这会产生一个Series,等同于df.A df['A'] 使用[]对行切片 df[0:3] 使用标签筛选 使用标签获取切片数据 df.loc[date[0]] 使用标签获取多轴数据 df.loc[:,['A','B']] 显示标签切片,包括两个端点 df.loc['20130102':'20130104',['A','B']] 获取标量值 df.loc[dates[0],'A'] 快速获取标量值(与上一个作用相同) df.at[dates[0],'A'] 通过位置筛选 通过所传递整数的位置选择 df.iloc[3] 通过整数切片 df.iloc[3:5,2:3] 通过整数位地址的列表 df.iloc[[1,2,4],[0,2]] 对行/列切片 df.iloc[1:3,:] df.ilo[:,1,3] 获得特定值 df.iloc[1,1] 快速获取标量(与上一个结果相同) df.iat[1,2] 布尔索引 使用单个列的值来选择数据。 df[df.A > 0] 使用isin()方法进行过滤,下面实现的是筛选E中'tw'和'four'两列 df2 = df.copy() df2['E'] = ['one', 'one','two','three','four','three'] df2[df2['E'].isin(['two','four'])] 赋值 为新列赋值,该列能够通过标签自动匹配原先的数据 s1 = pd.Series([1,2,3,4,5,6], index=pd.date_range('20130102', periods=6)) df['F']=s1 通过标签赋值 df.at[dates[0],'A'] = 0 通过位置赋值 df.iat[0,1] = 0 通过传入一个numy矩阵赋值 df.iat[0,1] = 0 缺失值 pandas优先使用np.nan表示缺失值。缺失值默认在计算中排除。 重建索引允许您更改/添加/删除索引上的指定轴。这将返回数据的副本。 df1 = df.reindex(index=dates[0:4], columns=list(df.columns) + ['E']) df1.loc[dates[0]:dates[1],'E'] = 1 删除任何包含缺失值的行 df1.dropna(how='any') 填充缺失值 df1.fillna(value=5) 判断是否为缺失值并返回布尔值 pd.isnull(df1) 操作 统计 描述统计 df.mean() 、 df.mean(1) apply 将函数应用到数据上 df.apply(np.cumsum) df.apply(lambda x: x.max() - x.min()) 直方图 s = pd.Series(np.random.randint(0, 7, size=10)) s.value_counts() 合并 pandas提供了多种方法方便的合并Series, DataFrame,和Panel对象 Concat 使用concat()串联不同pandas对象 df = pd.DataFrame(np.random.randn(10, 4)) pieces = [df[:3], df[3:7], df[7:]] pd.concat(pieces) JOIN SQL风格的合并 left = pd.DataFrame({'key': ['foo', 'foo'], 'lval': [1, 2]}) right = pd.DataFrame({'key': ['foo', 'foo'], 'rval': [4, 5]}) pd.merge(left, right, on='key') Append 在dataframe中添加行 df = pd.DataFrame(np.random.randn(8, 4), columns=['A','B','C','D']) s = df.iloc[3] df.append(s, ignore_index=True) 分组:Groupin 我们所说'group by'是指以下步骤中的一个或多个处理: 将数据基于一些标准分成多个组 分别应用函数到每个组 ** 组合**结果成数据结构 df = pd.DataFrame({'A' : ['foo', 'bar', 'foo', 'bar', 'foo', 'bar', 'foo', 'foo'], 'B' : ['one', 'one', 'two', 'three', 'two', 'two', 'one', 'three'], 'C' : np.random.randn(8), 'D' : np.random.randn(8)}) 分组并对所分的组使用sum函数 df.groupby('A').sum() 通过多列组合形成了一个层次指数,我们再应用函数 df.groupby(['A','B']).sum() 重塑:Reshaping 堆:stack tuples = list(zip(*[['bar', 'bar', 'baz', 'baz', ....: 'foo', 'foo', 'qux', 'qux'], ....: ['one', 'two', 'one', 'two', ....: 'one', 'two', 'one', 'two']])) index = pd.MultiIndex.from_tuples(tuples, names=['first', 'second']) df = pd.DataFrame(np.random.randn(8, 2), index=index, columns=['A', 'B']) df2 = df[:4] df2 stack stack()方法“压缩”了DataFrame的层次。 stacked = df2.stack() 数据透视表: Pivot Tables df = pd.DataFrame({'A' : ['one', 'one', 'two', 'three'] * 3, .....: 'B' : ['A', 'B', 'C'] * 4, .....: 'C' : ['foo', 'foo', 'foo', 'bar', 'bar', 'bar'] * 2, .....: 'D' : np.random.randn(12), .....: 'E' : np.random.randn(12)}) .....: 我们可以很方便的从这些数据构造数据透视表: pd.pivot_table(df, values='D', index=['A', 'B'], columns=['C']) 时间序列<small>Time Series</small> pandas拥有许多简单,功能强大,高效的功能可以在波动期间执行采样操作(例如,数据转换成二5每分钟的数据)。常见于,但不限于,财务应用 等。 rng = pd.date_range('1/1/2012', periods=100, freq='S') ts = pd.Series(np.random.randint(0, 500, len(rng)), index=rng) ts.resample('5Min').sum() 作图: Plotting 画图建议在网页版的jupyter notebook进行操作,减少不必要的烦恼。 Series画图方法 ts = pd.Series(np.random.randn(1000), index=pd.date_range('1/1/2000', periods=1000)) ts = ts.cumsum() ts.plot() DataFrame的画图方法 df = pd.DataFrame(np.random.randn(1000, 4), index=ts.index, .....: columns=['A', 'B', 'C', 'D']) df = df.cumsum() plt.figure(); df.plot(); plt.legend(loc='best')

优秀的个人博客,低调大师

SOTON私人定制:利用Python进行数据分析(学习Numpy)

Numpy:数组和矢量计算包 对于大部分数据分析工具,作者主要关注如下功能 快速矢量化矩阵运算,用于数据规整化和清理,筛选,过滤,格式转换等 常用矩阵算法,排序、唯一值和集合运算 高效描述性统计和聚合分析 数据对准,和关联数据操作,从而便于合并不同类型的数据集 避免使用if-elif-else和loops进行逻辑判断 分组数据操作 而Numpy的部分功能如下: ndarray, 一个具有矢量算术运算和复杂广播能力的快速且节省空间的多维数组 用于对整组数据进行快速运算的标准数学函数(无需编写循环函数) 用于读写磁盘数据的工具以及用于操作内存映射文件的工具 线性代数, 随机数生成以及傅里叶变换功能 用于继承由C, C++, Fortran等语言编写的代码的工具 尽管Numpy并不满足作者的所有需求,但是熟练掌握的Numpy的面向数组编程(arrary-oriented programming),以数组的方式思考对成为Python数据分析科学家至关重要。 ndarray: 多维数组对象,高效的源头 Python低效的原因有一个就是“在Python里面一切都是对象”,所以它不存在基本数据类型,每次运算都要进行类型判断会降低了效率。而Numpy将数据存放在连续的内存块中,Numpy处理这部分内存块就不需要进行类型检查了。并且Numpy的矢量化运算,避免了Python原生for循环,效率再次提高。 举例说明: import numpy as np raw_arr = list(range(10000)) np_arr = np.arange(10000) %%timeit raw_arr2 = [x * 2 for x in raw_arr] # 时间是349 us += 2.83 us %%timeit np_arr2 = np_arr * 2 # 时间是6.94 us += 33.5 ns 速度相差了50倍。 注:Java作为一门面向对象语言,保留了8种基本数据类型(不包括字符串)。 ndarrays的思维导图: ndarrays 对应的学习笔记 关于数据类型, 一般情况下我们没必要对它太过于关注。但是对于大数据集,则需要自己主动声明。因为数据类型(dtype)负责将一块内存解释为特定数据类型,即直接映射到相应的机器表示。在R语言中有一类类型转换函数(例如as.numeric)对数组内的数据类型进行转换,在Numpy则通过dtype. 矢量化运算是Numpy用C语言编写,在C语言层面是也是循环。这也是为什么一个数组内的数据类型要一致。 我曾经在Python和R的异同(一)里谈到原生Python要想实现R语言的矢量化就要使用列表推导式, 而目前可以用numpy带来的矢量化运算属性了。 切片Numpy和原生的Python都有切片的功能, 所谓的切片(slicing) 就是从已有的数组中返回选定的元素,而索引(index)提供指向存储在数组指定位置的数据值的指针。值得注意的是,Python以0为基。和原生Python切片不同,Numpy切片得到只是原始数据的视图(view),也就是浅复制,即你对Numpy切片后的数据进行操作,会影响到原始数据。原因就是Numpy的目的是处理大数据,对大规模的数据进行实际复制会消耗不必要的性能和内存。 numpy的索引操作和R语言几乎一模一样,分为切片索引,布尔值索引,花式索引。这些都在《R语言实战》基本数据管理章节中的数据集选取子集里面提及。 花式索引以及布尔值索引和切片索引不同, 前者将数据复制到新的数组中,而后者是原始数据的视图。 可能原因是前两者的得到数据在原始数据中位置不是整块存放。 转置(transpose)是数据重塑的一种特殊形式,返回的是原始数据的视图。数组不仅有transpose方法,还有一个T属性(是np.swapaxes的特殊形式), 这两者在二维数组上是相同的。但是在更高维度上,T属性依旧还是轴对换,transpose方法还需要提供轴编号组成的元组,这个真的是非常难以理解。 更详细的内容见之前写的Numpy:数组合矢量计算 Numpy高级,常用的矢量化运算函数 Numpy提供了大量通用函数(UNIVERSAL FUNCTIONS, UFUNC)进行矢量化运算的函数 常用函数 基本操作 import numpy as np a=np.array([0,1,2,3,4]);a #一维数组 array([0, 1, 2, 3, 4]) b = np.array([[0,1,2],[3,4,5]]);b #二维数组 array([[0, 1, 2], [3, 4, 5]]) c=np.array([[[1],[2],[3],[4]]]); c #三维数组 array([[[1], [2], [3], [4]]]) c.shape (1, 4, 1) 产生数组的方法 均匀分布 np.arange(10) array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) np.arange(1,9,2) array([1, 3, 5, 7]) 等间距数组 np.linspace(0,1,6,endpoint=False) array([ 0. , 0.16666667, 0.33333333, 0.5 , 0.66666667, 0.83333333]) 常用矩阵 np.ones((3,3)) #全1矩阵 array([[ 1., 1., 1.], [ 1., 1., 1.], [ 1., 1., 1.]]) np.zeros((4,4)) #全0矩阵 array([[ 0., 0., 0., 0.], [ 0., 0., 0., 0.], [ 0., 0., 0., 0.], [ 0., 0., 0., 0.]]) np.eye(5) #对角矩阵 array([[ 1., 0., 0., 0., 0.], [ 0., 1., 0., 0., 0.], [ 0., 0., 1., 0., 0.], [ 0., 0., 0., 1., 0.], [ 0., 0., 0., 0., 1.]]) np.diag(np.array([1,2,3,4])) #对角矩阵 array([[1, 0, 0, 0], [0, 2, 0, 0], [0, 0, 3, 0], [0, 0, 0, 4]]) np.random.rand(4) #[0,1]均匀分布 array([ 0.80734513, 0.03497501, 0.15490748, 0.35552225]) np.random.randn(4) #符合高斯分布 array([-1.64777274, 0.17147949, -0.61706612, -0.78031714]) 基本数据类型 a = np.array([1,2,3,4,5]) a.dtype #查看数据类型 dtype('int32') b = np.arange(5,dtype=int) #声明数据类型 b.dtype dtype('int32') 其他数据类型 complex128, bool, S7, int32, int64, unit32, unit64 可视化基础 %matplotlib inline import matplotlib.pyplot as plt plt.plot(np.arange(10)) # 直线图 plt.show 一维图 x = np.linspace(1,4,2) y = np.linspace(5,25,2) plt.plot(x,y,'-r') 二维矩阵图 image = np.random.rand(30,30) plt.imshow(image,cmap=plt.cm.hot) plt.colorbar() 切片和索引 a = np.diag(np.arange(3));a array([[0, 0, 0], [0, 1, 0], [0, 0, 2]]) print(a[1,2],a[1:2]) 0 [[0 1 0]] a[1,2]=2;a array([[0, 0, 0], [0, 1, 2], [0, 0, 2]]) 注:切片是原先矩阵上创建的视图,与原先矩阵在内存上的同一位置,使用capy可以强制开一个内存 a = np.arange(10) b = a[::2] np.may_share_memory(a,b) True a = np.arange(10) c = a[::2].copy() np.may_share_memory(a,c) False 索引和切片 花式索引 np.random.seed(3) a = np.random.random_integers(0,20,15);a array([10, 3, 8, 0, 19, 10, 11, 9, 10, 6, 0, 20, 12, 7, 14]) # 使用布尔mask mask = (a % 3 ==0) extract_from_a = a[mask];extract_from_a array([-1, -1, -1, -1, -1, -1]) #使用整数矩阵索引 a = np.arange(0,100,10) a[[2,3,4,2,4]] array([20, 30, 40, 20, 40]) 花式索引 数组数值运算 逐个元素运算 a = np.array([1,2,3,4]) # 加一个矢量 a+1 array([2, 3, 4, 5]) b = np.ones(4)+1;b array([ 2., 2., 2., 2.]) print(b-a,b*a) #数组之间运算 [ 1. 0. -1. -2.] [ 2. 4. 6. 8.] 其他运算 a = np.random.rand(1,3) b = np.random.rand(1,3) print(a>b,a==b) 逐个元素比较 [[False False True]] [[False False False]] np.array_equal(a,b) # 整体比较 False 逻辑运算 a = np.array([1, 1, 0, 0], dtype=bool) b = np.array([1, 0, 1, 0], dtype=bool) np.logical_or(a, b) np.logical_and(a, b) array([ True, False, False, False], dtype=bool) 三角函数 a = np.arange(5) print(np.sin(a),np.log(a),np.exp(a)) [ 0. 0.84147098 0.90929743 0.14112001 -0.7568025 ] [ -inf 0. 0.69314718 1.09861229 1.38629436] [ 1. 2.71828183 7.3890561 20.08553692 54.59815003] d:\Anaconda3\lib\site-packages\ipykernel\__main__.py:1: RuntimeWarning: divide by zero encountered in log if __name__ == '__main__': 转置 a.T array([0, 1, 2, 3, 4]) 基础归纳 求和 x = np.array([1,2,3,4,5]) print(np.sum(x),x.sum()) 15 15 行和列 x = np.array([[1,1],[2,2]]) x.sum(axis=1),x.sum(axis=0) (array([2, 4]), array([3, 3])) 求极值 x = np.arange(10) print(x.min(),x.argmin()) # 最小值和最小值的索引 0 0 print(x.max(),x.argmax()) # 最大值和最大值的索引 9 9 逻辑运算 np.all([True,True,False,False]) #全部为真才是真 False np.any([True,False,True]) #有一个为真就是真 True a = np.zeros((100,100)) np.any(a!=0) False 基本统计方法 x = np.array([1, 2, 3, 1]) y = np.array([[1, 2, 3], [5, 6, 1]]) x.mean() np.median(x) np.median(y, axis=-1) # last axis x.std() # full population standard dev. 0.82915619758884995

优秀的个人博客,低调大师

ASP.NET2.0应用中定制安全凭证之实践篇

一、方案架构 本方案架构很简单——它用一个Web服务来包装ASP.NET 2.0提供者并且为远程客户暴露该凭证管理,你甚至还能在该架构中加上一些失去的功能。然后,在提供一个丰富的用户接口和全面凭证管理经验的同时,使用一个Windows表单应用程序来消费该Web服务。该Web服务配置文件将包含特定于该凭证存储的指令。然而,这的确意味着所有由该Web服务管理的应用程序都将可以共享这些指令。 尽管你能够从头到尾地构建该Web服务,也就是说,首先用静态方法Roles和Membership来包装它们并定义该Web服务,我却更喜欢一种契约驱动的方法:首先设计执行各种操作的最好接口将是什么,并且直到需要时才考虑怎样实现它们。这样做可以确保由Web服务暴露的接口支持所有要求的管理功能并且还将减少该客户应用程序与任何实现细节(例如包装提供者)之间的耦合。 ASP.NET 2.0的一个更好的特点是它支持Web服务接口,你可以定义并且让该Web服务暴露逻辑接口,就象类的表现一样。为此,你需要用WebServiceBinding属性修饰你的接口并且经由WebMethod属性来暴露单个的接口方法。然后,你将有一个派生于这个接口的类并实现该接口,而且编译器将要求你支持该接口的所有方法。 为了管理和交互于凭证存储和Web服务配置,我定义了5个接口-IApplicationManager,IMembershipManager,IPasswordManager,IroleManager和IUserManager。 (一) IApplicationManager 该IApplicationManager接口显示于所附源码中的列表2,允许管理员删除一指定的应用程序-也就是说,从数据库中删除所有到它的参考并且删除它的所有用户和角色。IApplicationManager允许从存储中删除所有的应用程序,并且它能返回在该存储中的所有应用程序的一个列表。注意,这个接口作为一个内部的接口被定义-public或internal可见性修饰词对Web服务接口都是无意义的。该接口上的每个方法用WebMethod属性加以修饰并有一个该方法的简短描述。此外,存取凭证存储的所有方法都被设置为使用事务处理。这样以来,两种操作-如删除一应用程序和创建一用户将在彼此完全隔离的情况下执行,从而保证了如删除所有用户等复杂操作的原子性。.NET 2.0中的Web服务只能启动一个新事务,而且它是由WebMethod属性的TransactionOption属性来控制的。最后一点是把WebServiceBinding属性应用于接口上。这就指定该接口是一个客户和服务都能绑定到的Web服务接口。为了把该接口以一个WSDL契约方式暴露给外界,你需要使用一个shim类。这个shim类的设计是必要的,因为你不能把一个接口作为一Web服务暴露,而且你也不能在其上应用WebService属性。这个shim类还将经由WebService属性为该接口命名空间定义。下面的代码显示了IApplicationManagerShim抽象类的定义。 [WebService(Name="IApplicationManager", Namespace="http://CredentialsServices", Description="IApplicationManager is used to manage applications. This web service is only the definition of the interface. You cannot invoke method calls on it.")] abstract class IApplicationManagerShim : IApplicationManager{ public abstract void DeleteApplication(string application); public abstract string[] GetApplications(); public abstract void DeleteAllApplications(); } 因为IApplicationManagerShim是一个类,所以你可以把它暴露为一个Web服务。因为它是一抽象类且所有方法被定义为抽象方法,所以不需要(也不能)实现任何方法。为了使其看起来就象该接口,IapplicationManagerShim把WebService属性的属性名设置为IApplicationManager(代替缺省的类名)。现在,你可以使用IApplicationManager.asmx文件来暴露该接口。 <%@ WebService Language="C#" CodeBehind="~/App_Code/IApplicationManagerShim.cs" Class="IApplicationManagerShim"%> 现在,如果你浏览到IApplicationManager.asmx页面,你就会看到该接口定义。你可以使用WSDL.exe的serverInterface选项来把接口定义输入到客户端或任何其它想绑定到该接口定义上的服务。 (二) IMembershipManager IMembershipManager接口(见所附源码中的列表3)允许你管理用户帐户的所有方面-创建和删除用户帐户,更新用户帐户,检索用户帐户细节以及检索在一应用程序中的所有用户。 (三) IRoleManager IRoleManager接口允许你管理逻辑角色的所有方面-创建和删除角色,从角色中增加和删除用户以及检索在一应用程序中的所有角色。 [WebServiceBinding("IRoleManager")] interface IRoleManager{ [WebMethod(...)] void CreateRole(string application,string role); [WebMethod(...)] bool DeleteRole(string application,string role,bool throwOnPopulatedRole); [WebMethod(...)] void AddUserToRole(string application,string userName, string role); [WebMethod(...)] void DeleteAllRoles(string application,bool throwOnPopulatedRole); [WebMethod(...)] string[] GetAllRoles(string application); [WebMethod(...)] string[] GetRolesForUser(string application,string userName); [WebMethod(...)] string[] GetUsersInRole(string application, string role); [WebMethod(...)] void RemoveUserFromRole(string application,string userName, string roleName); //更多成员 } (四) IPasswordManager 这个IPasswordManager接口主要提供与应用程序口令策略相关的只读信息。 [WebServiceBinding("IPasswordManager")] interface IPasswordManager{ [WebMethod(...)] bool EnablePasswordReset(string application); [WebMethod(...)] bool EnablePasswordRetrieval(string application); [WebMethod(...)] string GeneratePassword(string application,int length, int numberOfNonAlphanumericCharacters); [WebMethod(...)] bool RequiresQuestionAndAnswer(string application); [WebMethod(...)] string ResetPassword(string application,string userName); [WebMethod(...)] string GetPassword(string application,string userName,string passwordAnswer); [WebMethod(...)] void ChangePassword(string application,string userName,string newPassword); //更多成员 } 典型地,该策略存储在应用程序的配置文件中。该策略包括是否启动口令重置和检索,口令强度和口令回答策略等。你也可以使用IpasswordManager来生成一相应于该口令强度策略的新口令。另外,IpasswordManager可用于重置、改变或检索一指定用户的口令。 (五) IUserManager IUserManager接口允许校验用户凭证,检索角色身份以及获取指定用户是其成员之一的所有角色。该接口用于测试和分析目的。 [WebServiceBinding("IUserManager")] public interface IUserManager{ [WebMethod(...)] bool Authenticate(string applicationName,string userName, string password); [WebMethod(...)] bool IsInRole(string applicationName,string userName, string role); [WebMethod(...)] string[] GetRoles(string applicationName,string userName); } 二、AspNetSqlProviderService Web服务 显示在所附源码中的列表4中的AspNetSqlProviderService类实现了五个Web接口。其过程就象实现任何其它接口一样-你可以隐式或显式地派生并实现方法(见列表4)。我是通过把这些实现简单地代理到提供者的适当的方法来实现该Web接口上的大多数方法的。在每一次使用角色或身份之前,你必须为之作好准备-通过设置要使用的应用程序名。例如,为了实现IRoleManager.CreateRole(),你将需要建立:void IRoleManager.CreateRole(string application,string role){ Roles.ApplicationName = application; Roles.CreateRole(role); } 其中的一些方法在调用该提供者前后还要求一点工作。例如,如果启动口令检索,你只能检索用户口令,而AspNetSqlProviderService则用于判定它。string IPasswordManager.GetPassword(string application,string userName, string passwordAnswer){ Membership.ApplicationName = application; Debug.Assert(Membership.EnablePasswordRetrieval); MembershipUser membershipUser =Membership.GetUser(userName); return membershipUser.GetPassword(passwordAnswer); } 然而,还有一些方法并没有得到提供者的直接支持。有两种可能的解决办法-第一种是尝试并使用提供者的其它方法来完成所希望的操作。第二种是直接执行aspnetdb数据库。两种方法都存在利弊。例如,可以考虑实现MembershipManager.DeleteAllUsers()方法。你可以对该应用程序中的每个用户调用身份提供者的DeleteUser()方法,如列表4所示。首先你要调用IMembershipManager.GetAllUsers()方法来得到应用程序中的所有用户。这就是你通过实现该接口的类来使用该接口方法的显式实现方式。然后,你可以定义一个匿名方法来删除用户,把该匿名方法赋值到一个Action<string>代理,并且使用Array类的静态方法ForEach<T>()删除每个用户。public delegate void Action public abstract class Array : ... { public static void ForEach<T>(T[] array,Action<T> action); }>(t> 第一种方法的优点是任何与删除一个用户相关的内部活动(如也删除所有的角色身份)仍旧被执行。其不足是,你需要对该数据库做更多的调用。 正如刚才提到的,第二种方法是直接对aspnetdb数据库编程。当提供者没有提供任何方式来完成此任务时,这是最有用的。例如,提供者并不支持删除一应用程序,更不说删除所有的应用程序了。尽管你可以编写一个存储过程来做这件事情,但我的另一个目标是不动用aspnetdb,而是使用原始SQL命令来实现IApplicationManager.DeleteApplication()和IApplicationManager.DeleteAllApplications()。我已用一个AspNetDbTablesAdapter助理类(在此没有显示)包装了这些命令。直接访问数据库的优点是你仅执行一个命令;不足之处是,如果要改变数据库模式,你将需要更改你的代码。假定如删除所有的用户或一应用程序等操作是一般不涉及的并且超级用户的数目经常很小,那么我想最好尽可能让AspNetSqlProviderService使用ASP.NET 2.0提供者。 (一) 设置服务 由AspNetSqlProviderService Web服务使用的Web.Config文件中的设置影响它管理的所有应用程序。特别地,如口令策略这样的设置适用于所有的应用程序。该服务使用默认提供者(SQL SERVER),因此如果缺省的连接字符串(在文件machine.config中维护)已经足够的话,就不需要指定一个提供者甚至一个连接字符串。如果你需要一个不同的连接字符串,你需要包括一个connectionStrings标签(见所附源码中的列表5)。另外,为了使用Roles类,你必须通过下列指令来启动基于角色的安全。<roleManager enabled="true" /> (二) 保护服务 尽管其凭证由AspNetSqlProviderService Web服务来管理的应用程序可能是基于互联网或基于内部网的,但是服务本身是被设计由一个管理员通过本地内部网来存取的。你应该认证和授权到该服务的调用。另外,你还应该通过加密通讯来提供秘密服务。这是要求的,因为该服务要处理如用户名和口令等敏感信息。保证秘密的最容易的方法是使用HTTPS。AspNetSqlProviderService在它的构造器中经由静态VerifySecureConnection()助理方法来进行验证是否使用了一个安全连接。VerifySecureConnection()使用当前请求的IsSecureConnection属性。为了支持开发或该服务的其它类型的非生产性发布,VerifySecureConnection()方法用Conditional属性加以修饰。只有定义编译符号HTTPS时该方法才会起作用。关于认证该服务的用户,既然Web服务是一本地内部网服务,那么使用Windows认证就不会有任何错误了。我选择了使用集成的Windows认证-这将省去了用户必须明确地登录的麻烦。集成的认证的另外一个优点是,它用一种专利方式来散列化发送过去的凭证。 为了配置集成的Windows认证,转到在IIS下的AspNetSqlProviderService Web服务属性,选择目录安全选项卡,并且点击"Edit…"按钮。不选择"Anonymous access"复选框并且保证选中"Integrated Windows authentication"复选框。AspNetSqlProviderService类被配置以要求认证(见列表4)-它使用PrincipalPermission属性并把被认证的属性设计为true。[PrincipalPermission(SecurityAction.Demand,...,Authenticated=true)] 一旦调用者通过IIS被认证,该服务缺省地将在IIS中以配置的身份仍旧运行。我想以调用者身份运行该服务。为此,Web.Config文件(见列表5)包含了一个identity标签-它把impersonate属性设置为true。<identity impersonate="true"/> 然后,你需要使用SQL SERVER管理工具来允许Web服务的调用者从aspnetdb数据库中进行读和写。 保护该Web服务的另一个重要地方是授权。我想要验证只有Windows超级用户组的成员才能存取这一服务。为此,AspNetSqlProviderService类上的PrincipalPermission属性要求只有超级用户角色的成员才被允许使用该服务。[PrincipalPermission(SecurityAction.Demand, Role = "Administrators",...)] 你可以用任何其它组(该服务的实际用户应该是其中的一员)来替换"Administrators"。 PrincipalPermission属性使用依附于该线程的安全负责人(principal)来验证调用者是否的确是指定角色中的一员。在依赖于NT组(如超级用户)时,这将强制你使用一个WindowsPrincipal的实例。public class WindowsPrincipal : IPrincipal{ public WindowsPrincipal(WindowsIdentity ntIdentity); public virtual bool IsInRole(string role); //其它成员部分 } 问题在于,为了使用Roles类,AspNetSqlProviderService Web.Config文件必须启动基于角色的安全策略。<roleManager enabled="true" /> 这反过来使得ASP.NET 2.0把一不同的principal依附到HttpContext和线程上,当然还有RolePrincipal类。public sealed class RolePrincipal : IPrincipal{...} 在NT超级用户角色中试图使用RolePrincipal和过分要求的身份将会失败,因为它将存取aspnetdb而不是Windows组来查找它。为补偿这一点,你必须手工地交换这些负责人并且在每次请求时把WindowsPrincipal的一个实例依附到该线程上。为此,最容易的办法是把一个Global.asax文件添加到该Web服务工程-通过指定在Global.cs文件中的Global类为类后的代码。<%@ Application Language="C#" CodeBehind ="Global.cs" Inherits = "Global"%> 这个Global类为应用程序授权请求提供一个处理器。public class Global : HttpApplication{ protected void Application_AuthorizeRequest(object sender, EventArgs e){ if(HttpContext.Current.User.Identity.IsAuthenticated){ WindowsIdentity identity = HttpContext.Current.User.Identity as WindowsIdentity; Debug.Assert(identity != null); WindowsPrincipal principal; principal = new WindowsPrincipal(identity); Thread.CurrentPrincipal = principal; } } } 如果调用者被认证,那么你需要实例化一新的WindowsPrincipal对象并且把它依附于当前线程。WindowsPrincipal构造器需要一个WindowsIdentity的实例。幸好,因为该服务正在使用Windows集成的认证,在成功认证后,与当前HTTP上下文相联系的身份已经是WindowsIdentity类型了,因此你可以只取得这个实例。 三、凭证管理器应用程序 本文相应的源代码包含了这个凭证管理器应用程序-一个具有丰富的用户接口的Windows表单应用程序,它使用在上一步描述的Web服务接口来为任何数目的应用程序管理安全凭证存储。 该应用程序导入五个Web接口定义,并且它独占地使用那些接口。该应用程序有一个称为AspNetSqlProviderService的Web服务代理类-它用于定位该服务。你需要从导入的接口手工地把它添加到该服务上。 图4.Applications选项卡:这个选项卡让你选择要配置的应用程序。 partial class AspNetSqlProviderService : SoapHttpClientProtocol,IMembershipManager, IUserManager,IPasswordManager, IApplicationManager,IRoleManager { public AspNetSqlProviderService (){ Credentials = CredentialCache.DefaultCredentials; Url = Settings.Default.AspNetSqlProviderService ; } //其它的执行 } 为了支持集成的Windows认证,这个代理类的构造器使用CredentialCache的静态属性DefaultCredentials设置凭证属性-它只是简单地读取当前线程的安全标志。另外,这个构造器还使用设计器生成的Settings类从应用程序配置类中读取Web服务地址。 图5.Users选项卡:该选项卡列出在选定的应用程序中的所有用户。 这个应用程序的使用相当直观,所以我只介绍一下主要屏幕和选项。Applications选项卡(见图4)允许你选择要配置的应用程序。 在此,选择一应用程序将影响所有其它的选项卡。你可以创建和删除一个应用程序或删除所有应用程序。Users选项卡列举出在选择的应用程序中的所有用户。 你可以创建或删除一用户。如果你删除一用户但是不选择"All Data"复选框的话,它将删除该用户但是维持它的角色身份信息。你可以更新一用户帐户或删除所有用户。根据从AspNetSqlProviderService Web服务返回的口令策略的不同,你能够或不能够改变或重置口令,而且可以或不可以需要回答该口令。在Users选项卡的按钮和它所显示的对话框也相应地启动或禁止。 在Users选项卡的右边是统计信息,如当前用户的在线数。Roles选项卡允许你把角色添加到应用程序。 图6:Roles选项卡:这个选项卡让你把角色添加到应用程序。 当删除一个角色时,如果你选择了"Fail if populated"复选框,那么如果它有任何成员的话,就不会让你删掉该角色。左边的列表视图显示在该应用程序中的所有用户。你可以从一个角色添加或删除一用户,或从所有角色中删除一用户。在底部,"Users in role"列表框显示了在上面选定的角色中的所有用户,而"Roles for User"列表框显示了在上面选定的用户中的所有角色(见《 理论篇》之图3)。 Passwords选项卡显示在图7中,它列出已配置的口令策略并且允许你生成一与指定的口令强度策略相匹配的新口令。 图7.Passwords选项卡:你可以使用这个选项卡生成一口令。图8.Credentials Service选项卡:使用这个选项卡来选择使用的Web服务。 该选项卡让你选择要使用的Web服务。一旦启动,凭证管理器应用程序即从应用程序配置文件中读取这个地址。这个选项卡显示被选择的Web服务。如果地址是无效的,也就是说,该服务不支持所有要求的功能,那么在应用程序中的所有控件都将为空且是禁止的。你可以提供一个不同的地址,而下面的Web浏览器控件将会显示这一服务。然而,如果该服务支持要求的Web方法(一有效的Web服务)的话,你可以只选择一个Web服务地址(通过点击Select按钮)。如果该服务是无效的,那么将禁止Select按钮。 不幸的是,在.NET 2.0中没有提供校验某服务是否支持一特别绑定或Web接口的内置支持,因此我不得不手工实现。所附源码中的列表6显示出RefreshSelectButton()和ContainsInterface()助理方法。RefreshSelectButton()首先禁止Select按钮和相匹配的菜单项。然后,验证指定的地址是一个.NET Web服务的地址。然后,它存取显示在Web浏览器控件中的页面的内容并且验证它包含支持所有的接口的方法。为此,它要调用ContainsInterface()方法并把页面的内容和要验证的接口类型提供给它。ContainsInterface()验证该类型是一个接口的类型并且获得一个MethodInfo对象数组-标记在该接口上的每个方法。然后,它定义一个接收单个实例MethodInfo的匿名方法并且使用字符串类的Contains()方法来验证该内容包含那个方法。ContainsInterface()使用该数组类的静态TrueForAll<T>()方法。public delegate bool Predicate public abstract class Array : ... { public static bool TrueForAll< T>(T[] array,Predicate< T> match); }>(t> ContainsInterface()提供给TrueForAll()一个MethodInfo对象数组和匿名方法形式的Predicate。只有在该内容中找到所有的方法时,TrueForAll<T>()才返回true。 本文转自朱先忠老师51CTO博客,原文链接:http://blog.51cto.com/zhuxianzhong/59332 ,如需转载请自行联系原作者

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册