可以使用类提供的方法保护数据。
Crypto
类中的方法提供标准 用于创建摘要、消息身份验证代码和签名的算法 作为加密和解密信息。这些可用于保护 Salesforce,或与 Google 或 Amazon 等外部服务集成 网络服务 (AWS)。Crypto
示例:集成 Amazon WebServices
以下示例演示了 Amazon WebServices 与 销售人员:
public class HMacAuthCallout {
public void testAlexaWSForAmazon() {
// The date format is yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
DateTime d = System.now();
String timestamp = ''+ d.year() + '-' +
d.month() + '-' +
d.day() + '\'T\'' +
d.hour() + ':' +
d.minute() + ':' +
d.second() + '.' +
d.millisecond() + '\'Z\'';
String timeFormat = d.formatGmt(timestamp);
String urlEncodedTimestamp = EncodingUtil.urlEncode(timestamp, 'UTF-8');
String action = 'UrlInfo';
String inputStr = action + timeFormat;
String algorithmName = 'HMacSHA1';
Blob mac = Crypto.generateMac(algorithmName, Blob.valueOf(inputStr),
Blob.valueOf('your_signing_key'));
String macUrl = EncodingUtil.urlEncode(EncodingUtil.base64Encode(mac), 'UTF-8');
String urlToTest = 'amazon.com';
String version = '2005-07-11';
String endpoint = 'http://awis.amazonaws.com/';
String accessKey = 'your_key';
HttpRequest req = new HttpRequest();
req.setEndpoint(endpoint +
'?AWSAccessKeyId=' + accessKey +
'&Action=' + action +
'&ResponseGroup=Rank&Version=' + version +
'&Timestamp=' + urlEncodedTimestamp +
'&Url=' + urlToTest +
'&Signature=' + macUrl);
req.setMethod('GET');
Http http = new Http();
try {
HttpResponse res = http.send(req);
System.debug('STATUS:'+res.getStatus());
System.debug('STATUS_CODE:'+res.getStatusCode());
System.debug('BODY: '+res.getBody());
} catch(System.CalloutException e) {
System.debug('ERROR: '+ e);
}
}
}
示例:加密和 解密
下面的示例使用 和 方法以及类的方法。encryptWithManagedIVdecryptWithManagedIVgenerateAesKeyCrypto
// Use generateAesKey to generate the private key
Blob cryptoKey = Crypto.generateAesKey(256);
// Generate the data to be encrypted.
Blob data = Blob.valueOf('Test data to encrypted');
// Encrypt the data and have Salesforce generate the initialization vector
Blob encryptedData = Crypto.encryptWithManagedIV('AES256', cryptoKey, data);
// Decrypt the data
Blob decryptedData = Crypto.decryptWithManagedIV('AES256', cryptoKey, encryptedData);
下面是为 和 Crypto 方法编写单元测试的示例。
encryptWithManagedIVdecryptWithManagedIV
@isTest
private class CryptoTest {
static testMethod void testValidDecryption() {
// Use generateAesKey to generate the private key
Blob key = Crypto.generateAesKey(128);
// Generate the data to be encrypted.
Blob data = Blob.valueOf('Test data');
// Generate an encrypted form of the data using base64 encoding
String b64Data = EncodingUtil.base64Encode(data);
// Encrypt and decrypt the data
Blob encryptedData = Crypto.encryptWithManagedIV('AES128', key, data);
Blob decryptedData = Crypto.decryptWithManagedIV('AES128', key, encryptedData);
String b64Decrypted = EncodingUtil.base64Encode(decryptedData);
// Verify that the strings still match
System.assertEquals(b64Data, b64Decrypted);
}
static testMethod void testInvalidDecryption() {
// Verify that you must use the same key size for encrypting data
// Generate two private keys, using different key sizes
Blob keyOne = Crypto.generateAesKey(128);
Blob keyTwo = Crypto.generateAesKey(256);
// Generate the data to be encrypted.
Blob data = Blob.valueOf('Test data');
// Encrypt the data using the first key
Blob encryptedData = Crypto.encryptWithManagedIV('AES128', keyOne, data);
try {
// Try decrypting the data using the second key
Crypto.decryptWithManagedIV('AES256', keyTwo, encryptedData);
System.assert(false);
} catch(SecurityException e) {
System.assertEquals('Given final block not properly padded', e.getMessage());
}
}
}
对数据进行编码
您可以对 URL 进行编码和解码,并将字符串转换为十六进制 使用类提供的方法设置格式。
EncodingUtil
此示例演示如何对 UTF-8 中的时间戳值进行 URL 编码 通过调用 .urlEncode
DateTime d = System.now();
String timestamp = ''+ d.year() + '-' +
d.month() + '-' +
d.day() + '\'T\'' +
d.hour() + ':' +
d.minute() + ':' +
d.second() + '.' +
d.millisecond() + '\'Z\'';
System.debug(timestamp);
String urlEncodedTimestamp = EncodingUtil.urlEncode(timestamp, 'UTF-8');
System.debug(urlEncodedTimestamp);
下一个示例演示如何使用 HTTP 摘要计算客户端响应 身份验证 (RFC2617)。convertToHex
@isTest
private class SampleTest {
static testmethod void testConvertToHex() {
String myData = 'A Test String';
Blob hash = Crypto.generateDigest('SHA1',Blob.valueOf(myData));
String hexDigest = EncodingUtil.convertToHex(hash);
System.debug(hexDigest);
}
}
使用模式和匹配器
Apex 提供模式和匹配器,使您能够使用 正则表达式。
模式是正则表达式的编译表示形式。 匹配器使用模式对字符执行匹配操作 字符串。
正则表达式是用于匹配的字符串 另一个字符串,使用特定语法。Apex 支持通过其 Pattern 和 Matcher 类使用正则表达式。
注意
在 Apex 中,Patterns 和 Matchers 以及正则表达式都是基于 在 Java 中的对应物上。请参见 http://java.sun.com/j2se/1.5.0/docs/api/index.html?java/util/regex/Pattern.html。
许多 Matcher 对象可以共享同一个 Pattern 对象,如下所示 在下图中:
可以从同一个 Pattern 对象创建许多 Matcher 对象
Apex 中的正则表达式遵循 Java 中使用的正则表达式的标准语法。 任何基于 Java 的正则表达式字符串都可以轻松导入到 您的 Apex 代码。
注意
Salesforce 限制常规输入序列的次数 表达式可以访问 1,000,000 次。如果达到该限制, 收到运行时错误。
所有正则表达式都指定为字符串。最常规 表达式首先编译到 Pattern 对象中:只有 String 方法采用正则表达式 这没有被编译。split通常,在将正则表达式编译为 Pattern 之后 对象,则只需使用 Pattern 对象一次即可创建 Matcher 对象。 然后,使用 Matcher 对象执行所有进一步的操作。为 例:
// First, instantiate a new Pattern object "MyPattern"
Pattern MyPattern = Pattern.compile('a*b');
// Then instantiate a new Matcher object "MyMatcher"
Matcher MyMatcher = MyPattern.matcher('aaaaab');
// You can use the system static method assert to verify the match
System.assert(MyMatcher.matches());
如果只打算使用一次正则表达式,请使用 class 方法编译表达式 并在单个调用中将字符串与其匹配。例如 以下内容等效于上面的代码:Patternmatches
Boolean Test = Pattern.matches('a*b', 'aaaaab');
- 使用区域
- 使用匹配操作
- 使用边界
- 了解捕获组
- 模式和匹配器示例
使用区域
Matcher 对象在其输入字符串的子集中查找匹配项 称为区域。Matcher 对象的默认区域 始终是输入字符串的整个部分。但是,您可以更改 使用该方法获取某个区域的起点和终点,您可以查询 使用 和 方法的区域终结点。regionregionStartregionEnd
该方法需要 起始值和结束值。下表提供了示例 如何在不设置另一个值的情况下设置另一个值。region
区域开始 | 区域结束 | 代码示例 |
---|---|---|
显式指定 | 保持不变 | MyMatcher.region(start, MyMatcher.regionEnd()); |
保持不变 | 显式指定 | MyMatcher.region(MyMatcher.regionStart(), end); |
重置为默认值 | 显式指定 | MyMatcher.region(0, end); |
使用匹配操作
Matcher 对象对角色执行匹配操作 序列,通过解释 Pattern。
Matcher 对象是通过 Pattern 的方法从 Pattern 实例化的。创建后,匹配器 对象可用于执行以下类型的匹配操作:matcher
- 将 Matcher 对象的整个输入字符串与模式进行匹配 使用方法matches
- 将 Matcher 对象的输入字符串与模式匹配,从 在开始时,但不匹配整个区域,使用该方法lookingAt
- 扫描 Matcher 对象的输入字符串以查找下一个子字符串 与使用方法的模式匹配find
这些方法中的每一个都返回一个指示成功或失败的布尔值。
使用这些方法中的任何一种后,您可以找到更多信息 关于上一个匹配项,即找到的内容,通过使用以下命令 Matcher 类方法:
- end:一旦匹配 made,此方法返回匹配字符串中 匹配的最后一个字符。
- start:一旦匹配 made,此方法返回第一个字符串中的位置 匹配的字符。
- group:一旦匹配 made,此方法返回匹配的子序列。
使用边界
默认情况下,区域由定位边界分隔,这意味着线锚点(例如 或 )在区域边界处匹配,即使区域边界也是如此 已从输入字符串的开头和结尾移开。您可以 指定区域是否对方法使用定位边界。默认情况下, 区域始终使用定位边界。如果设置为 ,则线锚点仅匹配 输入字符串的真正末尾。^$useAnchoringBoundsuseAnchoringBoundsfalse
默认情况下,不会搜索位于区域之外的所有文本, 也就是说,该区域具有不透明的边界。但是,使用透明边界可以搜索外部的文本 一个区域。仅当区域不再使用透明边界时 包含整个输入字符串。您可以指定边界的类型 区域具有使用该方法。useTransparentBounds
假设您正在搜索以下字符串,以及您所在的地区 只是“STRING”这个词:
This is a concatenated STRING of cats and dogs.
如果你搜索“猫”这个词,你不会 接收匹配项,除非您设置了透明边界。
了解捕获组
在匹配操作期间,输入字符串的每个子字符串 与模式匹配的将被保存。这些匹配的子字符串称为捕获组。
捕获组通过计算其左括号进行编号 从左到右。例如,在正则表达式字符串中,有四个捕获 组:((A)(B(C)))
- ((A)(B(C)))
- (A)
- (B(C))
- (C)
组 0 始终代表整个表达式。
与组关联的捕获输入始终是子字符串 最近匹配的组,即返回的组 Matcher 类匹配操作之一。
如果使用其中一个匹配操作第二次评估组, 如果第二次评估,则保留其先前捕获的值(如果有) 失败。
模式和匹配器示例
Matcher 类方法 返回匹配字符串中最后一个字符之后的位置 那是匹配的。在解析字符串时,您将使用它 并希望在找到匹配项后对其进行其他工作, 比如找到下一个匹配项。end
在正则表达式语法中,表示匹配一次或根本不匹配,表示匹配 1 次或多次。?+
在以下示例中,使用 Matcher 传入的字符串 对象与模式匹配,因为匹配字符串 – 后跟一次。然后它与最后一个匹配 – 然后是根本不匹配。(a(b)?)‘ab’‘a’‘b’‘a’‘a’‘b’
pattern myPattern = pattern.compile('(a(b)?)+');
matcher myMatcher = myPattern.matcher('aba');
System.assert(myMatcher.matches() && myMatcher.hitEnd());
// We have two groups: group 0 is always the whole pattern, and group 1 contains
// the substring that most recently matched--in this case, 'a'.
// So the following is true:
System.assert(myMatcher.groupCount() == 2 &&
myMatcher.group(0) == 'aba' &&
myMatcher.group(1) == 'a');
// Since group 0 refers to the whole pattern, the following is true:
System.assert(myMatcher.end() == myMatcher.end(0));
// Since the offset after the last character matched is returned by end,
// and since both groups used the last input letter, that offset is 3
// Remember the offset starts its count at 0. So the following is also true:
System.assert(myMatcher.end() == 3 &&
myMatcher.end(0) == 3 &&
myMatcher.end(1) == 3);
在以下示例中,电子邮件地址被规范化并重复 如果存在不同的顶级域名或子域名,则会报告 对于相似的电子邮件地址。例如,规范化为 。john@fairway.smithcojohn@smithco
class normalizeEmailAddresses{
public void hasDuplicatesByDomain(Lead[] leads) {
// This pattern reduces the email address to 'john@smithco'
// from 'john@*.smithco.com' or 'john@smithco.*'
Pattern emailPattern = Pattern.compile('(?<=@)((?![\\w]+\\.[\\w]+$)
[\\w]+\\.)|(\\.[\\w]+$)');
// Define a set for emailkey to lead:
Map<String,Lead> leadMap = new Map<String,Lead>();
for(Lead lead:leads) {
// Ignore leads with a null email
if(lead.Email != null) {
// Generate the key using the regular expression
String emailKey = emailPattern.matcher(lead.Email).replaceAll('');
// Look for duplicates in the batch
if(leadMap.containsKey(emailKey))
lead.email.addError('Duplicate found in batch');
else {
// Keep the key in the duplicate key custom field
lead.Duplicate_Key__c = emailKey;
leadMap.put(emailKey, lead);
}
}
}
// Now search the database looking for duplicates
for(Lead[] leadsCheck:[SELECT Id, duplicate_key__c FROM Lead WHERE
duplicate_key__c IN :leadMap.keySet()]) {
for(Lead lead:leadsCheck) {
// If there's a duplicate, add the error.
if(leadMap.containsKey(lead.Duplicate_Key__c))
leadMap.get(lead.Duplicate_Key__c).email.addError('Duplicate found
in salesforce(Id: ' + lead.Id + ')');
}
}
}
}