前端技术
HTML
CSS
Javascript
前端框架和UI库
VUE
ReactJS
AngularJS
JQuery
NodeJS
JSON
Element-UI
Bootstrap
Material UI
服务端和客户端
Java
Python
PHP
Golang
Scala
Kotlin
Groovy
Ruby
Lua
.net
c#
c++
后端WEB和工程框架
SpringBoot
SpringCloud
Struts2
MyBatis
Hibernate
Tornado
Beego
Go-Spring
Go Gin
Go Iris
Dubbo
HessianRPC
Maven
Gradle
数据库
MySQL
Oracle
Mongo
中间件与web容器
Redis
MemCache
Etcd
Cassandra
Kafka
RabbitMQ
RocketMQ
ActiveMQ
Nacos
Consul
Tomcat
Nginx
Netty
大数据技术
Hive
Impala
ClickHouse
DorisDB
Greenplum
PostgreSQL
HBase
Kylin
Hadoop
Apache Pig
ZooKeeper
SeaTunnel
Sqoop
Datax
Flink
Spark
Mahout
数据搜索与日志
ElasticSearch
Apache Lucene
Apache Solr
Kibana
Logstash
数据可视化与OLAP
Apache Atlas
Superset
Saiku
Tesseract
系统与容器
Linux
Shell
Docker
Kubernetes
[敏感信息保护的加密传输技术实践]的搜索结果
这里是文章列表。热门标签的颜色随机变换,标签颜色没有特殊含义。
点击某个标签可搜索标签相关的文章。
点击某个标签可搜索标签相关的文章。
MySQL
...,企业也面临数据隐私保护的压力。例如,欧盟《通用数据保护条例》(GDPR)要求企业在存储和处理个人数据时必须严格遵守相关规定,否则将面临巨额罚款。因此,企业在选择云数据库供应商时,不仅要考虑技术层面的因素,还需关注其合规性与安全性措施。以Google Cloud为例,他们最近宣布升级其Cloud SQL服务,增加了更多加密选项以及更强的身份验证机制,以应对日益严峻的网络安全威胁。 此外,开源数据库社区也在快速发展。PostgreSQL作为功能强大的关系型数据库管理系统,近年来因其丰富的插件生态和高度可定制性而受到广泛关注。据统计,全球范围内PostgreSQL的使用率在过去两年内增长了约40%,成为仅次于MySQL的第二大最受欢迎的关系型数据库。这表明,无论是商业产品还是开源项目,都在不断演进以满足现代企业的多样化需求。 对于普通开发者而言,掌握最新的数据库技术和最佳实践至关重要。例如,了解如何高效地进行数据迁移、优化查询性能以及实施灾难恢复策略,都是确保业务连续性的关键技能。同时,随着人工智能技术的进步,智能化数据库管理工具逐渐兴起,它们能够自动识别潜在问题并提供解决方案,极大提升了开发效率。 总之,数据库领域正经历着前所未有的变革,无论是云转型、法规遵从还是技术创新,都值得每一位从业者持续关注和学习。未来,数据库将更加智能、安全且易于使用,为企业创造更大的价值。
2025-03-24 15:46:41
78
笑傲江湖
Go Gin
...控制》所述,采用限流技术成为一种普遍且有效的策略。然而,随着AI技术的迅猛发展,API的应用场景日益复杂,对API的管理和保护提出了新的挑战,尤其是AI伦理与数据隐私问题。 AI伦理的核心在于确保技术的发展与应用遵循道德原则,尊重人类的价值观和权利。当AI技术被用于决策过程时,可能会引发偏见、透明度不足、责任归属模糊等问题。例如,AI系统在推荐算法中可能会放大数据偏差,导致不公正的结果。因此,开发人员需要在设计和部署AI系统时,充分考虑伦理因素,确保算法的公平性、透明性和可解释性。 数据隐私是另一个关键议题。随着API收集和处理的数据量激增,保护个人隐私成为不容忽视的问题。《使用 gincontrib/ratelimit 实现 API 访问控制》中提到的速率限制技术有助于防止恶意或异常的访问行为,但在实际应用中,API还应采取加密、匿名化、最小权限等措施来保护敏感数据。此外,遵守GDPR(欧盟通用数据保护条例)、CCPA(加州消费者隐私法)等法律法规,确保数据的合法收集和使用,也是企业必须面对的责任。 结合AI伦理与数据隐私的双重挑战,API的设计与管理需更加注重综合考量。开发者应当在追求技术创新的同时,始终将伦理与隐私保护置于首位,通过建立透明、负责任的AI系统,增强公众对技术的信任。同时,监管机构和行业组织应加强对AI伦理和数据隐私的规范制定,推动形成全球统一的标准,以促进技术的健康发展,确保技术惠及全人类。 综上所述,AI伦理与数据隐私的双刃剑效应提醒我们,在享受技术带来的便利与效率的同时,必须警惕潜在的风险,采取积极措施加以应对。通过持续的技术创新、伦理规范的建立和完善,以及法律法规的引导,我们可以最大化地发挥API和AI技术的正面作用,构建一个更加安全、公正、可持续的数字未来。
2024-08-24 16:02:03
109
山涧溪流
Etcd
... 《智能合约在区块链技术中的创新应用》 随着区块链技术的不断发展,智能合约的应用正逐渐从理论走向实践,成为推动行业变革的重要力量。智能合约是一种自动执行合同条款的程序,它利用区块链的去中心化、透明度和不可篡改性特性,实现了合同执行的自动化和信任的构建,极大地提高了交易效率和安全性。 区块链与智能合约的融合 区块链技术为智能合约提供了理想的运行环境。在传统的合同执行过程中,双方需要依赖第三方机构(如律师、仲裁机构)来确保合同条款的公正执行。而智能合约则通过编程方式定义合同条款,并自动执行这些条款,无需人工干预。这种自动化执行减少了人为错误的可能性,降低了交易成本,并加快了交易速度。 创新应用场景 1. 供应链金融:智能合约能够确保供应链中各方的交易按照预定规则自动执行,如自动支付、货物交付确认等,大大提高了资金流转的效率和透明度。 2. 保险业:在保险领域,智能合约可以自动触发赔付条件,无需人工审核,减少了欺诈风险,提高了理赔速度。 3. 数字资产交易:智能合约在加密货币和数字资产交易中扮演了关键角色,自动执行交易、锁定资金、执行复杂的交易逻辑,为投资者提供了更安全、更灵活的投资环境。 4. 知识产权管理:智能合约可以自动验证版权归属,保护创作者权益,同时简化了版权交易流程,促进了内容的合法流通。 挑战与未来展望 尽管智能合约带来了诸多优势,但同时也面临着诸如法律合规性、技术安全性和隐私保护等方面的挑战。未来,随着法律法规的完善和技术的不断成熟,智能合约将在更多领域展现出其潜力,成为推动数字经济发展的关键工具。同时,跨链技术的发展将进一步打破不同区块链平台之间的壁垒,促进智能合约在全球范围内的广泛应用。 智能合约的创新应用不仅是区块链技术的前沿探索,也是推动全球数字化转型的重要驱动力。通过不断解决现有挑战,智能合约有望在未来构建更加公平、高效、可信的数字世界。
2024-07-30 16:28:05
455
飞鸟与鱼
Kylin
...棒哒!这背后涉及到的技术细节可多了去了,比如索引优化、查询语句的编写技巧,还有就是数据库配置的调整,每一步都得精心设计,才能让整个系统运行得既高效又稳定。所以,这不仅仅是个理论问题,更是一场实战演练,考验的是咱们对数据库知识的掌握和运用能力呢!本文将带你一起揭开这个谜题的面纱,从理论到实践,全方位解析Kylin与MySQL联接优化的关键点。 二、理论基础 理解Kylin与MySQL的联接机制 在深入讨论优化策略之前,我们首先需要理解两者之间的基本联接机制。Kylin是一个基于Hadoop的列式存储OLAP引擎,它通过预先计算并存储聚合数据来加速查询速度。而MySQL作为一个广泛使用的SQL数据库管理系统,提供了丰富的查询语言和存储能力。嘿,兄弟!你听过数据联接这事儿吗?它通常在咱们把数据从一个地方搬进另一个地方或者在查询数据的时候出现。就像拼图一样,对了,就是那种需要精准匹配才能完美组合起来的拼图。用对了联接策略,那操作效率简直能嗖的一下上去,比火箭还快呢!所以啊,小伙伴们,别小瞧了这个小小的联接步骤,它可是咱们大数据处理里的秘密武器! 三、策略一 优化联接条件 实践示例: sql -- 原始查询语句 SELECT FROM kylin_table JOIN mysql_table ON kylin_table.id = mysql_table.id; -- 优化后的查询语句 SELECT FROM kylin_table JOIN mysql_table ON kylin_table.id = mysql_table.id AND kylin_table.date >= '2023-01-01' AND kylin_table.date <= '2023-12-31'; 通过在联接条件中加入过滤条件(如时间范围),可以减少MySQL服务器需要处理的数据量,从而提高联接效率。 四、策略二 利用索引优化 实践示例: 在MySQL表上为联接字段创建索引,可以大大加速查询速度。同时,在Kylin中,确保相关维度的列已经进行了适当的索引,可以进一步提升性能。 sql -- MySQL创建索引 CREATE INDEX idx_kylin_table_id ON kylin_table(id); -- Kylin配置维度索引 id long true 通过这样的配置,不仅MySQL的查询速度得到提升,Kylin的聚合计算也更加高效。 五、策略三 批量导入与增量更新 实践示例: 对于大型数据集,考虑使用批量导入策略,而不是频繁的增量更新。哎呀,你瞧,咱们用批量导入这招,就像是给MySQL服务器做了一次减压操,让它不那么忙碌,喘口气。同时,借助Kylin的离线大法,我们就能让那些实时查询快如闪电,不拖泥带水。这样一来,不管是数据处理还是查询速度,都大大提升了,用户满意度也蹭蹭往上涨呢! bash 批量导入脚本示例 $ hadoop fs -put data.csv /input/ $ bin/hive -e "LOAD DATA INPATH '/input/data.csv' INTO TABLE kylin_table;" 六、策略四 优化联接模式 选择合适的联接模式(如内联接、外联接等)对于性能优化至关重要。哎呀,你得知道,在咱们实际干活的时候,选对了数据联接的方式,就像找到了开锁的金钥匙,能省下不少力气,避免那些没必要的数据大扫荡。比如说,你要是搞个报表啥的,用对了联接方法,数据就乖乖听话,找起来快又准,省得咱们一个个文件翻,一个个字段找,那得多费劲啊!所以,挑对工具,效率就是王道! 实践示例: 假设我们需要查询所有在特定时间段内的订单信息,并且关联了用户的基本信息。这里,我们可以使用内联接: sql SELECT FROM orders o INNER JOIN users u ON o.user_id = u.user_id WHERE o.order_date BETWEEN '2023-01-01' AND '2023-12-31'; 七、总结与展望 通过上述策略的实施,我们能够显著提升Kylin与MySQL联接操作的性能。哎呀,你知道优化数据库操作这事儿,可真是个门道多得很!比如说,调整联接条件啊,用上索引来提速啊,批量导入数据也是一大妙招,还有就是选对联接方式,这些小技巧都能让咱们的操作变得顺畅无比,响应速度嗖嗖的快起来。就像开车走高速,不堵车不绕弯,直奔目的地,那感觉,爽歪歪!哎呀,随着咱手里的数据越来越多,就像超市里的货物堆积如山,技术这玩意儿也跟咱们的手机更新换代一样快。所以啊,要想让咱们的系统运行得又快又好,就得不断调整和改进策略。就像是给汽车定期加油、保养,让它跑得既省油又稳定。这事儿,可得用心琢磨,不能偷懒!未来,随着更多高级特性如分布式计算、机器学习集成等的引入,Kylin与MySQL的联接优化将拥有更广阔的应用空间,助力数据分析迈向更高层次。
2024-09-20 16:04:27
104
百转千回
Hadoop
...据基础。 技术融合与创新 为了应对数据管理的挑战,技术界不断探索新的集成方法与工具。例如,使用API网关、微服务架构等现代技术手段,可以更灵活地连接不同的数据源,实现数据的无缝集成。同时,AI与机器学习技术也被引入,用于自动优化数据集成流程,提高数据质量与分析精度。这种技术融合不仅增强了数据集成的自动化水平,也为数据驱动的决策提供了更强大的支持。 安全与合规性考量 在数据集成过程中,安全与合规性是不可忽视的关键因素。随着全球数据保护法规(如GDPR、CCPA等)的出台,确保数据集成过程中的隐私保护与数据安全显得尤为重要。企业需要在集成方案设计之初就充分考虑数据加密、访问控制、审计追踪等安全措施,确保符合相关法律法规的要求。此外,建立透明的数据流转机制,增强用户对数据使用的信任度,也是维护企业声誉与合规性的重要环节。 结语 HBase与NoSQL数据库的集成在现代数据管理中扮演着不可或缺的角色。面对数据量的增长、技术的迭代以及合规性要求的提升,这一集成模式需要不断适应变化,探索更高效、安全的数据处理与分析方法。未来,随着大数据、人工智能等技术的进一步发展,数据集成的边界将进一步拓宽,为各行各业提供更加智能、个性化的数据解决方案。 在这个不断演进的过程中,企业应持续关注技术创新与最佳实践,构建灵活、安全的数据生态体系,以应对未来的挑战与机遇。
2024-08-10 15:45:14
35
柳暗花明又一村
JSON
...等号:一场误会引发的技术冒险 1. 引言 为什么我们要聊这个? 大家好啊!今天咱们聊聊一个看似简单却可能让人抓狂的话题——JSON解析中冒号变等号的问题。你说这话是不是觉得有点愣?对啊,这种感觉太正常了,特别是你头一回碰见JSON的时候,心里肯定在想:“这是啥东东?”我当年也是懵懵懂懂地开始学编程,结果一不小心就踩进了这个坑里。所以今天想跟大家聊聊我的经历,顺便给大家分享一些解决办法。 JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,它易于人阅读和编写,同时也易于机器解析和生成。但有时候,这个格式会因为某些小细节而让人头疼不已。哎呀,就拿这个来说吧,你辛辛苦苦敲了一段看着特别标准的JSON数据,结果程序一跑直接给你来个“格式错误”,整得你一头雾水。最后扒拉开一看,嘿,好家伙,罪魁祸首竟然是那个该死的冒号被你手滑打成了等号!哎呀,这种错误简直让人哭笑不得! 不过呢,别担心,今天我会带着大家一起深入探讨这个问题,看看为什么会发生这样的事情,以及如何避免类似的情况再次发生。咱们一起揭开这场“冒号变等号”的谜团吧! --- 2. 什么是JSON?它的基本结构长什么样? 首先,咱们得搞清楚JSON到底是什么。简单来说,JSON是一种用来存储和传输数据的格式。你可以把它想象成一种“万能语言”,不管是搞前端的还是做后端的,大家都能用JSON来互相“说话”、传递信息。 JSON的基本结构其实非常简单,主要由两种元素组成: - 键值对:用冒号:分隔,左边是键(key),右边是值(value)。比如"name": "Alice"。 - 数组:用方括号[]包裹起来的一组值,可以是字符串、数字、布尔值或者嵌套的JSON对象。例如[1, 2, 3]。 示例代码: json { "name": "Alice", "age": 25, "isStudent": false, "courses": ["Math", "Science"] } 这段JSON数据描述了一个学生的信息。你看,整个结构清晰明了,只需要一点点耐心就能读懂。不过嘛,要是这儿的冒号不小心打成了等号=,那整个JSON结构可就直接“翻车”了,啥也跑不出来了!不信的话,咱们试试看。 --- 3. 冒号变等号 一个让人崩溃的小错误 说到冒号变等号,我真的有一肚子的话要说。记得有一次,我在调试一个API接口时,发现返回的数据总是出错。百思不得其解之后,我才意识到问题出在JSON格式上。原来是我手滑,把某个键值对中的冒号写成了等号。 错误示例: json { "name=Alice", "age=25", "isStudent=false", "courses=[Math, Science]" } 看到这里,你是不是也觉得特别别扭?没错,这就是典型的JSON格式错误。正常情况下,JSON中的键值对应该用冒号分隔,而不是等号。等号在这里根本不起作用,会导致整个JSON对象无法被正确解析。 那么问题来了,为什么会有人犯这样的错误呢?我觉得主要有以下几点原因: 1. 疏忽大意 有时候我们写代码太赶时间,注意力不够集中,结果就出现了这种低级错误。 2. 习惯差异 有些人可能来自其他编程语言背景,习惯了用等号作为赋值符号,结果不自觉地把这种习惯带到了JSON中。 3. 工具误导 有些文本编辑器或者IDE可能会自动补全等号,如果没有及时检查,就容易出错。 --- 4. 如何优雅地处理这种错误? 既然知道了问题所在,接下来就是解决问题的时候啦!别急,咱们可以从以下几个方面入手: 4.1 检查与验证 首先,最直接的办法就是仔细检查你的JSON数据。如果怀疑有问题,可以使用在线工具进行验证。比如著名的[JSONLint](https://jsonlint.com/),它可以帮你快速找出格式错误的地方。 4.2 使用正确的编辑器 选择一款适合的代码编辑器也很重要。像VS Code这样的工具不仅支持语法高亮,还能实时检测JSON格式是否正确。如果你发现等号突然冒出来,编辑器通常会立即提醒你。 4.3 编写自动化测试 对于经常需要处理JSON数据的项目,建议编写一些自动化测试脚本来确保数据格式无误。这样即使出现错误,也能第一时间发现并修复。 示例代码:简单的JSON验证函数 python import json def validate_json(data): try: json.loads(data) print("JSON is valid!") except ValueError as e: print(f"Invalid JSON: {e}") 测试用例 valid_json = '{"name": "Alice", "age": 25}' invalid_json = '{"name=Alice", "age=25"}' validate_json(valid_json) 输出: JSON is valid! validate_json(invalid_json) 输出: Invalid JSON: Expecting property name enclosed in double quotes: line 1 column 2 (char 1) --- 5. 总结 保持警惕,远离坑点 好了,今天的分享就到这里啦!通过这篇文章,希望大家对JSON解析中的冒号变等号问题有了更深刻的认识。嘿,听好了,这事儿可别小瞧了!哪怕就是一个不起眼的小标点,都有可能让整套系统“翻车”。细节这东西啊,就像是搭积木,你要是漏掉一块或者放歪了,那整个塔就悬乎了。所以呀,千万别觉得小地方无所谓,它们往往是关键中的关键! 最后,我想说的是,学习编程的过程就是不断踩坑又爬出来的旅程。遇到问题不可怕,可怕的是我们不去面对它。只要多加练习,多积累经验,相信每个人都能成为高手!加油吧,小伙伴们! 如果你还有其他疑问,欢迎随时来找我讨论哦~咱们下次再见啦!
2025-03-31 16:18:15
12
半夏微凉
转载文章
...谋而合,展现了理论与实践相结合的重要性。 同时,回文串在密码学、遗传学以及文学创作等多个领域均有应用。例如,在DNA序列分析中,回文结构往往关联着基因调控的重要区域;在密码学中,特定类型的回文串可用于构建加密算法的关键部分。深入理解并熟练掌握回文串的相关性质及处理方法,无疑有助于我们在这些领域取得更多的技术突破。 总之,从基础的编程题出发,我们可以洞察到字符串处理与算法优化在前沿科研和实际应用中的深远影响。通过持续关注和学习此类问题的最新研究成果与应用案例,我们能够不断提升自身的算法设计和问题解决能力。
2023-10-05 13:54:12
228
转载
DorisDB
...一艘载满现代数据处理技术的巨轮。哎呀,这家伙可真是个宝啊!不仅性能杠杠的,稳定性也是没得说,而且还能轻松升级扩容,怪不得那么多大公司都离不开它,用它来做数据的存储和分析,简直是如虎添翼!然而,就像任何航海之旅,DorisDB航行中也会遭遇风浪——“写入失败”。嘿,兄弟!这篇文章就像是一场探险之旅,带你深入揭秘这个棘手问题的真相。咱们不只停留在表面,而是要挖出问题的根儿,然后一起找寻解决的钥匙。想象一下,我们是在大海捞针,但有了指南针和渔网,这场寻找就变得既刺激又充满乐趣。跟着我,咱们在数据的汪洋里畅游,找到属于你的那片宁静海港,让你不再被信息的洪流淹没,而是能稳稳驾驭,轻松自在地航行。准备好了吗?出发吧! 第一章:写入失败的初探 现象描述:当你尝试向DorisDB表中插入数据时,突然间,一切变得静止。查询返回一个错误信息,告诉你“写入失败”。这不仅让你感到沮丧,还可能影响了业务流程的连续性。 原因分析:写入失败可能是由多种因素引起的,包括但不限于网络延迟、资源限制(如磁盘空间不足)、事务冲突、以及数据库配置问题等。理解这些原因有助于我们对症下药。 第二章:案例研究:网络延迟引发的写入失败 场景还原:假设你正使用Python的dorisdb库进行数据插入操作。代码如下: python from dorisdb import DorisDBClient client = DorisDBClient(host='your_host', port=your_port, database='your_db') cursor = client.cursor() 插入数据 cursor.execute("INSERT INTO your_table (column1, column2) VALUES ('value1', 'value2')") 问题浮现:执行上述代码后,你收到了“写入失败”的消息,同时发现网络连接偶尔会中断。 解决方案:首先,检查网络连接稳定性。确保你的服务器与DorisDB实例之间的网络畅通无阻。其次,优化SQL语句的执行效率,减少网络传输的数据量。例如,可以考虑批量插入数据,而不是逐条插入。 第三章:资源限制:磁盘空间不足的挑战 场景还原:你的DorisDB实例运行在一个资源有限的环境中,某天,当你试图插入大量数据时,系统提示磁盘空间不足。 问题浮现:尽管你已经确保了网络连接稳定,但写入仍然失败。 解决方案:增加磁盘空间是显而易见的解决方法,但这需要时间和成本。哎呀,兄弟,你得知道,咱们手头的空间那可是个大问题啊!要是想在短时间内搞定它,我这儿有个小妙招给你。首先,咱们得做个大扫除,把那些用不上的数据扔掉。就像家里大扫除一样,那些过时的文件、照片啥的,该删就删,别让它占着地方。其次呢,咱们可以用更牛逼的压缩工具,比如ZIP或者RAR,它们能把文件压缩得更小,让硬盘喘口气。这样一来,不仅空间大了,还能节省点资源,挺划算的嘛!试试看,说不定你会发现自己的设备运行起来比以前流畅多了!嘿,兄弟!你听说过 DorisDB 的分片和分布式功能吗?这玩意儿超级厉害!它就像个大仓库,能把咱们的数据均匀地摆放在多个小仓库里(那些就是节点),这样不仅能让数据更高效地存储起来,还能让我们的系统跑得更快,用起来更顺畅。试试看,保管让你爱不释手! 第四章:事务冲突与并发控制 场景还原:在高并发环境下,多个用户同时尝试插入数据到同一表中,导致了写入失败。 问题浮现:即使网络连接稳定,磁盘空间充足,事务冲突仍可能导致写入失败。 解决方案:引入适当的并发控制机制是关键。在DorisDB中,可以通过设置合理的锁策略来避免或减少事务冲突。例如,使用行级锁或表级锁,根据具体需求选择最合适的锁模式。哎呀,兄弟,咱们在优化程序的时候,得注意一点,别搞那些没必要的同时进行的操作,这样能大大提升系统的稳定性。就像是做饭,你要是同时炒好几个菜,肯定得忙得团团转,而且容易出错。所以啊,咱们得一个个来,稳扎稳打,这样才能让系统跑得又快又稳! 结语:从困惑到解决的旅程 面对“写入失败”,我们需要冷静分析,从不同的角度寻找问题所在。哎呀,你知道嘛,不管是网速慢了点、硬件不够给力、操作过程中卡壳了,还是设置哪里没对劲,这些事儿啊,都有各自的小妙招来解决。就像是遇到堵车了,你得找找是哪段路的问题,然后对症下药,说不定就是换个路线或者等等红绿灯,就能顺畅起来呢!哎呀,你知道不?咱们要是能持续地学习和动手做,那咱处理问题的能力就能慢慢上个新台阶。就像给水管通了塞子,数据的流动就更顺畅了。这样一来,咱们的业务跑起来也快多了,就像是有了个贴身保镖,保护着业务高效运转呢!嘿!听好了,每回遇到难题都不是白来的,那可是让你升级打怪的好机会!咱们就一起手牵手,勇闯数据的汪洋大海,去发现那些藏在暗处的新世界吧!别怕,有我在你身边,咱俩一起探险,一起成长!
2024-10-07 15:51:26
122
醉卧沙场
Tornado
...t Manager的加密策略 1. 为什么选中了Tornado和Google Cloud Secret Manager? 嘿,大家好!我是你们的老朋友,今天想聊聊我的新发现——Tornado 和 Google Cloud Secret Manager 的结合。先说说我为啥对这俩家伙感兴趣吧。 首先,Tornado 是 Python 中的一个高性能 Web 框架,它轻量级又灵活,适合构建实时应用或者需要高并发处理的应用场景。我以前用 Django 做过几个项目,感觉还挺不错的。不过一到几十万人同时在线的时候,服务器就开始“吭哧吭哧”地忙不过来了,感觉它都快撑不住了,哎哟,真是让人头大!后来听人说 Tornado 的异步非阻塞功能特别厉害,我心想不能落后啊,赶紧抽空研究了一下。结果发现,它的性能确实吊炸天,而且代码写起来也挺优雅。 然后是 Google Cloud Secret Manager,这是一个专门用来存储敏感信息(比如 API 密钥、数据库密码啥的)的服务。对开发者而言,安全这事得放首位,要是还用那种硬编码或者直接把密钥啥的写进配置文件的老办法,那简直就是在玩火自焚啊!Google Cloud Secret Manager 提供了加密存储、访问控制等功能,简直是保护秘钥的最佳选择之一。 所以,当我把这两者放在一起的时候,脑海里立刻浮现出一个画面:Tornado 快速响应前端请求,而 Secret Manager 在背后默默守护着那些珍贵的秘密。是不是很带感?接下来我们就一步步深入探索它们的合作方式吧! --- 2. 初识Tornado 搭建一个简单的Web服务 既然要玩转 Tornado,咱们得先搭个基础框架才行。好嘞,接下来我就简单搞个小网页服务,就让它回一句暖心的问候就行啦!虽然看起来简单,但这可是后续一切的基础哦! python import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.write("Hello, Tornado!") def make_app(): return tornado.web.Application([ (r"/", MainHandler), ]) if __name__ == "__main__": app = make_app() app.listen(8888) print("Server started at http://localhost:8888") tornado.ioloop.IOLoop.current().start() 这段代码超级简单对不对?我们定义了一个 MainHandler 类继承自 tornado.web.RequestHandler,重写了它的 get 方法,当收到 GET 请求时就会执行这个方法,并向客户端返回 "Hello, Tornado!"。然后呢,就用 make_app 这个函数把路由和这个处理器绑在一起,最后再启动服务器,让它开始监听 8888 端口。 运行后打开浏览器输入 http://localhost:8888,就能看到页面显示 "Hello, Tornado!" 了。是不是特别爽?不过别急着高兴,这只是万里长征的第一步呢! --- 3. 引入Google Cloud Secret Manager:让秘密不再裸奔 现在我们知道如何用 Tornado 做点事情了,但问题是,如果我们的应用程序需要用到一些敏感信息(例如数据库连接字符串),该怎么办呢?直接写在代码里吗?当然不行!这就是为什么我们要引入 Google Cloud Secret Manager。 3.1 安装依赖库 首先需要安装 Google Cloud 的官方 Python SDK: bash pip install google-cloud-secret-manager 3.2 获取Secret Manager中的值 假设我们在 Google Cloud Console 上已经创建了一个名为 my-secret 的密钥,并且它里面保存了我们的数据库密码。我们可以这样从 Secret Manager 中读取这个值: python from google.cloud import secretmanager def access_secret_version(project_id, secret_id, version_id): client = secretmanager.SecretManagerServiceClient() name = f"projects/{project_id}/secrets/{secret_id}/versions/{version_id}" response = client.access_secret_version(name=name) payload = response.payload.data.decode('UTF-8') return payload 使用示例 db_password = access_secret_version("your-project-id", "my-secret", "latest") print(f"Database Password: {db_password}") 这段代码做了什么呢?很简单,它实例化了一个 SecretManagerServiceClient 对象,然后根据提供的项目 ID、密钥名称以及版本号去访问对应的密钥内容。注意这里的 version_id 参数可以设置为 "latest" 来获取最新的版本。 --- 4. 将两者结合起来 构建更安全的应用 那么问题来了,怎么才能让 Tornado 和 Google Cloud Secret Manager 协同工作呢?其实答案很简单——我们可以将从 Secret Manager 获取到的敏感数据注入到 Tornado 的配置对象中,从而在整个应用范围内使用这些信息。 4.1 修改Tornado应用以支持从Secret Manager加载配置 让我们修改之前的 MainHandler 类,让它从 Secret Manager 中加载数据库密码并用于某种操作(比如查询数据库)。为了简化演示,这里我们假设有一个 get_db_password 函数负责完成这项任务: python from google.cloud import secretmanager def get_db_password(): client = secretmanager.SecretManagerServiceClient() name = f"projects/{YOUR_PROJECT_ID}/secrets/my-secret/versions/latest" response = client.access_secret_version(name=name) return response.payload.data.decode('UTF-8') class MainHandler(tornado.web.RequestHandler): def initialize(self, db_password): self.db_password = db_password def get(self): self.write(f"Connected to database with password: {self.db_password}") def make_app(): db_password = get_db_password() return tornado.web.Application([ (r"/", MainHandler, {"db_password": db_password}), ]) 在这个例子中,我们在 make_app 函数中调用了 get_db_password() 来获取数据库密码,并将其传递给 MainHandler 的构造函数作为参数。这样一来,每个 MainHandler 实例都会拥有自己的数据库密码属性。 --- 5. 总结与展望 好了朋友们,今天的分享就到这里啦!通过这篇文章,我们了解了如何利用 Tornado 和 Google Cloud Secret Manager 来构建更加安全可靠的 Web 应用。虽然过程中遇到了不少挑战,但最终的效果还是让我感到非常满意。 未来的话,我还想尝试更多有趣的功能组合,比如结合 Redis 缓存提高性能,或者利用 Pub/Sub 实现消息队列机制。如果你也有类似的想法或者遇到什么问题,欢迎随时跟我交流呀! 最后祝大家 coding愉快,记得保护好自己的秘密哦~ 😊
2025-04-09 15:38:23
43
追梦人
转载文章
...表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。 sysinternals的网站创立于1996年由Mark russinovich和布赖科格斯韦尔主办其先进的系统工具和技术资料.微软于 2006年7月收购sysinternals公司 . 不管你是一个IT高级工作者还是一个开发者,你都会发现sysinternals工具可以帮助您管理、故障分析和诊断你的Windows系统和应用程序. 如果您有关于如何使用这些工具的问题,请访问sysinternals论坛从其他用户和我们的团队获取解答和帮助. 该工具包括: AccessChk 这个工具为您显示指定至档案、登录机码或 Windows 服务的使用者或群组之存取。 AccessEnum 这个简单又具有超高安全性的工具,会让您知道拥有对您系统目录、档案及登录机码的存取之对象和方式。用它来寻找您权限下的安全性漏洞。 AdRestore 取消删除 Server 2003 Active Directory 物件。 BgInfo 这个可完全设定的程式,会自动产生包括含有 IP 位址、电脑名称,和网路介面卡等等重要资讯的桌面背景。 BlueScreen 这个萤幕保护程式不只将「蓝色萤幕」(Blue Screens) 模仿得维妙维肖,也能模仿重新开机 (需使用 CHKDSK 完成),而且在 Windows NT 4、Windows 2000、Windows XP、Server 2003 和 Windows 9x 中皆能执行。 CacheSet CacheSet 是一种能让您使用 NT 提供的功能来控制 Cache Manager 的工作组大小。除了和 NT 所有版本相容之外,还提供原始程式码。 检视系统时钟的解析度,同时也是计时器解析度的最大值。 Contig 希望能够快速地将常用的档案进行磁碟重组吗?使用 Contig 最佳化个别档案,或是建立新的连续档案。 Ctrl2cap 这是一种核心模式驱动程式,展示键盘输入筛选只在键盘类别驱动程式之上,目的是为了将大写锁定按键转换至控制按键。这个层级的筛选允许在 NT 「发现」按键之前,先进行转换和隐藏按键。包括完整的来源。此外,Ctrl2cap 还会显示如何使用 NtDisplayString() 将讯息列印至初始化的蓝色萤幕。 DebugView Sysinternals 的另一个首开先例:这个程式会拦截分别由 DbgPrint 利用装置驱动程式,和 OutputDebugString 利用 Win32 程式所做的呼叫。它能够在您的本机上或跨往际往路,在不需要作用中的侦错工具情况下,检视和录制侦错工作阶段输出。 DiskExt 显示磁碟区磁碟对应。 Diskmon 这个公用程式会撷取全部的硬碟活动,或是提供系统匣中的软体磁碟活动指示器的功能。 DiskView 图形化磁区公用程式。 Du 依目录检视磁碟使用状况。 EFSDump 检视加密档案的资讯。 Filemon 这个监控工具让您即时检视所有档案系统的活动。 Handle 这个易於操纵的命令列公用程式能够显示档案开启的种类和使用的处理程序等更多资讯。 Hex2dec 十六进位数字和十进位数字相互转换。 Junction 建立 Win2K NTFS 符号连结。 LDMDump 倾印逻辑磁碟管理员的磁碟上之资料库内容,其中描述 Windows 2000 动态磁碟分割。 ListDLLs 列出所有目前载入的 DLL,包括载入位置和他们的版本编号。2.0 版列印载入模组的完整路径名称。 LiveKd 使用 Microsoft 核心侦错工具检视即时系统。 LoadOrder 检视在您 WinNT/2K 系统上载入装置的顺序。 LogonSessions 列出系统上的作用中登入工作阶段。 MoveFile 允许您对下一次开机进行移动和删除命令的排程。 NTFSInfo 使用 NTFSInfo 检视详细的 NTFS 磁碟区资讯,包括主档案表格 (MFT) 和 MFT 区的大小和位置,还有 NTFS 中继资料档案的大小。 PageDefrag 将您的分页档和登录 Hive 进行磁碟重组。 PendMoves 列举档案重新命名的清单,删除下次开机将会执行的命令。 Portmon 使用这个进阶的监视工具进行监视序列和平行连接埠活动。它不仅掌握所有标准的序列和平行 IOCTL,甚至会显示传送和接收的资料部份。Version 3.x 具有强大的新 UI 增强功能和进阶的筛选功能。 Process Monitor 即时监控档案系统、登录、程序、执行绪和 DLL 活动。 procexp 任务管理器,这个管理器比windows自带的管理器要强大方便的很多,建议替换自带的任务管理器(本人一直用这个管理器,很不错)。此工具也有汉化版,fans可以自己搜索下载 ProcFeatures 这个小应用程式会描述「实体位址扩充」的处理器和 Windows 支援,而没「没有执行」缓冲区溢位保护。 PsExec 以有限的使用者权限执行处理程序。 PsFile 检视远端开启档案有哪些。 PsGetSid 显示电脑或使用者的 SID。 PsInfo 取得有关系统的资讯。 PsKill 终止本机或远端处理程序。 PsList 显示处理程序和执行绪的相关资讯。 PsLoggedOn 显示使用者登录至一个系统。 PsLogList 倾印事件记录档的记录。 PsPasswd 变更帐户密码。 PsService 检视及控制服务。 PsShutdown 关机及选择重新启动电脑。 PsSuspend 暂停及继续处理程序。 PsTools PsTools 产品系列包括命令列公用程式,其功能有列出在本机或远端电脑上执行的处理程序、远端执行的处理程序、重新开机的电脑和倾印事件记录等等。 RegDelNull 扫描并删除登录机码,这些登录机码包括了标准登录编辑工具无法删除的内嵌式 Null 字元。 RegHide 建立名为 "HKEY_LOCAL_MACHINE\Software\Sysinternals\Can't touch me!\0" 并使用原生 API 的金钥,而且会在此金钥内建立一个值。 Regjump 跳至您在 Regedit 中指定的登录路径。 Regmon 这个监视工具让您即时看到全部的登录活动。 RootkitRevealer 扫描您系统上 Rootkit 为基础的恶意程式码。 SDelete 以安全的方法覆写您的机密档案,并且清除因先前使用这个 DoD 相容安全删除程式所删除档案後而释放的可用空间。包括完整的原始程式码。 ShareEnum 扫描网路上档案共用并检视其安全性设定,来关闭安全性漏洞。 Sigcheck 倾印档案版本资讯和验证系统上的影像皆已完成数位签章。 Strings 搜寻 binaryimages 中的 ANSI 和 UNICODE 字串。 Sync 将快取的资料清除至磁碟。 TCPView 作用中的通讯端命令列检视器。 VolumeId 设定 FAT 或 NTFS 磁碟区 ID。 Whois 看看谁拥有一个网际网路位址。 Winobj 最完整的物件管理员命名空间检视器在此。 ZoomIt 供萤幕上缩放和绘图的简报公用程式。 转自:http://www.360doc.com/content/15/0323/06/20545288_457293504.shtml 本篇文章为转载内容。原文链接:https://blog.csdn.net/qq_33515088/article/details/80721846。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2024-01-22 15:44:41
102
转载
Nacos
...的应用。 同时,随着技术的发展,安全问题日益受到重视。在使用Nacos或其他配置管理工具时,数据传输的安全性至关重要。建议开发者们在部署过程中启用SSL/TLS加密,确保敏感信息在网络中传输时不会被窃取或篡改。另外,定期更新工具版本,修复已知漏洞,也是保障系统安全的重要措施。 在全球范围内,开源社区对这些技术的支持力度也在不断加大。比如GitHub上的Nacos项目,其活跃度非常高,每周都有大量的贡献者提交代码改进和修复问题。这种持续的技术迭代为企业提供了强大的技术支持,使得企业在面对复杂多变的技术挑战时能够更加从容应对。 总之,在选择合适的配置管理工具时,企业需要综合考量自身的业务需求和技术栈特点,同时也要密切关注最新的技术趋势和安全动态,以确保系统的稳定性和安全性。
2025-04-06 15:56:57
67
清风徐来
转载文章
...相关领域的最新动态和技术趋势也至关重要。例如,在Node.js社区中,Node.js 16.x已成为最新的LTS版本,提供了更多性能优化和新特性支持,开发者可以通过官方文档快速掌握升级方法并充分利用新版本优势(参考来源:Node.js官方网站)。同时,MySQL数据库也在不断迭代更新,MySQL 8.0带来了诸如窗口函数、Caching_sha2_password等安全性和功能性的重大改进,对于提升项目的数据处理效率和安全性具有重要意义(参考来源:MySQL官网博客)。 在云服务和镜像源方面,阿里云、腾讯云等国内服务商也推出了针对deepin系统的加速镜像源服务,用户可根据自身网络状况选择合适的镜像源以提高软件安装和更新的速度(参考来源:阿里云、腾讯云官方文档)。此外,随着Web开发技术的发展,Vue.js、React等前端框架持续火爆,配合Webpack、Vite等现代构建工具,可以更高效地搭建和维护前端项目结构(参考来源:Vue.js、React官网及技术社区文章)。 在办公领域,WPS Office不仅实现了对Linux系统的全面支持,还不断优化跨平台兼容性,并且积极跟进Microsoft Office的新功能,使得国产办公软件在用户体验上逐渐与国际接轨(参考来源:WPS官方公告及媒体报道)。而在浏览器市场,除了Edge浏览器之外,Firefox、Chromium-based浏览器如Chrome和Opera同样提供Linux版,它们之间的性能对比、隐私保护策略以及对Web新技术的支持情况值得深入研究(参考来源:各大浏览器官网及第三方评测报告)。 总之,随着开源生态的繁荣和Linux发行版的普及,关注和掌握deepin系统及其周边软件的最新发展动态,将有助于我们更好地利用这一平台进行高效开发和舒适办公。
2023-11-15 19:14:44
54
转载
转载文章
...和安全验证机制的最新实践与发展动态。 近期,Spring Boot作为主流Java Web开发框架,在其最新的2.5版本中增强了对文件上传的支持,不仅简化了配置流程,还优化了大文件分块上传与断点续传等功能。例如,开发者可以利用MultipartFile接口轻松处理多部分表单提交的文件,并结合云存储服务(如阿里云OSS或AWS S3)进行分布式文件存储与管理,极大地提高了系统的稳定性和可扩展性。 同时,针对安全性问题,Spring Security框架提供了更严格的CSRF保护和JWT token验证等机制,确保用户在执行敏感操作(如文件上传与下载)时的身份合法性。此外,OAuth 2.0授权协议在企业级应用中的普及,使得跨系统、跨平台的用户身份验证与授权更为便捷且安全。 另外,随着前端技术的发展,诸如React、Vue.js等现代前端框架也实现了对文件上传组件的高度封装,配合后端API能够提供无缝的用户体验。例如,通过axios库在前端发起multipart/form-data类型的POST请求,配合后端的RESTful API完成文件上传过程,而后再通过响应式编程实现文件上传状态的实时反馈。 综上所述,随着技术的演进,无论是后端框架还是前端技术,都在不断提升文件上传下载功能的安全性、易用性和性能表现。在实际项目开发中,除了掌握基础的文件处理方法外,还需关注行业前沿趋势,灵活运用新技术手段以满足不断变化的业务需求。
2023-11-12 20:53:42
140
转载
Apache Lucene
...到来,数据量的激增对信息检索系统提出了更高的要求。Apache Lucene,作为一款开源的全文检索库,长期以来在文本检索领域扮演着核心角色。本文旨在深入探讨Apache Lucene在现代搜索引擎架构中的地位、面临的挑战及未来的发展趋势。 当前应用与优势 Apache Lucene因其高效、可扩展性和灵活性,被广泛应用于各类搜索引擎和大数据处理系统中。它不仅支持多种语言的分词和索引构建,还能提供强大的查询解析和匹配算法,使得在大规模数据集上的实时搜索成为可能。此外,Lucene的社区活跃度高,持续更新与优化,使其在处理复杂查询、支持多语言和适应不同应用场景方面具有显著优势。 面临的挑战 尽管Apache Lucene表现突出,但随着技术的快速发展和用户需求的多样化,它也面临着一些挑战。首先,随着数据规模的不断扩大,如何在保持高性能的同时降低资源消耗成为关键。其次,面对实时性要求越来越高的应用场景,如何实现快速响应和低延迟成为了亟待解决的问题。再者,随着AI和机器学习技术的融合,如何将这些先进算法集成到Lucene中,提升检索精度和智能化水平,也是未来研究的重点。 未来发展展望 展望未来,Apache Lucene有望在以下几个方向上实现突破: 1. 性能优化与资源管理:通过算法优化和硬件加速技术,进一步提高处理速度和资源利用率,满足大流量、高并发场景的需求。 2. 集成AI与机器学习:引入深度学习、自然语言处理等AI技术,增强检索系统的智能性和个性化推荐能力。 3. 跨语言与多模态搜索:随着全球化的进程加快,支持更多语言的处理和多模态(文本、图像、语音等)搜索将成为重要发展方向。 4. 隐私保护与安全:在数据安全和个人隐私日益受到重视的背景下,开发基于差分隐私、同态加密等技术的检索系统,保障用户数据的安全性。 结语 Apache Lucene作为一款成熟且仍在不断演进的全文检索库,在现代搜索引擎架构中发挥着不可或缺的作用。面对未来的挑战,它不仅需要持续优化现有功能,还需不断创新,以适应不断变化的市场需求和技术发展趋势。通过融合前沿技术,Apache Lucene有望在未来的信息检索领域中继续引领创新,为用户提供更高效、更智能、更安全的搜索体验。 --- 这篇“延伸阅读”旨在讨论Apache Lucene在当前及未来可能面临的技术挑战与发展方向,强调其在现代搜索引擎架构中的核心地位,并提出可能的解决方案和展望。通过深入分析当前应用优势、面临的挑战及未来发展趋势,为读者提供了一个全面而前瞻性的视角。
2024-07-25 00:52:37
391
青山绿水
Sqoop
...为一个热爱折腾数据的技术爱好者,最近我在尝试用Sqoop来完成一些数据迁移任务。哈哈,Sqoop这个名字一听就觉得挺酷的,对不?它就像个超级厉害的“中间人”,一边连着Hadoop那个大数据的世界,另一边又搭在传统的数据库上,两边都能玩得转! 说到Sqoop,它的主要功能就是从关系型数据库中抽取数据并导入到Hadoop生态系统中,或者反过来把Hadoop中的数据导出到关系型数据库里。对我来说,这简直就是个救星啊!毕竟我天天都要跟一堆 structured data(结构化数据)打交道,没有它,我的日子能过得下去才怪呢! 不过呢,事情并没有想象中那么顺利。话说有一次我用 Sqoop 做数据迁移的时候,发现了个让人挠头的问题——只要碰到某些特别的数据处理任务,作业就突然“罢工”了,也不知道是啥原因。这事儿可把我给整郁闷了,我都觉得自己的水平挺过关的了,没想到被一个看起来超简单的题目给绊住了,真是有点糗啊! 示例代码: bash sqoop import \ --connect jdbc:mysql://localhost:3306/mydatabase \ --username root \ --password mypassword \ --table employees \ --target-dir /user/hadoop/employees 这段代码看起来挺正常的,但我后来发现,当表中的数据量过大或者存在一些复杂的约束条件时,Sqoop就表现得不太友好。 --- 二、Sqoop作业失败的背后 接下来,让我们一起深入探讨一下这个问题。说实话,刚开始接触Sqoop那会儿,我对它是怎么工作的压根儿没弄明白,稀里糊涂的。我以为只要配置好连接信息,然后指定源表和目标路径就行了。但实际上,Sqoop并不是这么简单的工具。 当我第一次遇到作业失败的情况时,内心是崩溃的。屏幕上显示的错误信息密密麻麻,但仔细一看,其实都是些常见的问题。打个比方啊,Sqoop这家伙一碰到一些特别的符号,比如空格或者换行符,就容易“翻车”,直接给你整出点问题来。还有呢,有时候因为网络卡了一下,延迟太高,Sqoop就跟服务器说拜拜了,连接就这么断了,挺烦人的。 有一次,我在尝试将一张包含大量JSON字段的表导出到HDFS时,Sqoop直接报错了。我当时就在心里嘀咕:“为啥别的工具处理起来轻轻松松的事儿,到Sqoop这儿就变得这么棘手呢?”后来,我一咬牙,开始翻遍各种资料,想着一定要找出个解决办法来。 思考与尝试: 经过一番研究,我发现Sqoop默认情况下并不会对数据进行深度解析,这意味着如果数据本身存在问题,Sqoop可能无法正确处理。所以,为了验证这个假设,我又做了一次测试。 bash sqoop import \ --connect jdbc:mysql://localhost:3306/mydatabase \ --username root \ --password mypassword \ --table problematic_table \ --fields-terminated-by '\t' \ --lines-terminated-by '\n' 这次我特意指定了分隔符和换行符,希望能避免之前遇到的那些麻烦。嘿,没想到这次作业居然被我搞定了!中间经历了不少波折,不过好在最后算是弄懂了个中奥秘,也算没白费功夫。 --- 三、透明性的重要性 Sqoop到底懂不懂我的需求? 说到Sqoop的透明性,我觉得这是一个非常重要的概念。所谓的透明性嘛,简单来说,就是Sqoop能不能明白咱们的心思,然后老老实实地按咱们想的去干活儿,不添乱、不出错!显然,在我遇到的这些问题中,Sqoop的表现并不能让人满意。 举个例子来说,假设你有一个包含多列的大表,其中某些列的数据类型比较复杂(例如数组、嵌套对象等)。在这种情况下,Sqoop可能会因为无法正确识别这些数据类型而失败。更糟糕的是,它并不会给出明确的提示,而是默默地报错,让你一头雾水。 为了更好地应对这种情况,我在后续的工作中加入了更多的调试步骤。比如说啊,你可以先用describe这个命令去看看表的结构,确保所有的字段都乖乖地被正确识别了;接着呢,再用--check-column这个选项去瞅一眼,看看有没有重复的记录藏在里面。这样一来,虽然增加了工作量,但至少能减少不必要的麻烦。 示例代码: bash sqoop job --create my_job \ -- import \ --connect jdbc:mysql://localhost:3306/mydatabase \ --username root \ --password mypassword \ --table employees \ --check-column id \ --incremental append \ --last-value 0 这段代码展示了如何创建一个增量作业,用于定期更新目标目录中的数据。通过这种方式,可以有效避免一次性加载过多数据带来的性能瓶颈。 --- 四、总结与展望 与Sqoop共舞 总的来说,尽管Sqoop在某些场景下表现得不尽人意,但它依然是一个强大的工具。通过不断学习和实践,我相信自己能够更加熟练地驾驭它。未来的计划里,我特别想试试一些更酷的功能,比如说用Sqoop直接搞出Avro文件,或者把Spark整进来做分布式计算,感觉会超级带劲! 最后,我想说的是,技术这条路从来都不是一帆风顺的。遇到困难并不可怕,可怕的是我们因此放弃努力。正如那句话所说:“失败乃成功之母。”只要保持好奇心和求知欲,总有一天我们会找到属于自己的答案。 如果你也有类似的经历,欢迎随时交流!我们一起进步,一起成长! --- 希望这篇文章对你有所帮助,如果有任何疑问或者想要了解更多细节,请随时告诉我哦!
2025-03-22 15:39:31
93
风中飘零
Hadoop
...,随着云计算和大数据技术的快速发展,数据安全与隐私保护成为全球关注的焦点。特别是在跨境数据流动日益频繁的背景下,如何确保数据在不同系统间的高效迁移同时兼顾安全性,已经成为企业和政府必须面对的重大课题。就在上周,欧盟委员会发布了一份关于加强数据跨境传输监管的新提案,旨在强化GDPR(《通用数据保护条例》)的执行力度,尤其是针对云服务提供商的跨境数据处理活动提出了更为严格的审查标准。这一举措无疑将对依赖Hadoop等分布式系统的企业带来深远影响,尤其是在涉及跨国业务的数据处理环节中,如何平衡技术创新与法律合规将成为新的挑战。 与此同时,国内也在加速推进数据安全立法进程。近日,中国信通院发布了《中国数字经济发展白皮书》,其中特别提到,在数字经济快速发展的背景下,数据要素市场化配置改革亟需解决的关键问题之一便是如何构建统一的数据流通体系。报告建议,应加快制定和完善数据分级分类管理制度,鼓励采用先进的技术手段如区块链、联邦学习等,以提升数据流动的安全性和透明度。这表明,无论是在国际还是国内层面,围绕数据安全的技术创新与政策规范都呈现出同步加强的趋势。 值得注意的是,尽管Hadoop因其强大的分布式计算能力在全球范围内得到了广泛应用,但其在实际部署过程中仍面临诸多挑战,例如如何在满足业务需求的同时避免因权限配置不当而导致的数据泄露风险。对此,专家指出,企业应当加强对员工的数据安全意识培训,同时积极引入第三方审计机制,定期评估系统内的访问控制策略是否符合最新的行业标准。此外,随着量子计算等新兴技术的发展,未来的数据加密方案也需要重新审视,以应对潜在的安全威胁。 综上所述,无论是国际法规的变化还是国内政策的调整,都在推动数据安全领域发生深刻变革。对于那些希望借助Hadoop等工具实现高效数据迁移的企业而言,只有紧跟时代步伐,不断优化自身的数据管理体系,才能在未来竞争中立于不败之地。
2025-04-29 15:54:59
77
风轻云淡
转载文章
...时代的发展,网络爬虫技术不仅被广泛应用在信息聚合、数据分析等领域,也引起了法律与伦理层面的关注。 近期,《个人信息保护法》等相关法律法规的出台,对网络爬虫的使用提出了更为严格的规范要求。例如,在未经用户授权的情况下,爬取并存储他人网站图片可能涉及侵犯版权及个人信息问题。因此,在实际操作中,除了掌握技术手段外,还需遵循相关法规,如robots.txt协议,并尊重网站的版权声明和服务条款。 同时,为了应对日益复杂的动态加载内容和反爬机制,开发者需要不断更新技术和策略,比如利用Selenium等工具模拟用户行为动态渲染页面,或者研究新的网络请求伪装方法以绕过反爬策略。此外,对于海量数据的高效爬取与存储,分布式爬虫框架(如Scrapy)以及云存储解决方案(如阿里云OSS、AWS S3)的应用也成为现代爬虫工程的重要组成部分。 总而言之,在探索网络爬虫技术深度的同时,务必关注行业动态,紧跟法规政策走向,并在实践中不断提升道德和技术双重素养,确保网络爬虫项目的合规、高效运行。
2023-06-12 10:26:04
130
转载
转载文章
...表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。 判空 对于list和map使用CollectionUtils.isEmpty()判空(null和size=0) 对于对象使用ObjectUtils.isEmpty()判定,可以尝试使用Optional.ofNullable() 对于数组使用ArrayUtils.isEmpty()判空(null和length=0) 对于字符串使用 StringUtils.isBlank()判空(null和空字符串) 工具类 使用hutool可以方便的进行文件类型的判断、唯一id(uuid,Snowflake)的生成、数据加密解密、二维码生成、图片加水印、BASE64编码解码、图片验证码等操作 集合 使用Arrays.asList()返回的list为数组的内部list,只允许遍历不允许增删,可以使用Stream流转换为list Collection和map对于仅遍历可以使用增强for循环和,但如果有删除为避免错误必须使用迭代器 foreach遍历不允许改变变量的地址,java的参数是值传递,修改了形参的地址并不影响原来的参数,故即使你修改了值也不会同步到原变量中,故操作的变量都显式或者隐式的定义为final JSON fastjson parseArray(String text, Class<T> clazz) 解析List parseObject(String text, Class<T> clazz) 解析Object JSON对于null、空白字符串、“null”会返回nullif (text == null) {return null;} else {DefaultJSONParser parser = new DefaultJSONParser(text, ParserConfig.getGlobalInstance());JSONLexer lexer = parser.lexer;int token = lexer.token();ArrayList list;if (token == 8) {lexer.nextToken(); // nextToken() => ...if ("null".equalsIgnoreCase(ident)) this.token = 8;list = null;} } String toJSONString(Object object) 将对象转为String toJSONBytes(Object object, SerializerFeature... features) 将对象转为byte[] @JSONField() 可以忽略字段serialize ,别名映射name,日期格式化format等 jackson @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 设置Date到前台的格式 @JsonIgnore SpringMVC不会向前台传递该字段 ObjectMapper mapper = new ObjectMapper();String str = mapper.writeValueAsString(admin); // 对象转JSON字符串mapper.readValue(s,Admin.class ); // JSON字符串转对象 EasyExcel 官方API https://www.yuque.com/easyexcel/doc 使用类注解@ExcelIgnoreUnannotated配合@ExcelProperty操作 @ExcelProperty可以指定表头列名,列顺序和表头的合并 @ColumnWidth(10)可以指定列宽,其长度约为(中文length3+英文length1) @DateTimeFormat(value="yyyy-MM-dd HH:mm:ss")可以指定日期格式 自定义策略实现SheetWriteHandler工作表回调接口,在afterSheetCreate()工作表创建之后方法可以 设置列宽 自定义表头 新建单元格 自定义策略实现RowWriteHandler行回调接口,在afterRowDispose()行操作完之后方法可以 设置行高 设置行样式 自定义策略实现CustomerCellHandler单元格回调接口,在afterCellDispose()单元格操作完之后方法可以 根据行号,列宽甚至是单元格的值来设置单元格样式 可以对单元格的值获取和修改 样式通常包括内容格式、批注、背景色、自动换行、平和垂直居中、边框大小和颜色、字体实例(格式,颜色,大小,加粗等)等 自定义策略继承AbstractMergeStrategy单元格合并抽象类,在merge()方法中可以通过CellRangeAddress合并单元格 过于复杂的表格可以使用模板,配合写出write和填充fill一起使用 Mybatis 在mapper方法的@select中也是可以直接书写动态SQL的,但要使用<script></script>包裹,这样就不用在java文件和xml文件切换了,将@select中包裹的代码直接放到浏览器的控制台输出后会自动转义\n,\t,+,"等 动态sql中“<” 和 “>” 号要用转义字符 “<” 和 ”>“ (分号要带) 动态sql中test中表达式通常使用 test=“id != null and id != ‘’”,要注意的是字符串不能直接识别单引号,有两种方法使用id==“1001"或者id==‘1001’.toString(),另外参数如果是boolean,可以直接使用test=”!flag",如果判定集合的话可以使用 test=“list != null and list.size>0” 返回数据类型为Map只能接收一条记录,字段为键名,字段值为值,但通常是用实体类接收,或是使用注解@MapKey来进行每条记录的映射,效果等同于List用Stream流转Map foreach遍历list collection=“list” item=“vo” separator="," open="(" close=")"> {vo.id} foreach遍历map collection=“map” index=“key” item=“value”,{key}获取建,{value}获取值,$亦可 collection=“map.entrySet()” index=“key” item=“value”,同上 collection=“map.keys” item=“key”,{key}为键 不要使用where 1=1,使用动态where拼接,会自动剔除where后多余的and和or 单个参数时无论基本和引用并且未使用在动态SQL可以不加参数注解@Param,但一旦参数大于一个或者参数在动态SQL中使用就必须加@Param 并不是直接把参数加引号,而是变成?的形式交给prepareStatement处理,$直接使用值,当ORDER BY诸如此类不需要加引号的参数时,使用$代替,但为避免sql注入,该参数不能交由用户控制 Plus 官方API https://baomidou.com/guide/ @TableName 表名 @TableField(strategy = FieldStrategy.IGNORED) 更新不会忽略NULL值 @TableField(exist = false)表明该字段非数据字段,否则新增更新会报错 MybatisPlus对于单表的操作还是非常优秀的,在对单表进行新增或者更新的时候经常使用,但对于单表的查询业务上很少出现仅仅查询一张表的情况,但也会有,如果条件不大于3个还是可以使用的,多了倒没有直接写SQL来的方便了 MybatisPlus的批量插入也是通过for循环插入的,还是建议使用Mybatis的动态foreach进行批量插入 MybatisPlus的分页器会对方法中的参数判断,如果存在分页对象就先查询总数看是否大于0,然后拼接当前的数据库limit语句,所以如果我们分页对象为null,就可以实现不分页查询 Object paramObj = boundSql.getParameterObject();IPage page = null;if (paramObj instanceof IPage) { ……public static String getOriginalCountSql(String originalSql) {return String.format("SELECT COUNT(1) FROM ( %s ) TOTAL", originalSql);} ……originalSql = DialectFactory.buildPaginationSql(page, buildSql, dbType, this.dialectClazz); ……public String buildPaginationSql(String originalSql, long offset, long limit) {StringBuilder sql = new StringBuilder(originalSql);sql.append(" LIMIT ").append(offset).append(",").append(limit);return sql.toString();} IDEA 插件 Lombok : 快速生成getter、setter等 Alibaba Java Coding Guidelines :阿里规约扫描 Rainbow Brackets :彩色括号 HighlightBracketPair :高亮提示 MyBatisX :mabatisPlus提供的xml和mapper转换的插件,小鸟图标 CamelCase :大小写、驼峰、下划线、中划线转换插件 使用shift+Alt+u进行转换(很方便) 可以在Editor中设置CamelCase的转换,一般只保留下划线和驼峰两种 String Manipulation :字符串工具(未使用) RestfulToolkit http :Restful请求工具 打开idea,在右侧边栏会有一个标签(RestServices),打开可以看到里面是url路径 ctrl+\或者ctrl+alt+n会检索路径 Ctrl + Enter格式化json 没有记忆功能,也不能加token,只是查找请求路径使用 easycode :代码生成工具(个人觉得很好用,常用于生成实体类) 支持自定义模板 支持添加自定义列,不影响数据库 支持多表同时生成 支持自定义类型映射 支持配置导入导出 支持动态调试 支持自定义属性 Power Mode 11 :打字特效(纯属装逼) Nyan Progress Bar :漂亮的进度条(纯属装逼) Other Vo:数据持久化模型 Query:数据查询模型 Dto:数据传输模型 本篇文章为转载内容。原文链接:https://blog.csdn.net/qq_40910781/article/details/111416185。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-05-26 23:30:52
268
转载
转载文章
...的影响。 2. 行业实践案例:今年年初,某大型商业银行在其年度报告中分享了运用大数据与人工智能技术优化信用卡业务的实践经验,其中重点介绍了如何通过构建多元线性回归模型及正则化方法处理信贷风险评估和客户消费潜力预测问题,这一实例为业界提供了宝贵借鉴。 3. 监管政策影响:随着数据隐私保护法规(例如欧盟GDPR、中国个人信息保护法)的出台和完善,金融机构在利用用户数据进行信用消费预测时面临更多挑战。《经济学人》杂志的一篇文章对此进行了深度解读,探讨了在严格遵守法规的前提下,如何合法合规地挖掘数据价值以提高预测准确性。 4. 数据科学工具更新:Python生态中的Pandas、Statsmodels等库不断迭代升级,为数据分析工作者提供了更为强大的功能支持。最近,Scikit-learn发布了新版更新,强化了其在回归模型诊断、正则化模型训练等方面的性能,值得广大数据科学家关注并应用于实际项目中。 综上所述,了解前沿学术研究成果、掌握行业最佳实践、关注法律法规变化以及跟踪数据科学工具更新,都将有助于深化您在信用卡消费预测领域的专业素养,并为解决实际业务问题提供有力支持。
2023-11-23 15:52:56
106
转载
转载文章
...议访问和读写PLC的技术实现后,进一步的延伸阅读可以聚焦于当前工业4.0及智能制造背景下,OPC UA在全球自动化领域的最新应用案例和发展趋势。 近期,国际自动化巨头如西门子、罗克韦尔自动化等公司持续深化与OPC UA标准的合作,将其融入到自家的工业通讯解决方案中。例如,西门子在其TIA博途(TIA Portal)V17版本中集成了对OPC UA更全面的支持,允许用户更加便捷地配置OPC UA服务器,并确保数据安全、实时且高效地在不同层级的自动化系统间传输。 同时,随着物联网(IoT)和工业互联网的发展,OPC UA作为跨平台、高安全性的通讯标准,在云计算、边缘计算以及各类工业场景中的应用日益广泛。诸如微软Azure IoT Edge等云服务已实现对OPC UA的原生支持,使得工厂设备能够无缝对接云端,实现远程监控与智能决策。 此外,德国联邦经济事务和能源部正积极推动“工业4.0组件”的标准化进程,其中OPC UA扮演着核心角色,为实现生产设备间互操作性提供关键支撑。最新的OPC UA规范也在不断迭代更新,以满足未来工厂智能化、网络化的需求,如适应时间敏感网络(TSN)、增强信息安全机制等。 综上所述,深入研究OPC UA的实际应用场景及其在国内外工业领域内的政策导向和技术革新,对于理解和掌握现代工业通信技术的发展具有重要指导意义。紧跟行业动态,了解OPC UA如何赋能制造业数字化转型,将有助于我们更好地应对未来挑战并抓住机遇。
2023-05-10 18:43:00
269
转载
转载文章
...表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。 注:本文是【ASP.NET Identity系列教程】的第三篇。本系列教程详细、完整、深入地介绍了微软的ASP.NET Identity技术,描述了如何运用ASP.NET Identity实现应用程序的用户管理,以及实现应用程序的认证与授权等相关技术,译者希望本系列教程能成为掌握ASP.NET Identity技术的一份完整而有价值的资料。读者若是能够按照文章的描述,一边阅读、一边实践、一边理解,定能有意想不到的巨大收获!希望本系列博文能够得到广大园友的高度推荐。 15 Advanced ASP.NET Identity 15 ASP.NET Identity高级技术 In this chapter, I finish my description of ASP.NET Identity by showing you some of the advanced features it offers. I demonstrate how you can extend the database schema by defining custom properties on the user class and how to use database migrations to apply those properties without deleting the data in the ASP.NET Identity database. I also explain how ASP.NET Identity supports the concept of claims and demonstrates how they can be used to flexibly authorize access to action methods. I finish the chapter—and the book—by showing you how ASP.NET Identity makes it easy to authenticate users through third parties. I demonstrate authentication with Google accounts, but ASP.NET Identity has built-in support for Microsoft, Facebook, and Twitter accounts as well. Table 15-1 summarizes this chapter. 本章将完成对ASP.NET Identity的描述,向你展示它所提供的一些高级特性。我将演示,你可以扩展ASP.NET Identity的数据库架构,其办法是在用户类上定义一些自定义属性。也会演示如何使用数据库迁移,这样可以运用自定义属性,而不必删除ASP.NET Identity数据库中的数据。还会解释ASP.NET Identity如何支持声明(Claims)概念,并演示如何将它们灵活地用来对动作方法进行授权访问。最后向你展示ASP.NET Identity很容易通过第三方部件来认证用户,以此结束本章以及本书。将要演示的是使用Google账号认证,但ASP.NET Identity对于Microsoft、Facebook以及Twitter账号,都有内建的支持。表15-1是本章概要。 Table 15-1. Chapter Summary 表15-1. 本章概要 Problem 问题 Solution 解决方案 Listing 清单号 Store additional information about users. 存储用户的附加信息 Define custom user properties. 定义自定义用户属性 1–3, 8–11 Update the database schema without deleting user data. 更新数据库架构而不删除用户数据 Perform a database migration. 执行数据库迁移 4–7 Perform fine-grained authorization. 执行细粒度授权 Use claims. 使用声明(Claims) 12–14 Add claims about a user. 添加用户的声明(Claims) Use the ClaimsIdentity.AddClaims method. 使用ClaimsIdentity.AddClaims方法 15–19 Authorize access based on claim values. 基于声明(Claims)值授权访问 Create a custom authorization filter attribute. 创建一个自定义的授权过滤器注解属性 20–21 Authenticate through a third party. 通过第三方认证 Install the NuGet package for the authentication provider, redirect requests to that provider, and specify a callback URL that creates the user account. 安装认证提供器的NuGet包,将请求重定向到该提供器,并指定一个创建用户账号的回调URL。 22–25 15.1 Preparing the Example Project 15.1 准备示例项目 In this chapter, I am going to continue working on the Users project I created in Chapter 13 and enhanced in Chapter 14. No changes to the application are required, but start the application and make sure that there are users in the database. Figure 15-1 shows the state of my database, which contains the users Admin, Alice, Bob, and Joe from the previous chapter. To check the users, start the application and request the /Admin/Index URL and authenticate as the Admin user. 本章打算继续使用第13章创建并在第14章增强的Users项目。对应用程序无需做什么改变,但需要启动应用程序,并确保数据库中有一些用户。图15-1显示了数据库的状态,它含有上一章的用户Admin、Alice、Bob以及Joe。为了检查用户,请启动应用程序,请求/Admin/Index URL,并以Admin用户进行认证。 Figure 15-1. The initial users in the Identity database 图15-1. Identity数据库中的最初用户 I also need some roles for this chapter. I used the RoleAdmin controller to create roles called Users and Employees and assigned the users to those roles, as described in Table 15-2. 本章还需要一些角色。我用RoleAdmin控制器创建了角色Users和Employees,并为这些角色指定了一些用户,如表15-2所示。 Table 15-2. The Types of Web Forms Code Nuggets 表15-2. 角色及成员(作者将此表的标题写错了——译者注) Role 角色 Members 成员 Users Alice, Joe Employees Alice, Bob Figure 15-2 shows the required role configuration displayed by the RoleAdmin controller. 图15-2显示了由RoleAdmin控制器所显示出来的必要的角色配置。 Figure 15-2. Configuring the roles required for this chapter 图15-2. 配置本章所需的角色 15.2 Adding Custom User Properties 15.2 添加自定义用户属性 When I created the AppUser class to represent users in Chapter 13, I noted that the base class defined a basic set of properties to describe the user, such as e-mail address and telephone number. Most applications need to store more information about users, including persistent application preferences and details such as addresses—in short, any data that is useful to running the application and that should last between sessions. In ASP.NET Membership, this was handled through the user profile system, but ASP.NET Identity takes a different approach. 我在第13章创建AppUser类来表示用户时曾做过说明,基类定义了一组描述用户的基本属性,如E-mail地址、电话号码等。大多数应用程序还需要存储用户的更多信息,包括持久化应用程序爱好以及地址等细节——简言之,需要存储对运行应用程序有用并且在各次会话之间应当保持的任何数据。在ASP.NET Membership中,这是通过用户资料(User Profile)系统来处理的,但ASP.NET Identity采取了一种不同的办法。 Because the ASP.NET Identity system uses Entity Framework to store its data by default, defining additional user information is just a matter of adding properties to the user class and letting the Code First feature create the database schema required to store them. Table 15-3 puts custom user properties in context. 因为ASP.NET Identity默认是使用Entity Framework来存储其数据的,定义附加的用户信息只不过是给用户类添加属性的事情,然后让Code First特性去创建需要存储它们的数据库架构即可。表15-3描述了自定义用户属性的情形。 Table 15-3. Putting Cusotm User Properties in Context 表15-3. 自定义用户属性的情形 Question 问题 Answer 回答 What is it? 什么是自定义用户属性? Custom user properties allow you to store additional information about your users, including their preferences and settings. 自定义用户属性让你能够存储附加的用户信息,包括他们的爱好和设置。 Why should I care? 为何要关心它? A persistent store of settings means that the user doesn’t have to provide the same information each time they log in to the application. 设置的持久化存储意味着,用户不必每次登录到应用程序时都提供同样的信息。 How is it used by the MVC framework? 在MVC框架中如何使用它? This feature isn’t used directly by the MVC framework, but it is available for use in action methods. 此特性不是由MVC框架直接使用的,但它在动作方法中使用是有效的。 15.2.1 Defining Custom Properties 15.2.1 定义自定义属性 Listing 15-1 shows how I added a simple property to the AppUser class to represent the city in which the user lives. 清单15-1演示了如何给AppUser类添加一个简单的属性,用以表示用户生活的城市。 Listing 15-1. Adding a Property in the AppUser.cs File 清单15-1. 在AppUser.cs文件中添加属性 using System;using Microsoft.AspNet.Identity.EntityFramework;namespace Users.Models { public enum Cities {LONDON, PARIS, CHICAGO}public class AppUser : IdentityUser {public Cities City { get; set; } }} I have defined an enumeration called Cities that defines values for some large cities and added a property called City to the AppUser class. To allow the user to view and edit their City property, I added actions to the Home controller, as shown in Listing 15-2. 这里定义了一个枚举,名称为Cities,它定义了一些大城市的值,另外给AppUser类添加了一个名称为City的属性。为了让用户能够查看和编辑City属性,给Home控制器添加了几个动作方法,如清单15-2所示。 Listing 15-2. Adding Support for Custom User Properties in the HomeController.cs File 清单15-2. 在HomeController.cs文件中添加对自定义属性的支持 using System.Web.Mvc;using System.Collections.Generic;using System.Web;using System.Security.Principal;using System.Threading.Tasks;using Users.Infrastructure;using Microsoft.AspNet.Identity;using Microsoft.AspNet.Identity.Owin;using Users.Models;namespace Users.Controllers {public class HomeController : Controller {[Authorize]public ActionResult Index() {return View(GetData("Index"));}[Authorize(Roles = "Users")]public ActionResult OtherAction() {return View("Index", GetData("OtherAction"));}private Dictionary<string, object> GetData(string actionName) {Dictionary<string, object> dict= new Dictionary<string, object>();dict.Add("Action", actionName);dict.Add("User", HttpContext.User.Identity.Name);dict.Add("Authenticated", HttpContext.User.Identity.IsAuthenticated);dict.Add("Auth Type", HttpContext.User.Identity.AuthenticationType);dict.Add("In Users Role", HttpContext.User.IsInRole("Users"));return dict;} [Authorize]public ActionResult UserProps() {return View(CurrentUser);}[Authorize][HttpPost]public async Task<ActionResult> UserProps(Cities city) {AppUser user = CurrentUser;user.City = city;await UserManager.UpdateAsync(user);return View(user);}private AppUser CurrentUser {get {return UserManager.FindByName(HttpContext.User.Identity.Name);} }private AppUserManager UserManager {get {return HttpContext.GetOwinContext().GetUserManager<AppUserManager>();} }} } I added a CurrentUser property that uses the AppUserManager class to retrieve an AppUser instance to represent the current user. I pass the AppUser object as the view model object in the GET version of the UserProps action method, and the POST method uses it to update the value of the new City property. Listing 15-3 shows the UserProps.cshtml view, which displays the City property value and contains a form to change it. 我添加了一个CurrentUser属性,它使用AppUserManager类接收了表示当前用户的AppUser实例。在GET版本的UserProps动作方法中,传递了这个AppUser对象作为视图模型。而在POST版的方法中用它更新了City属性的值。清单15-3显示了UserProps.cshtml视图,它显示了City属性的值,并包含一个修改它的表单。 Listing 15-3. The Contents of the UserProps.cshtml File in the Views/Home Folder 清单15-3. Views/Home文件夹中UserProps.cshtml文件的内容 @using Users.Models@model AppUser@{ ViewBag.Title = "UserProps";}<div class="panel panel-primary"><div class="panel-heading">Custom User Properties</div><table class="table table-striped"><tr><th>City</th><td>@Model.City</td></tr></table></div> @using (Html.BeginForm()) {<div class="form-group"><label>City</label>@Html.DropDownListFor(x => x.City, new SelectList(Enum.GetNames(typeof(Cities))))</div><button class="btn btn-primary" type="submit">Save</button>} Caution Don’t start the application when you have created the view. In the sections that follow, I demonstrate how to preserve the contents of the database, and if you start the application now, the ASP.NET Identity users will be deleted. 警告:创建了视图之后不要启动应用程序。在以下小节中,将演示如何保留数据库的内容,如果现在启动应用程序,将会删除ASP.NET Identity的用户。 15.2.2 Preparing for Database Migration 15.2.2 准备数据库迁移 The default behavior for the Entity Framework Code First feature is to drop the tables in the database and re-create them whenever classes that drive the schema have changed. You saw this in Chapter 14 when I added support for roles: When the application was started, the database was reset, and the user accounts were lost. Entity Framework Code First特性的默认行为是,一旦修改了派生数据库架构的类,便会删除数据库中的数据表,并重新创建它们。在第14章可以看到这种情况,在我添加角色支持时:当重启应用程序后,数据库被重置,用户账号也丢失。 Don’t start the application yet, but if you were to do so, you would see a similar effect. Deleting data during development is usually not a problem, but doing so in a production setting is usually disastrous because it deletes all of the real user accounts and causes a panic while the backups are restored. In this section, I am going to demonstrate how to use the database migration feature, which updates a Code First schema in a less brutal manner and preserves the existing data it contains. 不要启动应用程序,但如果你这么做了,会看到类似的效果。在开发期间删除数据没什么问题,但如果在产品设置中这么做了,通常是灾难性的,因为它会删除所有真实的用户账号,而备份恢复是很痛苦的事。在本小节中,我打算演示如何使用数据库迁移特性,它能以比较温和的方式更新Code First的架构,并保留架构中的已有数据。 The first step is to issue the following command in the Visual Studio Package Manager Console: 第一个步骤是在Visual Studio的“Package Manager Console(包管理器控制台)”中发布以下命令: Enable-Migrations –EnableAutomaticMigrations This enables the database migration support and creates a Migrations folder in the Solution Explorer that contains a Configuration.cs class file, the contents of which are shown in Listing 15-4. 它启用了数据库的迁移支持,并在“Solution Explorer(解决方案资源管理器)”创建一个Migrations文件夹,其中含有一个Configuration.cs类文件,内容如清单15-4所示。 Listing 15-4. The Contents of the Configuration.cs File 清单15-4. Configuration.cs文件的内容 namespace Users.Migrations {using System;using System.Data.Entity;using System.Data.Entity.Migrations;using System.Linq;internal sealed class Configuration: DbMigrationsConfiguration<Users.Infrastructure.AppIdentityDbContext> {public Configuration() {AutomaticMigrationsEnabled = true;ContextKey = "Users.Infrastructure.AppIdentityDbContext";}protected override void Seed(Users.Infrastructure.AppIdentityDbContext context) {// This method will be called after migrating to the latest version.// 此方法将在迁移到最新版本时调用// You can use the DbSet<T>.AddOrUpdate() helper extension method// to avoid creating duplicate seed data. E.g.// 例如,你可以使用DbSet<T>.AddOrUpdate()辅助器方法来避免创建重复的种子数据//// context.People.AddOrUpdate(// p => p.FullName,// new Person { FullName = "Andrew Peters" },// new Person { FullName = "Brice Lambson" },// new Person { FullName = "Rowan Miller" }// );//} }} Tip You might be wondering why you are entering a database migration command into the console used to manage NuGet packages. The answer is that the Package Manager Console is really PowerShell, which is a general-purpose tool that is mislabeled by Visual Studio. You can use the console to issue a wide range of helpful commands. See http://go.microsoft.com/fwlink/?LinkID=108518 for details. 提示:你可能会觉得奇怪,为什么要在管理NuGet包的控制台中输入数据库迁移的命令?答案是“Package Manager Console(包管理控制台)”是真正的PowerShell,这是Visual studio冒用的一个通用工具。你可以使用此控制台发送大量的有用命令,详见http://go.microsoft.com/fwlink/?LinkID=108518。 The class will be used to migrate existing content in the database to the new schema, and the Seed method will be called to provide an opportunity to update the existing database records. In Listing 15-5, you can see how I have used the Seed method to set a default value for the new City property I added to the AppUser class. (I have also updated the class file to reflect my usual coding style.) 这个类将用于把数据库中的现有内容迁移到新的数据库架构,Seed方法的调用为更新现有数据库记录提供了机会。在清单15-5中可以看到,我如何用Seed方法为新的City属性设置默认值,City是添加到AppUser类中自定义属性。(为了体现我一贯的编码风格,我对这个类文件也进行了更新。) Listing 15-5. Managing Existing Content in the Configuration.cs File 清单15-5. 在Configuration.cs文件中管理已有内容 using System.Data.Entity.Migrations;using Microsoft.AspNet.Identity;using Microsoft.AspNet.Identity.EntityFramework;using Users.Infrastructure;using Users.Models;namespace Users.Migrations {internal sealed class Configuration: DbMigrationsConfiguration<AppIdentityDbContext> {public Configuration() {AutomaticMigrationsEnabled = true;ContextKey = "Users.Infrastructure.AppIdentityDbContext";}protected override void Seed(AppIdentityDbContext context) {AppUserManager userMgr = new AppUserManager(new UserStore<AppUser>(context));AppRoleManager roleMgr = new AppRoleManager(new RoleStore<AppRole>(context)); string roleName = "Administrators";string userName = "Admin";string password = "MySecret";string email = "admin@example.com";if (!roleMgr.RoleExists(roleName)) {roleMgr.Create(new AppRole(roleName));}AppUser user = userMgr.FindByName(userName);if (user == null) {userMgr.Create(new AppUser { UserName = userName, Email = email },password);user = userMgr.FindByName(userName);}if (!userMgr.IsInRole(user.Id, roleName)) {userMgr.AddToRole(user.Id, roleName);}foreach (AppUser dbUser in userMgr.Users) {dbUser.City = Cities.PARIS;}context.SaveChanges();} }} You will notice that much of the code that I added to the Seed method is taken from the IdentityDbInit class, which I used to seed the database with an administration user in Chapter 14. This is because the new Configuration class added to support database migrations will replace the seeding function of the IdentityDbInit class, which I’ll update shortly. Aside from ensuring that there is an admin user, the statements in the Seed method that are important are the ones that set the initial value for the City property I added to the AppUser class, as follows: 你可能会注意到,添加到Seed方法中的许多代码取自于IdentityDbInit类,在第14章中我用这个类将管理用户植入了数据库。这是因为这个新添加的、用以支持数据库迁移的Configuration类,将代替IdentityDbInit类的种植功能,我很快便会更新这个类。除了要确保有admin用户之外,在Seed方法中的重要语句是那些为AppUser类的City属性设置初值的语句,如下所示: ...foreach (AppUser dbUser in userMgr.Users) { dbUser.City = Cities.PARIS;}context.SaveChanges();... You don’t have to set a default value for new properties—I just wanted to demonstrate that the Seed method in the Configuration class can be used to update the existing user records in the database. 你不一定要为新属性设置默认值——这里只是想演示Configuration类中的Seed方法,可以用它更新数据库中的已有用户记录。 Caution Be careful when setting values for properties in the Seed method for real projects because the values will be applied every time you change the schema, overriding any values that the user has set since the last schema update was performed. I set the value of the City property just to demonstrate that it can be done. 警告:在用于真实项目的Seed方法中为属性设置值时要小心,因为你每一次修改架构时,都会运用这些值,这会将自执行上一次架构更新之后,用户设置的任何数据覆盖掉。这里设置City属性的值只是为了演示它能够这么做。 Changing the Database Context Class 修改数据库上下文类 The reason that I added the seeding code to the Configuration class is that I need to change the IdentityDbInit class. At present, the IdentityDbInit class is derived from the descriptively named DropCreateDatabaseIfModelChanges<AppIdentityDbContext> class, which, as you might imagine, drops the entire database when the Code First classes change. Listing 15-6 shows the changes I made to the IdentityDbInit class to prevent it from affecting the database. 在Configuration类中添加种植代码的原因是我需要修改IdentityDbInit类。此时,IdentityDbInit类派生于描述性命名的DropCreateDatabaseIfModelChanges<AppIdentityDbContext> 类,和你相像的一样,它会在Code First类改变时删除整个数据库。清单15-6显示了我对IdentityDbInit类所做的修改,以防止它影响数据库。 Listing 15-6. Preventing Database Schema Changes in the AppIdentityDbContext.cs File 清单15-6. 在AppIdentityDbContext.cs文件是阻止数据库架构变化 using System.Data.Entity;using Microsoft.AspNet.Identity.EntityFramework;using Users.Models;using Microsoft.AspNet.Identity; namespace Users.Infrastructure {public class AppIdentityDbContext : IdentityDbContext<AppUser> {public AppIdentityDbContext() : base("IdentityDb") { }static AppIdentityDbContext() {Database.SetInitializer<AppIdentityDbContext>(new IdentityDbInit());}public static AppIdentityDbContext Create() {return new AppIdentityDbContext();} } public class IdentityDbInit : NullDatabaseInitializer<AppIdentityDbContext> {} } I have removed the methods defined by the class and changed its base to NullDatabaseInitializer<AppIdentityDbContext> , which prevents the schema from being altered. 我删除了这个类中所定义的方法,并将它的基类改为NullDatabaseInitializer<AppIdentityDbContext> ,它可以防止架构修改。 15.2.3 Performing the Migration 15.2.3 执行迁移 All that remains is to generate and apply the migration. First, run the following command in the Package Manager Console: 剩下的事情只是生成并运用迁移了。首先,在“Package Manager Console(包管理器控制台)”中执行以下命令: Add-Migration CityProperty This creates a new migration called CityProperty (I like my migration names to reflect the changes I made). A class new file will be added to the Migrations folder, and its name reflects the time at which the command was run and the name of the migration. My file is called 201402262244036_CityProperty.cs, for example. The contents of this file contain the details of how Entity Framework will change the database during the migration, as shown in Listing 15-7. 这创建了一个名称为CityProperty的新迁移(我比较喜欢让迁移的名称反映出我所做的修改)。这会在文件夹中添加一个新的类文件,而且其命名会反映出该命令执行的时间以及迁移名称,例如,我的这个文件名称为201402262244036_CityProperty.cs。该文件的内容含有迁移期间Entity Framework修改数据库的细节,如清单15-7所示。 Listing 15-7. The Contents of the 201402262244036_CityProperty.cs File 清单15-7. 201402262244036_CityProperty.cs文件的内容 namespace Users.Migrations {using System;using System.Data.Entity.Migrations; public partial class Init : DbMigration {public override void Up() {AddColumn("dbo.AspNetUsers", "City", c => c.Int(nullable: false));}public override void Down() {DropColumn("dbo.AspNetUsers", "City");} }} The Up method describes the changes that have to be made to the schema when the database is upgraded, which in this case means adding a City column to the AspNetUsers table, which is the one that is used to store user records in the ASP.NET Identity database. Up方法描述了在数据库升级时,需要对架构所做的修改,在这个例子中,意味着要在AspNetUsers数据表中添加City数据列,该数据表是ASP.NET Identity数据库用来存储用户记录的。 The final step is to perform the migration. Without starting the application, run the following command in the Package Manager Console: 最后一步是执行迁移。无需启动应用程序,只需在“Package Manager Console(包管理器控制台)”中运行以下命令即可: Update-Database –TargetMigration CityProperty The database schema will be modified, and the code in the Configuration.Seed method will be executed. The existing user accounts will have been preserved and enhanced with a City property (which I set to Paris in the Seed method). 这会修改数据库架构,并执行Configuration.Seed方法中的代码。已有用户账号会被保留,且增强了City属性(我在Seed方法中已将其设置为“Paris”)。 15.2.4 Testing the Migration 15.2.4 测试迁移 To test the effect of the migration, start the application, navigate to the /Home/UserProps URL, and authenticate as one of the Identity users (for example, as Alice with the password MySecret). Once authenticated, you will see the current value of the City property for the user and have the opportunity to change it, as shown in Figure 15-3. 为了测试迁移的效果,启动应用程序,导航到/Home/UserProps URL,并以Identity中的用户(例如Alice,口令MySecret)进行认证。一旦已被认证,便会看到该用户City属性的当前值,并可以对其进行修改,如图15-3所示。 Figure 15-3. Displaying and changing a custom user property 图15-3. 显示和个性自定义用户属性 15.2.5 Defining an Additional Property 15.2.5 定义附加属性 Now that database migrations are set up, I am going to define a further property just to demonstrate how subsequent changes are handled and to show a more useful (and less dangerous) example of using the Configuration.Seed method. Listing 15-8 shows how I added a Country property to the AppUser class. 现在,已经建立了数据库迁移,我打算再定义一个属性,这恰恰演示了如何处理持续不断的修改,也为了演示Configuration.Seed方法更有用(至少无害)的示例。清单15-8显示了我在AppUser类上添加了一个Country属性。 Listing 15-8. Adding Another Property in the AppUserModels.cs File 清单15-8. 在AppUserModels.cs文件中添加另一个属性 using System;using Microsoft.AspNet.Identity.EntityFramework; namespace Users.Models {public enum Cities {LONDON, PARIS, CHICAGO} public enum Countries {NONE, UK, FRANCE, USA}public class AppUser : IdentityUser {public Cities City { get; set; }public Countries Country { get; set; }public void SetCountryFromCity(Cities city) {switch (city) {case Cities.LONDON:Country = Countries.UK;break;case Cities.PARIS:Country = Countries.FRANCE;break;case Cities.CHICAGO:Country = Countries.USA;break;default:Country = Countries.NONE;break;} }} } I have added an enumeration to define the country names and a helper method that selects a country value based on the City property. Listing 15-9 shows the change I made to the Configuration class so that the Seed method sets the Country property based on the City, but only if the value of Country is NONE (which it will be for all users when the database is migrated because the Entity Framework sets enumeration columns to the first value). 我已经添加了一个枚举,它定义了国家名称。还添加了一个辅助器方法,它可以根据City属性选择一个国家。清单15-9显示了对Configuration类所做的修改,以使Seed方法根据City设置Country属性,但只当Country为NONE时才进行设置(在迁移数据库时,所有用户都是NONE,因为Entity Framework会将枚举列设置为枚举的第一个值)。 Listing 15-9. Modifying the Database Seed in the Configuration.cs File 清单15-9. 在Configuration.cs文件中修改数据库种子 using System.Data.Entity.Migrations;using Microsoft.AspNet.Identity;using Microsoft.AspNet.Identity.EntityFramework;using Users.Infrastructure;using Users.Models; namespace Users.Migrations {internal sealed class Configuration: DbMigrationsConfiguration<AppIdentityDbContext> {public Configuration() {AutomaticMigrationsEnabled = true;ContextKey = "Users.Infrastructure.AppIdentityDbContext";}protected override void Seed(AppIdentityDbContext context) {AppUserManager userMgr = new AppUserManager(new UserStore<AppUser>(context));AppRoleManager roleMgr = new AppRoleManager(new RoleStore<AppRole>(context)); string roleName = "Administrators";string userName = "Admin";string password = "MySecret";string email = "admin@example.com";if (!roleMgr.RoleExists(roleName)) {roleMgr.Create(new AppRole(roleName));}AppUser user = userMgr.FindByName(userName);if (user == null) {userMgr.Create(new AppUser { UserName = userName, Email = email },password);user = userMgr.FindByName(userName);}if (!userMgr.IsInRole(user.Id, roleName)) {userMgr.AddToRole(user.Id, roleName);} foreach (AppUser dbUser in userMgr.Users) {if (dbUser.Country == Countries.NONE) {dbUser.SetCountryFromCity(dbUser.City);} }context.SaveChanges();} }} This kind of seeding is more useful in a real project because it will set a value for the Country property only if one has not already been set—subsequent migrations won’t be affected, and user selections won’t be lost. 这种种植在实际项目中会更有用,因为它只会在Country属性未设置时,才会设置Country属性的值——后继的迁移不会受到影响,因此不会失去用户的选择。 1. Adding Application Support 1. 添加应用程序支持 There is no point defining additional user properties if they are not available in the application, so Listing 15-10 shows the change I made to the Views/Home/UserProps.cshtml file to display the value of the Country property. 应用程序中如果没有定义附加属性的地方,则附加属性就无法使用了,因此,清单15-10显示了我对Views/Home/UserProps.cshtml文件的修改,以显示Country属性的值。 Listing 15-10. Displaying an Additional Property in the UserProps.cshtml File 清单15-10. 在UserProps.cshtml文件中显示附加属性 @using Users.Models@model AppUser@{ ViewBag.Title = "UserProps";} <div class="panel panel-primary"><div class="panel-heading">Custom User Properties</div><table class="table table-striped"><tr><th>City</th><td>@Model.City</td></tr> <tr><th>Country</th><td>@Model.Country</td></tr></table></div>@using (Html.BeginForm()) {<div class="form-group"><label>City</label>@Html.DropDownListFor(x => x.City, new SelectList(Enum.GetNames(typeof(Cities))))</div><button class="btn btn-primary" type="submit">Save</button>} Listing 15-11 shows the corresponding change I made to the Home controller to update the Country property when the City value changes. 为了在City值变化时能够更新Country属性,清单15-11显示了我对Home控制器所做的相应修改。 Listing 15-11. Setting Custom Properties in the HomeController.cs File 清单15-11. 在HomeController.cs文件中设置自定义属性 using System.Web.Mvc;using System.Collections.Generic;using System.Web;using System.Security.Principal;using System.Threading.Tasks;using Users.Infrastructure;using Microsoft.AspNet.Identity;using Microsoft.AspNet.Identity.Owin;using Users.Models; namespace Users.Controllers {public class HomeController : Controller {// ...other action methods omitted for brevity...// ...出于简化,这里忽略了其他动作方法... [Authorize]public ActionResult UserProps() {return View(CurrentUser);}[Authorize][HttpPost]public async Task<ActionResult> UserProps(Cities city) {AppUser user = CurrentUser;user.City = city;user.SetCountryFromCity(city);await UserManager.UpdateAsync(user);return View(user);}// ...properties omitted for brevity...// ...出于简化,这里忽略了一些属性...} } 2. Performing the Migration 2. 准备迁移 All that remains is to create and apply a new migration. Enter the following command into the Package Manager Console: 剩下的事情就是创建和运用新的迁移了。在“Package Manager Console(包管理器控制台)”中输入以下命令: Add-Migration CountryProperty This will generate another file in the Migrations folder that contains the instruction to add the Country column. To apply the migration, execute the following command: 这将在Migrations文件夹中生成另一个文件,它含有添加Country数据表列的指令。为了运用迁移,可执行以下命令: Update-Database –TargetMigration CountryProperty The migration will be performed, and the value of the Country property will be set based on the value of the existing City property for each user. You can check the new user property by starting the application and authenticating and navigating to the /Home/UserProps URL, as shown in Figure 15-4. 这将执行迁移,Country属性的值将根据每个用户当前的City属性进行设置。通过启动应用程序,认证并导航到/Home/UserProps URL,便可以查看新的用户属性,如图15-4所示。 Figure 15-4. Creating an additional user property 图15-4. 创建附加用户属性 Tip Although I am focused on the process of upgrading the database, you can also migrate back to a previous version by specifying an earlier migration. Use the –Force argument make changes that cause data loss, such as removing a column. 提示:虽然我们关注了升级数据库的过程,但你也可以回退到以前的版本,只需指定一个早期的迁移即可。使用-Force参数进行修改,会引起数据丢失,例如删除数据表列。 15.3 Working with Claims 15.3 使用声明(Claims) In older user-management systems, such as ASP.NET Membership, the application was assumed to be the authoritative source of all information about the user, essentially treating the application as a closed world and trusting the data that is contained within it. 在旧的用户管理系统中,例如ASP.NET Membership,应用程序被假设成是用户所有信息的权威来源,本质上将应用程序视为是一个封闭的世界,并且只信任其中所包含的数据。 This is such an ingrained approach to software development that it can be hard to recognize that’s what is happening, but you saw an example of the closed-world technique in Chapter 14 when I authenticated users against the credentials stored in the database and granted access based on the roles associated with those credentials. I did the same thing again in this chapter when I added properties to the user class. Every piece of information that I needed to manage user authentication and authorization came from within my application—and that is a perfectly satisfactory approach for many web applications, which is why I demonstrated these techniques in such depth. 这是软件开发的一种根深蒂固的方法,使人很难认识到这到底意味着什么,第14章你已看到了这种封闭世界技术的例子,根据存储在数据库中的凭据来认证用户,并根据与凭据关联在一起的角色来授权访问。本章前述在用户类上添加属性,也做了同样的事情。我管理用户认证与授权所需的每一个数据片段都来自于我的应用程序——而且这是许多Web应用程序都相当满意的一种方法,这也是我如此深入地演示这些技术的原因。 ASP.NET Identity also supports an alternative approach for dealing with users, which works well when the MVC framework application isn’t the sole source of information about users and which can be used to authorize users in more flexible and fluid ways than traditional roles allow. ASP.NET Identity还支持另一种处理用户的办法,当MVC框架的应用程序不是有关用户的唯一信息源时,这种办法会工作得很好,而且能够比传统的角色授权更为灵活且流畅的方式进行授权。 This alternative approach uses claims, and in this section I’ll describe how ASP.NET Identity supports claims-based authorization. Table 15-4 puts claims in context. 这种可选的办法使用了“Claims(声明)”,因此在本小节中,我将描述ASP.NET Identity如何支持“Claims-Based Authorization(基于声明的授权)”。表15-4描述了声明(Claims)的情形。 提示:“Claim”在英文字典中不完全是“声明”的意思,根据本文的描述,感觉把它说成“声明”也不一定合适,所以在之后的译文中基本都写成中英文并用的形式,即“声明(Claims)”。根据表15-4中的声明(Claims)的定义:声明(Claims)是关于用户的一些信息片段。一个用户的信息片段当然有很多,每一个信息片段就是一项声明(Claim),用户的所有信息片段合起来就是该用户的声明(Claims)。请读者注意该单词的单复数形式——译者注 Table 15-4. Putting Claims in Context 表15-4. 声明(Claims)的情形 Question 问题 Answer 答案 What is it? 什么是声明(Claims)? Claims are pieces of information about users that you can use to make authorization decisions. Claims can be obtained from external systems as well as from the local Identity database. 声明(Claims)是关于用户的一些信息片段,可以用它们做出授权决定。声明(Claims)可以从外部系统获取,也可以从本地的Identity数据库获取。 Why should I care? 为何要关心它? Claims can be used to flexibly authorize access to action methods. Unlike conventional roles, claims allow access to be driven by the information that describes the user. 声明(Claims)可以用来对动作方法进行灵活的授权访问。与传统的角色不同,声明(Claims)让访问能够由描述用户的信息进行驱动。 How is it used by the MVC framework? 如何在MVC框架中使用它? This feature isn’t used directly by the MVC framework, but it is integrated into the standard authorization features, such as the Authorize attribute. 这不是直接由MVC框架使用的特性,但它集成到了标准的授权特性之中,例如Authorize注解属性。 Tip you don’t have to use claims in your applications, and as Chapter 14 showed, ASP.NET Identity is perfectly happy providing an application with the authentication and authorization services without any need to understand claims at all. 提示:你在应用程序中不一定要使用声明(Claims),正如第14章所展示的那样,ASP.NET Identity能够为应用程序提供充分的认证与授权服务,而根本不需要理解声明(Claims)。 15.3.1 Understanding Claims 15.3.1 理解声明(Claims) A claim is a piece of information about the user, along with some information about where the information came from. The easiest way to unpack claims is through some practical demonstrations, without which any discussion becomes too abstract to be truly useful. To get started, I added a Claims controller to the example project, the definition of which you can see in Listing 15-12. 一项声明(Claim)是关于用户的一个信息片段(请注意这个英文单词的单复数形式——译者注),并伴有该片段出自何处的某种信息。揭开声明(Claims)含义最容易的方式是做一些实际演示,任何讨论都会过于抽象根本没有真正的用处。为此,我在示例项目中添加了一个Claims控制器,其定义如清单15-12所示。 Listing 15-12. The Contents of the ClaimsController.cs File 清单15-12. ClaimsController.cs文件的内容 using System.Security.Claims;using System.Web;using System.Web.Mvc; namespace Users.Controllers {public class ClaimsController : Controller {[Authorize]public ActionResult Index() {ClaimsIdentity ident = HttpContext.User.Identity as ClaimsIdentity;if (ident == null) {return View("Error", new string[] { "No claims available" });} else {return View(ident.Claims);} }} } Tip You may feel a little lost as I define the code for this example. Don’t worry about the details for the moment—just stick with it until you see the output from the action method and view that I define. More than anything else, that will help put claims into perspective. 提示:你或许会对我为此例定义的代码感到有点失望。此刻对此细节不必着急——只要稍事忍耐,当看到该动作方法和视图的输出便会明白。尤为重要的是,这有助于洞察声明(Claims)。 You can get the claims associated with a user in different ways. One approach is to use the Claims property defined by the user class, but in this example, I have used the HttpContext.User.Identity property to demonstrate the way that ASP.NET Identity is integrated with the rest of the ASP.NET platform. As I explained in Chapter 13, the HttpContext.User.Identity property returns an implementation of the IIdentity interface, which is a ClaimsIdentity object when working using ASP.NET Identity. The ClaimsIdentity class is defined in the System.Security.Claims namespace, and Table 15-5 shows the members it defines that are relevant to this chapter. 可以通过不同的方式获得与用户相关联的声明(Claims)。方法之一就是使用由用户类定义的Claims属性,但在这个例子中,我使用了HttpContext.User.Identity属性,目的是演示ASP.NET Identity与ASP.NET平台集成的方式(请注意这句话所表示的含义:用户类的Claims属性属于ASP.NET Identity,而HttpContext.User.Identity属性则属于ASP.NET平台。由此可见,ASP.NET Identity已经融合到了ASP.NET平台之中——译者注)。正如第13章所解释的那样,HttpContext.User.Identity属性返回IIdentity的接口实现,当使用ASP.NET Identity时,该实现是一个ClaimsIdentity对象。ClaimsIdentity类是在System.Security.Claims命名空间中定义的,表15-5显示了它所定义的与本章有关的成员。 Table 15-5. The Members Defined by the ClaimsIdentity Class 表15-5. ClaimsIdentity类所定义的成员 Name 名称 Description 描述 Claims Returns an enumeration of Claim objects representing the claims for the user. 返回表示用户声明(Claims)的Claim对象枚举 AddClaim(claim) Adds a claim to the user identity. 给用户添加一个声明(Claim) AddClaims(claims) Adds an enumeration of Claim objects to the user identity. 给用户添加Claim对象的枚举。 HasClaim(predicate) Returns true if the user identity contains a claim that matches the specified predicate. See the “Applying Claims” section for an example predicate. 如果用户含有与指定谓词匹配的声明(Claim)时,返回true。参见“运用声明(Claims)”中的示例谓词 RemoveClaim(claim) Removes a claim from the user identity. 删除用户的声明(Claim)。 Other members are available, but the ones in the table are those that are used most often in web applications, for reason that will become obvious as I demonstrate how claims fit into the wider ASP.NET platform. 还有一些可用的其它成员,但表中的这些是在Web应用程序中最常用的,随着我演示如何将声明(Claims)融入更宽泛的ASP.NET平台,它们为什么最常用就很显然了。 In Listing 15-12, I cast the IIdentity implementation to the ClaimsIdentity type and pass the enumeration of Claim objects returned by the ClaimsIdentity.Claims property to the View method. A Claim object represents a single piece of data about the user, and the Claim class defines the properties shown in Table 15-6. 在清单15-12中,我将IIdentity实现转换成了ClaimsIdentity类型,并且给View方法传递了ClaimsIdentity.Claims属性所返回的Claim对象的枚举。Claim对象所示表示的是关于用户的一个单一的数据片段,Claim类定义的属性如表15-6所示。 Table 15-6. The Properties Defined by the Claim Class 表15-6. Claim类定义的属性 Name 名称 Description 描述 Issuer Returns the name of the system that provided the claim 返回提供声明(Claim)的系统名称 Subject Returns the ClaimsIdentity object for the user who the claim refers to 返回声明(Claim)所指用户的ClaimsIdentity对象 Type Returns the type of information that the claim represents 返回声明(Claim)所表示的信息类型 Value Returns the piece of information that the claim represents 返回声明(Claim)所表示的信息片段 Listing 15-13 shows the contents of the Index.cshtml file that I created in the Views/Claims folder and that is rendered by the Index action of the Claims controller. The view adds a row to a table for each claim about the user. 清单15-13显示了我在Views/Claims文件夹中创建的Index.cshtml文件的内容,它由Claims控制器中的Index动作方法进行渲染。该视图为用户的每项声明(Claim)添加了一个表格行。 Listing 15-13. The Contents of the Index.cshtml File in the Views/Claims Folder 清单15-13. Views/Claims文件夹中Index.cshtml文件的内容 @using System.Security.Claims@using Users.Infrastructure@model IEnumerable<Claim>@{ ViewBag.Title = "Claims"; }<div class="panel panel-primary"><div class="panel-heading">Claims</div><table class="table table-striped"><tr><th>Subject</th><th>Issuer</th><th>Type</th><th>Value</th></tr>@foreach (Claim claim in Model.OrderBy(x => x.Type)) {<tr><td>@claim.Subject.Name</td><td>@claim.Issuer</td><td>@Html.ClaimType(claim.Type)</td><td>@claim.Value</td></tr>}</table></div> The value of the Claim.Type property is a URI for a Microsoft schema, which isn’t especially useful. The popular schemas are used as the values for fields in the System.Security.Claims.ClaimTypes class, so to make the output from the Index.cshtml view easier to read, I added an HTML helper to the IdentityHelpers.cs file, as shown in Listing 15-14. It is this helper that I use in the Index.cshtml file to format the value of the Claim.Type property. Claim.Type属性的值是一个微软模式(Microsoft Schema)的URI(统一资源标识符),这是特别有用的。System.Security.Claims.ClaimTypes类中字段的值使用的是流行模式(Popular Schema),因此为了使Index.cshtml视图的输出更易于阅读,我在IdentityHelpers.cs文件中添加了一个HTML辅助器,如清单15-14所示。Index.cshtml文件正是使用这个辅助器格式化了Claim.Type属性的值。 Listing 15-14. Adding a Helper to the IdentityHelpers.cs File 清单15-14. 在IdentityHelpers.cs文件中添加辅助器 using System.Web;using System.Web.Mvc;using Microsoft.AspNet.Identity.Owin;using System;using System.Linq;using System.Reflection;using System.Security.Claims;namespace Users.Infrastructure {public static class IdentityHelpers {public static MvcHtmlString GetUserName(this HtmlHelper html, string id) {AppUserManager mgr= HttpContext.Current.GetOwinContext().GetUserManager<AppUserManager>();return new MvcHtmlString(mgr.FindByIdAsync(id).Result.UserName);} public static MvcHtmlString ClaimType(this HtmlHelper html, string claimType) {FieldInfo[] fields = typeof(ClaimTypes).GetFields();foreach (FieldInfo field in fields) {if (field.GetValue(null).ToString() == claimType) {return new MvcHtmlString(field.Name);} }return new MvcHtmlString(string.Format("{0}",claimType.Split('/', '.').Last()));} }} Note The helper method isn’t at all efficient because it reflects on the fields of the ClaimType class for each claim that is displayed, but it is sufficient for my purposes in this chapter. You won’t often need to display the claim type in real applications. 注:该辅助器并非十分有效,因为它只是针对每个要显示的声明(Claim)映射出ClaimType类的字段,但对我要的目的已经足够了。在实际项目中不会经常需要显示声明(Claim)的类型。 To see why I have created a controller that uses claims without really explaining what they are, start the application, authenticate as the user Alice (with the password MySecret), and request the /Claims/Index URL. Figure 15-5 shows the content that is generated. 为了弄明白我为何要先创建一个使用声明(Claims)的控制器,而没有真正解释声明(Claims)是什么的原因,可以启动应用程序,以用户Alice进行认证(其口令是MySecret),并请求/Claims/Index URL。图15-5显示了生成的内容。 Figure 15-5. The output from the Index action of the Claims controller 图15-5. Claims控制器中Index动作的输出 It can be hard to make out the detail in the figure, so I have reproduced the content in Table 15-7. 这可能还难以认识到此图的细节,为此我在表15-7中重列了其内容。 Table 15-7. The Data Shown in Figure 15-5 表15-7. 图15-5中显示的数据 Subject(科目) Issuer(发行者) Type(类型) Value(值) Alice LOCAL AUTHORITY SecurityStamp Unique ID Alice LOCAL AUTHORITY IdentityProvider ASP.NET Identity Alice LOCAL AUTHORITY Role Employees Alice LOCAL AUTHORITY Role Users Alice LOCAL AUTHORITY Name Alice Alice LOCAL AUTHORITY NameIdentifier Alice’s user ID The table shows the most important aspect of claims, which is that I have already been using them when I implemented the traditional authentication and authorization features in Chapter 14. You can see that some of the claims relate to user identity (the Name claim is Alice, and the NameIdentifier claim is Alice’s unique user ID in my ASP.NET Identity database). 此表展示了声明(Claims)最重要的方面,这些是我在第14章中实现传统的认证和授权特性时,一直在使用的信息。可以看出,有些声明(Claims)与用户标识有关(Name声明是Alice,NameIdentifier声明是Alice在ASP.NET Identity数据库中的唯一用户ID号)。 Other claims show membership of roles—there are two Role claims in the table, reflecting the fact that Alice is assigned to both the Users and Employees roles. There is also a claim about how Alice has been authenticated: The IdentityProvider is set to ASP.NET Identity. 其他声明(Claims)显示了角色成员——表中有两个Role声明(Claim),体现出Alice被赋予了Users和Employees两个角色这一事实。还有一个是Alice已被认证的声明(Claim):IdentityProvider被设置到了ASP.NET Identity。 The difference when this information is expressed as a set of claims is that you can determine where the data came from. The Issuer property for all the claims shown in the table is set to LOCAL AUTHORITY, which indicates that the user’s identity has been established by the application. 当这种信息被表示成一组声明(Claims)时的差别是,你能够确定这些数据是从哪里来的。表中所显示的所有声明的Issuer属性(发布者)都被设置到了LOACL AUTHORITY(本地授权),这说明该用户的标识是由应用程序建立的。 So, now that you have seen some example claims, I can more easily describe what a claim is. A claim is any piece of information about a user that is available to the application, including the user’s identity and role memberships. And, as you have seen, the information I have been defining about my users in earlier chapters is automatically made available as claims by ASP.NET Identity. 因此,现在你已经看到了一些声明(Claims)示例,我可以更容易地描述声明(Claim)是什么了。一项声明(Claim)是可用于应用程序中的有关用户的一个信息片段,包括用户的标识以及角色成员等。而且,正如你所看到的,我在前几章定义的关于用户的信息,被ASP.NET Identity自动地作为声明(Claims)了。 15.3.2 Creating and Using Claims 15.3.2 创建和使用声明(Claims) Claims are interesting for two reasons. The first reason is that an application can obtain claims from multiple sources, rather than just relying on a local database for information about the user. You will see a real example of this when I show you how to authenticate users through a third-party system in the “Using Third-Party Authentication” section, but for the moment I am going to add a class to the example project that simulates a system that provides claims information. Listing 15-15 shows the contents of the LocationClaimsProvider.cs file that I added to the Infrastructure folder. 声明(Claims)比较有意思的原因有两个。第一个原因是应用程序可以从多个来源获取声明(Claims),而不是只能依靠本地数据库关于用户的信息。你将会看到一个实际的示例,在“使用第三方认证”小节中,将演示如何通过第三方系统来认证用户。不过,此刻我只打算在示例项目中添加一个类,用以模拟一个提供声明(Claims)信息的系统。清单15-15显示了我添加到Infrastructure文件夹中LocationClaimsProvider.cs文件的内容。 Listing 15-15. The Contents of the LocationClaimsProvider.cs File 清单15-15. LocationClaimsProvider.cs文件的内容 using System.Collections.Generic;using System.Security.Claims; namespace Users.Infrastructure {public static class LocationClaimsProvider {public static IEnumerable<Claim> GetClaims(ClaimsIdentity user) {List<Claim> claims = new List<Claim>();if (user.Name.ToLower() == "alice") {claims.Add(CreateClaim(ClaimTypes.PostalCode, "DC 20500"));claims.Add(CreateClaim(ClaimTypes.StateOrProvince, "DC"));} else {claims.Add(CreateClaim(ClaimTypes.PostalCode, "NY 10036"));claims.Add(CreateClaim(ClaimTypes.StateOrProvince, "NY"));}return claims;}private static Claim CreateClaim(string type, string value) {return new Claim(type, value, ClaimValueTypes.String, "RemoteClaims");} }} The GetClaims method takes a ClaimsIdentity argument and uses the Name property to create claims about the user’s ZIP code and state. This class allows me to simulate a system such as a central HR database, which would be the authoritative source of location information about staff, for example. GetClaims方法以ClaimsIdentity为参数,并使用Name属性创建了关于用户ZIP码(邮政编码)和州府的声明(Claims)。上述这个类使我能够模拟一个诸如中心化的HR数据库(人力资源数据库)之类的系统,它可能会成为全体职员的地点信息的权威数据源。 Claims are associated with the user’s identity during the authentication process, and Listing 15-16 shows the changes I made to the Login action method of the Account controller to call the LocationClaimsProvider class. 在认证过程期间,声明(Claims)是与用户标识关联在一起的,清单15-16显示了我对Account控制器中Login动作方法所做的修改,以便调用LocationClaimsProvider类。 Listing 15-16. Associating Claims with a User in the AccountController.cs File 清单15-16. AccountController.cs文件中用户用声明的关联 ...[HttpPost][AllowAnonymous][ValidateAntiForgeryToken]public async Task<ActionResult> Login(LoginModel details, string returnUrl) {if (ModelState.IsValid) {AppUser user = await UserManager.FindAsync(details.Name,details.Password);if (user == null) {ModelState.AddModelError("", "Invalid name or password.");} else {ClaimsIdentity ident = await UserManager.CreateIdentityAsync(user,DefaultAuthenticationTypes.ApplicationCookie); ident.AddClaims(LocationClaimsProvider.GetClaims(ident));AuthManager.SignOut();AuthManager.SignIn(new AuthenticationProperties {IsPersistent = false}, ident);return Redirect(returnUrl);} }ViewBag.returnUrl = returnUrl;return View(details);}... You can see the effect of the location claims by starting the application, authenticating as a user, and requesting the /Claim/Index URL. Figure 15-6 shows the claims for Alice. You may have to sign out and sign back in again to see the change. 为了看看这个地点声明(Claims)的效果,可以启动应用程序,以一个用户进行认证,并请求/Claim/Index URL。图15-6显示了Alice的声明(Claims)。你可能需要退出,然后再次登录才会看到发生的变化。 Figure 15-6. Defining additional claims for users 图15-6. 定义用户的附加声明 Obtaining claims from multiple locations means that the application doesn’t have to duplicate data that is held elsewhere and allows integration of data from external parties. The Claim.Issuer property tells you where a claim originated from, which helps you judge how accurate the data is likely to be and how much weight you should give the data in your application. Location data obtained from a central HR database is likely to be more accurate and trustworthy than data obtained from an external mailing list provider, for example. 从多个地点获取声明(Claims)意味着应用程序不必复制其他地方保持的数据,并且能够与外部的数据集成。Claim.Issuer属性(图15-6中的Issuer数据列——译者注)能够告诉你一个声明(Claim)的发源地,这有助于让你判断数据的精确程度,也有助于让你决定这类数据在应用程序中的权重。例如,从中心化的HR数据库获取的地点数据可能要比外部邮件列表提供器获取的数据更为精确和可信。 1. Applying Claims 1. 运用声明(Claims) The second reason that claims are interesting is that you can use them to manage user access to your application more flexibly than with standard roles. The problem with roles is that they are static, and once a user has been assigned to a role, the user remains a member until explicitly removed. This is, for example, how long-term employees of big corporations end up with incredible access to internal systems: They are assigned the roles they require for each new job they get, but the old roles are rarely removed. (The unexpectedly broad systems access sometimes becomes apparent during the investigation into how someone was able to ship the contents of the warehouse to their home address—true story.) 声明(Claims)有意思的第二个原因是,你可以用它们来管理用户对应用程序的访问,这要比标准的角色管理更为灵活。角色的问题在于它们是静态的,而且一旦用户已经被赋予了一个角色,该用户便是一个成员,直到明确地删除为止。例如,这意味着大公司的长期雇员,对内部系统的访问会十分惊人:他们每次在获得新工作时,都会赋予所需的角色,但旧角色很少被删除。(在调查某人为何能够将仓库里的东西发往他的家庭地址过程中发现,有时会出现异常宽泛的系统访问——真实的故事) Claims can be used to authorize users based directly on the information that is known about them, which ensures that the authorization changes when the data changes. The simplest way to do this is to generate Role claims based on user data that are then used by controllers to restrict access to action methods. Listing 15-17 shows the contents of the ClaimsRoles.cs file that I added to the Infrastructure. 声明(Claims)可以直接根据用户已知的信息对用户进行授权,这能够保证当数据发生变化时,授权也随之而变。此事最简单的做法是根据用户数据来生成Role声明(Claim),然后由控制器用来限制对动作方法的访问。清单15-17显示了我添加到Infrastructure中的ClaimsRoles.cs文件的内容。 Listing 15-17. The Contents of the ClaimsRoles.cs File 清单15-17. ClaimsRoles.cs文件的内容 using System.Collections.Generic;using System.Security.Claims; namespace Users.Infrastructure {public class ClaimsRoles {public static IEnumerable<Claim> CreateRolesFromClaims(ClaimsIdentity user) {List<Claim> claims = new List<Claim>();if (user.HasClaim(x => x.Type == ClaimTypes.StateOrProvince&& x.Issuer == "RemoteClaims" && x.Value == "DC")&& user.HasClaim(x => x.Type == ClaimTypes.Role&& x.Value == "Employees")) {claims.Add(new Claim(ClaimTypes.Role, "DCStaff"));}return claims;} }} The gnarly looking CreateRolesFromClaims method uses lambda expressions to determine whether the user has a StateOrProvince claim from the RemoteClaims issuer with a value of DC and a Role claim with a value of Employees. If the user has both claims, then a Role claim is returned for the DCStaff role. Listing 15-18 shows how I call the CreateRolesFromClaims method from the Login action in the Account controller. CreateRolesFromClaims是一个粗糙的考察方法,它使用了Lambda表达式,以检查用户是否具有StateOrProvince声明(Claim),该声明来自于RemoteClaims发行者(Issuer),值为DC。也检查用户是否具有Role声明(Claim),其值为Employees。如果用户这两个声明都有,那么便返回一个DCStaff角色的Role声明。清单15-18显示了如何在Account控制器中的Login动作中调用CreateRolesFromClaims方法。 Listing 15-18. Generating Roles Based on Claims in the AccountController.cs File 清单15-18. 在AccountController.cs中根据声明生成角色 ...[HttpPost][AllowAnonymous][ValidateAntiForgeryToken]public async Task<ActionResult> Login(LoginModel details, string returnUrl) {if (ModelState.IsValid) {AppUser user = await UserManager.FindAsync(details.Name,details.Password);if (user == null) {ModelState.AddModelError("", "Invalid name or password.");} else {ClaimsIdentity ident = await UserManager.CreateIdentityAsync(user,DefaultAuthenticationTypes.ApplicationCookie);ident.AddClaims(LocationClaimsProvider.GetClaims(ident)); ident.AddClaims(ClaimsRoles.CreateRolesFromClaims(ident));AuthManager.SignOut();AuthManager.SignIn(new AuthenticationProperties {IsPersistent = false}, ident);return Redirect(returnUrl);} }ViewBag.returnUrl = returnUrl;return View(details);}... I can then restrict access to an action method based on membership of the DCStaff role. Listing 15-19 shows a new action method I added to the Claims controller to which I have applied the Authorize attribute. 然后我可以根据DCStaff角色的成员,来限制对一个动作方法的访问。清单15-19显示了在Claims控制器中添加的一个新的动作方法,在该方法上已经运用了Authorize注解属性。 Listing 15-19. Adding a New Action Method to the ClaimsController.cs File 清单15-19. 在ClaimsController.cs文件中添加一个新的动作方法 using System.Security.Claims;using System.Web;using System.Web.Mvc;namespace Users.Controllers {public class ClaimsController : Controller {[Authorize]public ActionResult Index() {ClaimsIdentity ident = HttpContext.User.Identity as ClaimsIdentity;if (ident == null) {return View("Error", new string[] { "No claims available" });} else {return View(ident.Claims);} } [Authorize(Roles="DCStaff")]public string OtherAction() {return "This is the protected action";} }} Users will be able to access OtherAction only if their claims grant them membership to the DCStaff role. Membership of this role is generated dynamically, so a change to the user’s employment status or location information will change their authorization level. 只要用户的声明(Claims)承认他们是DCStaff角色的成员,那么他们便能访问OtherAction动作。该角色的成员是动态生成的,因此,若是用户的雇用状态或地点信息发生变化,也会改变他们的授权等级。 提示:请读者从这个例子中吸取其中的思想精髓。对于读物的理解程度,仁者见仁,智者见智,能领悟多少,全凭各人,译者感觉这里的思想有无数的可能。举例说明:(1)可以根据用户的身份进行授权,比如学生在校时是“学生”,毕业后便是“校友”;(2)可以根据用户所处的部门进行授权,人事部用户属于人事团队,销售部用户属于销售团队,各团队有其自己的应用;(3)下一小节的示例是根据用户的地点授权。简言之:一方面用户的各种声明(Claim)都可以用来进行授权;另一方面用户的声明(Claim)又是可以自定义的。于是可能的运用就无法估计了。总之一句话,这种基于声明的授权(Claims-Based Authorization)有无限可能!要是没有我这里的提示,是否所有读者在此处都会有所体会?——译者注 15.3.3 Authorizing Access Using Claims 15.3.3 使用声明(Claims)授权访问 The previous example is an effective demonstration of how claims can be used to keep authorizations fresh and accurate, but it is a little indirect because I generate roles based on claims data and then enforce my authorization policy based on the membership of that role. A more direct and flexible approach is to enforce authorization directly by creating a custom authorization filter attribute. Listing 15-20 shows the contents of the ClaimsAccessAttribute.cs file, which I added to the Infrastructure folder and used to create such a filter. 前面的示例有效地演示了如何用声明(Claims)来保持新鲜和准确的授权,但有点不太直接,因为我要根据声明(Claims)数据来生成了角色,然后强制我的授权策略基于角色成员。一个更直接且灵活的办法是直接强制授权,其做法是创建一个自定义的授权过滤器注解属性。清单15-20演示了ClaimsAccessAttribute.cs文件的内容,我将它添加在Infrastructure文件夹中,并用它创建了这种过滤器。 Listing 15-20. The Contents of the ClaimsAccessAttribute.cs File 清单15-20. ClaimsAccessAttribute.cs文件的内容 using System.Security.Claims;using System.Web;using System.Web.Mvc; namespace Users.Infrastructure {public class ClaimsAccessAttribute : AuthorizeAttribute {public string Issuer { get; set; }public string ClaimType { get; set; }public string Value { get; set; }protected override bool AuthorizeCore(HttpContextBase context) {return context.User.Identity.IsAuthenticated&& context.User.Identity is ClaimsIdentity&& ((ClaimsIdentity)context.User.Identity).HasClaim(x =>x.Issuer == Issuer && x.Type == ClaimType && x.Value == Value);} }} The attribute I have defined is derived from the AuthorizeAttribute class, which makes it easy to create custom authorization policies in MVC framework applications by overriding the AuthorizeCore method. My implementation grants access if the user is authenticated, the IIdentity implementation is an instance of ClaimsIdentity, and the user has a claim with the issuer, type, and value matching the class properties. Listing 15-21 shows how I applied the attribute to the Claims controller to authorize access to the OtherAction method based on one of the location claims created by the LocationClaimsProvider class. 我所定义的这个注解属性派生于AuthorizeAttribute类,通过重写AuthorizeCore方法,很容易在MVC框架应用程序中创建自定义的授权策略。在这个实现中,若用户是已认证的、其IIdentity实现是一个ClaimsIdentity实例,而且该用户有一个带有issuer、type以及value的声明(Claim),它们与这个类的属性是匹配的,则该用户便是允许访问的。清单15-21显示了如何将这个注解属性运用于Claims控制器,以便根据LocationClaimsProvider类创建的地点声明(Claim),对OtherAction方法进行授权访问。 Listing 15-21. Performing Authorization on Claims in the ClaimsController.cs File 清单15-21. 在ClaimsController.cs文件中执行基于声明的授权 using System.Security.Claims;using System.Web;using System.Web.Mvc;using Users.Infrastructure;namespace Users.Controllers {public class ClaimsController : Controller {[Authorize]public ActionResult Index() {ClaimsIdentity ident = HttpContext.User.Identity as ClaimsIdentity;if (ident == null) {return View("Error", new string[] { "No claims available" });} else {return View(ident.Claims);} } [ClaimsAccess(Issuer="RemoteClaims", ClaimType=ClaimTypes.PostalCode,Value="DC 20500")]public string OtherAction() {return "This is the protected action";} }} My authorization filter ensures that only users whose location claims specify a ZIP code of DC 20500 can invoke the OtherAction method. 这个授权过滤器能够确保只有地点声明(Claim)的邮编为DC 20500的用户才能请求OtherAction方法。 15.4 Using Third-Party Authentication 15.4 使用第三方认证 One of the benefits of a claims-based system such as ASP.NET Identity is that any of the claims can come from an external system, even those that identify the user to the application. This means that other systems can authenticate users on behalf of the application, and ASP.NET Identity builds on this idea to make it simple and easy to add support for authenticating users through third parties such as Microsoft, Google, Facebook, and Twitter. 基于声明的系统,如ASP.NET Identity,的好处之一是任何声明都可以来自于外部系统,即使是将用户标识到应用程序的那些声明。这意味着其他系统可以代表应用程序来认证用户,而ASP.NET Identity就建立在这样的思想之上,使之能够简单而方便地添加第三方认证用户的支持,如微软、Google、Facebook、Twitter等。 There are some substantial benefits of using third-party authentication: Many users will already have an account, users can elect to use two-factor authentication, and you don’t have to manage user credentials in the application. In the sections that follow, I’ll show you how to set up and use third-party authentication for Google users, which Table 15-8 puts into context. 使用第三方认证有一些实际的好处:许多用户已经有了账号、用户可以选择使用双因子认证、你不必在应用程序中管理用户凭据等等。在以下小节中,我将演示如何为Google用户建立并使用第三方认证,表15-8描述了事情的情形。 Table 15-8. Putting Third-Party Authentication in Context 表15-8. 第三方认证情形 Question 问题 Answer 回答 What is it? 什么是第三方认证? Authenticating with third parties lets you take advantage of the popularity of companies such as Google and Facebook. 第三方认证使你能够利用流行公司,如Google和Facebook,的优势。 Why should I care? 为何要关心它? Users don’t like having to remember passwords for many different sites. Using a provider with large-scale adoption can make your application more appealing to users of the provider’s services. 用户不喜欢记住许多不同网站的口令。使用大范围适应的提供器可使你的应用程序更吸引有提供器服务的用户。 How is it used by the MVC framework? 如何在MVC框架中使用它? This feature isn’t used directly by the MVC framework. 这不是一个直接由MVC框架使用的特性。 Note The reason I have chosen to demonstrate Google authentication is that it is the only option that doesn’t require me to register my application with the authentication service. You can get details of the registration processes required at http://bit.ly/1cqLTrE. 提示:我选择演示Google认证的原因是,它是唯一不需要在其认证服务中注册我应用程序的公司。有关认证服务注册过程的细节,请参阅http://bit.ly/1cqLTrE。 15.4.1 Enabling Google Authentication 15.4.1 启用Google认证 ASP.NET Identity comes with built-in support for authenticating users through their Microsoft, Google, Facebook, and Twitter accounts as well more general support for any authentication service that supports OAuth. The first step is to add the NuGet package that includes the Google-specific additions for ASP.NET Identity. Enter the following command into the Package Manager Console: ASP.NET Identity带有通过Microsoft、Google、Facebook以及Twitter账号认证用户的内建支持,并且对于支持OAuth的认证服务具有更普遍的支持。第一个步骤是添加NuGet包,包中含有用于ASP.NET Identity的Google专用附件。请在“Package Manager Console(包管理器控制台)”中输入以下命令: Install-Package Microsoft.Owin.Security.Google -version 2.0.2 There are NuGet packages for each of the services that ASP.NET Identity supports, as described in Table 15-9. 对于ASP.NET Identity支持的每一种服务都有相应的NuGet包,如表15-9所示。 Table 15-9. The NuGet Authenticaton Packages 表15-9. NuGet认证包 Name 名称 Description 描述 Microsoft.Owin.Security.Google Authenticates users with Google accounts 用Google账号认证用户 Microsoft.Owin.Security.Facebook Authenticates users with Facebook accounts 用Facebook账号认证用户 Microsoft.Owin.Security.Twitter Authenticates users with Twitter accounts 用Twitter账号认证用户 Microsoft.Owin.Security.MicrosoftAccount Authenticates users with Microsoft accounts 用Microsoft账号认证用户 Microsoft.Owin.Security.OAuth Authenticates users against any OAuth 2.0 service 根据任一OAuth 2.0服务认证用户 Once the package is installed, I enable support for the authentication service in the OWIN startup class, which is defined in the App_Start/IdentityConfig.cs file in the example project. Listing 15-22 shows the change that I have made. 一旦安装了这个包,便可以在OWIN启动类中启用此项认证服务的支持,启动类的定义在示例项目的App_Start/IdentityConfig.cs文件中。清单15-22显示了所做的修改。 Listing 15-22. Enabling Google Authentication in the IdentityConfig.cs File 清单15-22. 在IdentityConfig.cs文件中启用Google认证 using Microsoft.AspNet.Identity;using Microsoft.Owin;using Microsoft.Owin.Security.Cookies;using Owin;using Users.Infrastructure;using Microsoft.Owin.Security.Google;namespace Users {public class IdentityConfig {public void Configuration(IAppBuilder app) {app.CreatePerOwinContext<AppIdentityDbContext>(AppIdentityDbContext.Create);app.CreatePerOwinContext<AppUserManager>(AppUserManager.Create);app.CreatePerOwinContext<AppRoleManager>(AppRoleManager.Create); app.UseCookieAuthentication(new CookieAuthenticationOptions {AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,LoginPath = new PathString("/Account/Login"),}); app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);app.UseGoogleAuthentication();} }} Each of the packages that I listed in Table 15-9 contains an extension method that enables the corresponding service. The extension method for the Google service is called UseGoogleAuthentication, and it is called on the IAppBuilder implementation that is passed to the Configuration method. 表15-9所列的每个包都含有启用相应服务的扩展方法。用于Google服务的扩展方法名称为UseGoogleAuthentication,它通过传递给Configuration方法的IAppBuilder实现进行调用。 Next I added a button to the Views/Account/Login.cshtml file, which allows users to log in via Google. You can see the change in Listing 15-23. 下一步骤是在Views/Account/Login.cshtml文件中添加一个按钮,让用户能够通过Google进行登录。所做的修改如清单15-23所示。 Listing 15-23. Adding a Google Login Button to the Login.cshtml File 清单15-23. 在Login.cshtml文件中添加Google登录按钮 @model Users.Models.LoginModel@{ ViewBag.Title = "Login";}<h2>Log In</h2> @Html.ValidationSummary()@using (Html.BeginForm()) {@Html.AntiForgeryToken();<input type="hidden" name="returnUrl" value="@ViewBag.returnUrl" /><div class="form-group"><label>Name</label>@Html.TextBoxFor(x => x.Name, new { @class = "form-control" })</div><div class="form-group"><label>Password</label>@Html.PasswordFor(x => x.Password, new { @class = "form-control" })</div><button class="btn btn-primary" type="submit">Log In</button>}@using (Html.BeginForm("GoogleLogin", "Account")) {<input type="hidden" name="returnUrl" value="@ViewBag.returnUrl" /><button class="btn btn-primary" type="submit">Log In via Google</button>} The new button submits a form that targets the GoogleLogin action on the Account controller. You can see this method—and the other changes I made the controller—in Listing 15-24. 新按钮递交一个表单,目标是Account控制器中的GoogleLogin动作。可从清单15-24中看到该方法,以及在控制器中所做的其他修改。 Listing 15-24. Adding Support for Google Authentication to the AccountController.cs File 清单15-24. 在AccountController.cs文件中添加Google认证支持 using System.Threading.Tasks;using System.Web.Mvc;using Users.Models;using Microsoft.Owin.Security;using System.Security.Claims;using Microsoft.AspNet.Identity;using Microsoft.AspNet.Identity.Owin;using Users.Infrastructure;using System.Web; namespace Users.Controllers {[Authorize]public class AccountController : Controller {[AllowAnonymous]public ActionResult Login(string returnUrl) {if (HttpContext.User.Identity.IsAuthenticated) {return View("Error", new string[] { "Access Denied" });}ViewBag.returnUrl = returnUrl;return View();}[HttpPost][AllowAnonymous][ValidateAntiForgeryToken]public async Task<ActionResult> Login(LoginModel details, string returnUrl) {if (ModelState.IsValid) {AppUser user = await UserManager.FindAsync(details.Name,details.Password);if (user == null) {ModelState.AddModelError("", "Invalid name or password.");} else {ClaimsIdentity ident = await UserManager.CreateIdentityAsync(user,DefaultAuthenticationTypes.ApplicationCookie); ident.AddClaims(LocationClaimsProvider.GetClaims(ident));ident.AddClaims(ClaimsRoles.CreateRolesFromClaims(ident)); AuthManager.SignOut();AuthManager.SignIn(new AuthenticationProperties {IsPersistent = false}, ident);return Redirect(returnUrl);} }ViewBag.returnUrl = returnUrl;return View(details);} [HttpPost][AllowAnonymous]public ActionResult GoogleLogin(string returnUrl) {var properties = new AuthenticationProperties {RedirectUri = Url.Action("GoogleLoginCallback",new { returnUrl = returnUrl})};HttpContext.GetOwinContext().Authentication.Challenge(properties, "Google");return new HttpUnauthorizedResult();}[AllowAnonymous]public async Task<ActionResult> GoogleLoginCallback(string returnUrl) {ExternalLoginInfo loginInfo = await AuthManager.GetExternalLoginInfoAsync();AppUser user = await UserManager.FindAsync(loginInfo.Login);if (user == null) {user = new AppUser {Email = loginInfo.Email,UserName = loginInfo.DefaultUserName,City = Cities.LONDON, Country = Countries.UK};IdentityResult result = await UserManager.CreateAsync(user);if (!result.Succeeded) {return View("Error", result.Errors);} else {result = await UserManager.AddLoginAsync(user.Id, loginInfo.Login);if (!result.Succeeded) {return View("Error", result.Errors);} }}ClaimsIdentity ident = await UserManager.CreateIdentityAsync(user,DefaultAuthenticationTypes.ApplicationCookie);ident.AddClaims(loginInfo.ExternalIdentity.Claims);AuthManager.SignIn(new AuthenticationProperties {IsPersistent = false }, ident);return Redirect(returnUrl ?? "/");}[Authorize]public ActionResult Logout() {AuthManager.SignOut();return RedirectToAction("Index", "Home");}private IAuthenticationManager AuthManager {get {return HttpContext.GetOwinContext().Authentication;} }private AppUserManager UserManager {get {return HttpContext.GetOwinContext().GetUserManager<AppUserManager>();} }} } The GoogleLogin method creates an instance of the AuthenticationProperties class and sets the RedirectUri property to a URL that targets the GoogleLoginCallback action in the same controller. The next part is a magic phrase that causes ASP.NET Identity to respond to an unauthorized error by redirecting the user to the Google authentication page, rather than the one defined by the application: GoogleLogin方法创建了AuthenticationProperties类的一个实例,并为RedirectUri属性设置了一个URL,其目标为同一控制器中的GoogleLoginCallback动作。下一个部分是一个神奇阶段,通过将用户重定向到Google认证页面,而不是应用程序所定义的认证页面,让ASP.NET Identity对未授权的错误进行响应: ...HttpContext.GetOwinContext().Authentication.Challenge(properties, "Google");return new HttpUnauthorizedResult();... This means that when the user clicks the Log In via Google button, their browser is redirected to the Google authentication service and then redirected back to the GoogleLoginCallback action method once they are authenticated. 这意味着,当用户通过点击Google按钮进行登录时,浏览器被重定向到Google的认证服务,一旦在那里认证之后,便被重定向回GoogleLoginCallback动作方法。 I get details of the external login by calling the GetExternalLoginInfoAsync of the IAuthenticationManager implementation, like this: 我通过调用IAuthenticationManager实现的GetExternalLoginInfoAsync方法,我获得了外部登录的细节,如下所示: ...ExternalLoginInfo loginInfo = await AuthManager.GetExternalLoginInfoAsync();... The ExternalLoginInfo class defines the properties shown in Table 15-10. ExternalLoginInfo类定义的属性如表15-10所示: Table 15-10. The Properties Defined by the ExternalLoginInfo Class 表15-10. ExternalLoginInfo类所定义的属性 Name 名称 Description 描述 DefaultUserName Returns the username 返回用户名 Email Returns the e-mail address 返回E-mail地址 ExternalIdentity Returns a ClaimsIdentity that identities the user 返回标识该用户的ClaimsIdentity Login Returns a UserLoginInfo that describes the external login 返回描述外部登录的UserLoginInfo I use the FindAsync method defined by the user manager class to locate the user based on the value of the ExternalLoginInfo.Login property, which returns an AppUser object if the user has been authenticated with the application before: 我使用了由用户管理器类所定义的FindAsync方法,以便根据ExternalLoginInfo.Login属性的值对用户进行定位,如果用户之前在应用程序中已经认证,该属性会返回一个AppUser对象: ...AppUser user = await UserManager.FindAsync(loginInfo.Login);... If the FindAsync method doesn’t return an AppUser object, then I know that this is the first time that this user has logged into the application, so I create a new AppUser object, populate it with values, and save it to the database. I also save details of how the user logged in so that I can find them next time: 如果FindAsync方法返回的不是AppUser对象,那么我便知道这是用户首次登录应用程序,于是便创建了一个新的AppUser对象,填充该对象的值,并将其保存到数据库。我还保存了用户如何登录的细节,以便下次能够找到他们: ...result = await UserManager.AddLoginAsync(user.Id, loginInfo.Login);... All that remains is to generate an identity the user, copy the claims provided by Google, and create an authentication cookie so that the application knows the user has been authenticated: 剩下的事情只是生成该用户的标识了,拷贝Google提供的声明(Claims),并创建一个认证Cookie,以使应用程序知道此用户已认证: ...ClaimsIdentity ident = await UserManager.CreateIdentityAsync(user,DefaultAuthenticationTypes.ApplicationCookie);ident.AddClaims(loginInfo.ExternalIdentity.Claims);AuthManager.SignIn(new AuthenticationProperties { IsPersistent = false }, ident);... 15.4.2 Testing Google Authentication 15.4.2 测试Google认证 There is one further change that I need to make before I can test Google authentication: I need to change the account verification I set up in Chapter 13 because it prevents accounts from being created with e-mail addresses that are not within the example.com domain. Listing 15-25 shows how I removed the verification from the AppUserManager class. 在测试Google认证之前还需要一处修改:需要修改第13章所建立的账号验证,因为它不允许example.com域之外的E-mail地址创建账号。清单15-25显示了如何在AppUserManager类中删除这种验证。 Listing 15-25. Disabling Account Validation in the AppUserManager.cs File 清单15-25. 在AppUserManager.cs文件中取消账号验证 using Microsoft.AspNet.Identity;using Microsoft.AspNet.Identity.EntityFramework;using Microsoft.AspNet.Identity.Owin;using Microsoft.Owin;using Users.Models; namespace Users.Infrastructure {public class AppUserManager : UserManager<AppUser> {public AppUserManager(IUserStore<AppUser> store): base(store) {}public static AppUserManager Create(IdentityFactoryOptions<AppUserManager> options,IOwinContext context) {AppIdentityDbContext db = context.Get<AppIdentityDbContext>();AppUserManager manager = new AppUserManager(new UserStore<AppUser>(db)); manager.PasswordValidator = new CustomPasswordValidator {RequiredLength = 6,RequireNonLetterOrDigit = false,RequireDigit = false,RequireLowercase = true,RequireUppercase = true}; //manager.UserValidator = new CustomUserValidator(manager) {// AllowOnlyAlphanumericUserNames = true,// RequireUniqueEmail = true//};return manager;} }} Tip you can use validation for externally authenticated accounts, but I am just going to disable the feature for simplicity. 提示:也可以使用外部已认证账号的验证,但这里出于简化,取消了这一特性。 To test authentication, start the application, click the Log In via Google button, and provide the credentials for a valid Google account. When you have completed the authentication process, your browser will be redirected back to the application. If you navigate to the /Claims/Index URL, you will be able to see how claims from the Google system have been added to the user’s identity, as shown in Figure 15-7. 为了测试认证,启动应用程序,通过点击“Log In via Google(通过Google登录)”按钮,并提供有效的Google账号凭据。当你完成了认证过程时,浏览器将被重定向回应用程序。如果导航到/Claims/Index URL,便能够看到来自Google系统的声明(Claims),已被添加到用户的标识中了,如图15-7所示。 Figure 15-7. Claims from Google 图15-7. 来自Google的声明(Claims) 15.5 Summary 15.5 小结 In this chapter, I showed you some of the advanced features that ASP.NET Identity supports. I demonstrated the use of custom user properties and how to use database migrations to preserve data when you upgrade the schema to support them. I explained how claims work and how they can be used to create more flexible ways of authorizing users. I finished the chapter by showing you how to authenticate users via Google, which builds on the ideas behind the use of claims. 本章向你演示了ASP.NET Identity所支持的一些高级特性。演示了自定义用户属性的使用,还演示了在升级数据架构时,如何使用数据库迁移保护数据。我解释了声明(Claims)的工作机制,以及如何将它们用于创建更灵活的用户授权方式。最后演示了如何通过Google进行认证结束了本章,这是建立在使用声明(Claims)的思想基础之上的。 本篇文章为转载内容。原文链接:https://blog.csdn.net/gz19871113/article/details/108591802。 该文由互联网用户投稿提供,文中观点代表作者本人意见,并不代表本站的立场。 作为信息平台,本站仅提供文章转载服务,并不拥有其所有权,也不对文章内容的真实性、准确性和合法性承担责任。 如发现本文存在侵权、违法、违规或事实不符的情况,请及时联系我们,我们将第一时间进行核实并删除相应内容。
2023-10-28 08:49:21
283
转载
MySQL
...优化,了解索引原理与实践策略至关重要。例如,选择合适的索引类型(B树、哈希、全文等),合理设计表结构以减少JOIN操作的复杂度,以及定期分析并优化执行计划,都是提升MySQL数据库性能的关键手段。 此外,随着数据安全问题日益凸显,MySQL的安全配置和权限管理同样值得深入研究。学习如何设置复杂的密码策略、实现用户访问审计、利用SSL加密传输数据,以及对备份与恢复策略进行定制化设计,是确保数据库系统稳定运行和数据安全的重要步骤。 综上所述,在掌握了MySQL数据库的基础创建操作后,持续关注MySQL最新动态,深入了解数据库性能调优和安全管理领域,将极大地助力您在实际项目中构建更加健壮、高效的数据库架构。
2023-08-12 18:53:34
138
码农
站内搜索
用于搜索本网站内部文章,支持栏目切换。
知识学习
实践的时候请根据实际情况谨慎操作。
随机学习一条linux命令:
umount /mnt
- 卸载已挂载的目录。
推荐内容
推荐本栏目内的其它文章,看看还有哪些文章让你感兴趣。
2023-04-28
2023-08-09
2023-06-18
2023-04-14
2023-02-18
2023-04-17
2024-01-11
2023-10-03
2023-09-09
2023-06-13
2023-08-07
2023-03-11
历史内容
快速导航到对应月份的历史文章列表。
随便看看
拉到页底了吧,随便看看还有哪些文章你可能感兴趣。
时光飞逝
"流光容易把人抛,红了樱桃,绿了芭蕉。"