很多情况下我们的CRM系统会和弟三方应用集成,一般情况我们会开发一个中间站点来提供web api 给弟三方应用。
参考:http://alexanderdevelopment.net/post/2015/01/24/authenticating-from-a-node-js-client-to-dynamics-crm-via-ad-fs-and-oauth2/
利用adfs 带的auto2.0可以有一种简单的方式和弟三方应用集成。我们做的只需要类似像和微信、微博、QQ集成弟三登录功能一样实现 ADFS oauth 2.0
弟一步 在ADFS上注册一个client ,生成的 ClientId、RedirectUri (指跳转页面),在ADFS中没有密码这个属性,在请求code的时候 会用这两个属性代替clientid和密码
Add-AdfsClient -ClientId "aa106265-fb3b-49e0-a0e8-6840b3d71ac2" -Name "hongfu dynamics CRM ADFS Client" -RedirectUri "http://localhost:21313/Default.aspx"
弟二步在我们自己的程序中注册登录代码
逻辑比较简单
1 用户进入登录页面
2 用户点击登录,页面会跳转到ADFS的登录页面,注意URL
3 在ADFS实现 登录后,回转到我们之前 定义的RedirectUri,URL中会传一个code参数
4 在登录面的onload 事件中读取出 code,去adfs请求token
string url = string.Format("{0}adfs/oauth2/token"
, _adfs);
string body = string.Format("grant_type=authorization_code&client_id={0}&redirect_uri={1}&code={2}"
, _clientID, Server.UrlEncode(_returnURL), code);
var requestJson = JsonConvert.SerializeObject(new
{
grant_type = "authorization_code",
client_id = _clientID,
redirect_uri = Server.UrlEncode(_returnURL)
,
code = code
});
HttpClient client = new HttpClient();
HttpContent content = new StringContent(body);
content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
var tokenstr = client.PostAsync(url, content).Result.Content.ReadAsStringAsync().Result;
5 请求完token后,再使用token调用CRM webapi ,查询出当前用户和客户信息
6 实现 代码如下
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens;
using System.Linq;
using System.Net;
using System.Threading;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Net.Http;
using Newtonsoft.Json;
using System.Net.Http.Headers;
public partial class _Default : Page
{
//
// Add-AdfsClient -ClientId "aa106265-fb3b-49e0-a0e8-6840b3d71ac2" -Name "hongfu dynamics CRM ADFS Client" -RedirectUri "http://localhost:21313/Default.aspx"
private static AuthenticationContext _authenticationContext;
// TODO Set these string values as approppriate for your app registration and organization.
// For more information, see the SDK topic "Walkthrough: Register an app with Active Directory".
private const string _clientID = "aa106265-fb3b-49e0-a0e8-6840b3d71ac2";
public const string CrmServiceUrl = "https://crm.crmad.com:446/";
public const string _adfs = "https://adfs.crmad.com/";
public const string _returnURL = "http://localhost:21313/Default.aspx";
protected void Page_Load(object sender2, EventArgs e)
{
System.Net.ServicePointManager.ServerCertificateValidationCallback =
((sender, certificate, chain, sslPolicyErrors) => true);
if (!string.IsNullOrEmpty(Request["code"]))
{
GetToken(Request["code"]);
//3. Client request access token
}
}
//<snippetModernOdataAppAuthDiscovery>
/// <summary>
/// Discover the authentication authority.
/// </summary>
/// <param name="serviceUrl">The URL of the organization's SOAP endpoint. </param>
/// <returns>The authority URL.</returns>
/// <remarks>The service URL must contain the SdkClient property.</remarks>
/// <example>https://contoso.crm.dynamics.com/XRMServices/2011/Organization.svc/web?SdkClientVersion=6.1.0.533;</example>
public static string DiscoveryAuthority(Uri serviceUrl)
{
// Use AuthenticationParameters to send a request to the organization's endpoint and
// receive tenant information in the 401 challenge.
HttpWebResponse response = null;
try
{
// Create a web request where the authorization header contains the word "Bearer".
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(serviceUrl);
// The response is to be encoded.
httpWebRequest.ContentType = "application/x-www-form-urlencoded";
response = (HttpWebResponse)httpWebRequest.GetResponse();
}
catch (WebException ex)
{
response = (HttpWebResponse)ex.Response;
}
finally
{
if (response != null)
response.Dispose();
}
// Return the authority URL.
return response.ToString();
}
//</snippetModernOdataAppAuthDiscovery>
protected void Button1_Click(object sender, EventArgs e)
{
string url = string.Format("{0}adfs/oauth2/authorize?response_type=code&client_id={1}&resource={2}&redirect_uri={3}"
, _adfs, _clientID, Server.UrlEncode(CrmServiceUrl), Server.UrlEncode(_returnURL));
Response.Redirect(url);
}
public class CRMToken
{
public string access_token { get; set; }
public string token_type { get; set; }
public string expires_in { get; set; }
public string refresh_token { get; set; }
}
void GetToken(string code)
{
string url = string.Format("{0}adfs/oauth2/token"
, _adfs);
string body = string.Format("grant_type=authorization_code&client_id={0}&redirect_uri={1}&code={2}"
, _clientID, Server.UrlEncode(_returnURL), code);
var requestJson = JsonConvert.SerializeObject(new
{
grant_type = "authorization_code",
client_id = _clientID,
redirect_uri = Server.UrlEncode(_returnURL)
,
code = code
});
HttpClient client = new HttpClient();
HttpContent content = new StringContent(body);
content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
var tokenstr = client.PostAsync(url, content).Result.Content.ReadAsStringAsync().Result;
var token = JsonConvert.DeserializeObject<CRMToken>(tokenstr);
using (HttpClient httpClient = new HttpClient())
{
httpClient.Timeout = new TimeSpan(0, 2, 0); // 2 minutes
httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token.access_token);
//GET [Organization URI]/api/data/v8.1/accounts?$select=name&$top=3 HTTP/1.1
// Accept: application / json
//OData - MaxVersion: 4.0
//OData - Version: 4.0
var api = string.Format("{0}api/data/v8.1/accounts?$select=name&$top=3", CrmServiceUrl);
httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
var str = httpClient.GetStringAsync(api).Result;
this.TextBox1.Text = str;
}
using (HttpClient httpClient = new HttpClient())
{
httpClient.Timeout = new TimeSpan(0, 2, 0); // 2 minutes
httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", token.access_token);
//GET [Organization URI]/api/data/v8.1/accounts?$select=name&$top=3 HTTP/1.1
// Accept: application / json
//OData - MaxVersion: 4.0
//OData - Version: 4.0
var api = string.Format("{0}api/data/v8.1/WhoAmI()", CrmServiceUrl);
httpClient.DefaultRequestHeaders.Add("Accept", "application/json");
var str = httpClient.GetStringAsync(api).Result;
this.Label1.Text = str;
}
}
protected void Button1_Click1(object sender, EventArgs e)
{
string url = string.Format("{0}adfs/oauth2/authorize?response_type=code&client_id={1}&resource={2}&redirect_uri={3}"
, _adfs, _clientID, Server.UrlEncode(CrmServiceUrl), Server.UrlEncode(_returnURL));
Response.Redirect(url);
}
}
<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<asp:Content ID="BodyContent" ContentPlaceHolderID="MainContent" runat="server">
<p>
<br />
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click1" Text="登录CRM" />
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>
</p>
<p>
<asp:TextBox ID="TextBox1" runat="server" Height="183px" TextMode="MultiLine" Width="833px"></asp:TextBox>
</p>
</asp:Content>