如何在DNN身份验证提供程序中填充UserInfo对象?

时间:2016-01-08 11:18:35

标签: oauth-2.0 linkedin dotnetnuke

我正在尝试在DotNetNuke 7.4中创建一个支持LinkedId的身份验证提供程序。我使用来自DnnPlatform GIT的Facebook提供商的源包作为基础,并为LinkedIn的oAuth修改了它。我可以通过LinkedIn连接并获取身份验证令牌,但代码失败

 OAuthClient.GetCurrentUser<LinkedInUserData>(); 

由于LinkedInUserData为null。具体的记录错误是

DotNetNuke.Services.Exceptions.Exceptions - ~/Default.aspx?tabid=55&error=An unexpected error has occurred
System.ArgumentNullException: Value cannot be null.
Parameter name: value
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at DotNetNuke.Services.Authentication.OAuth.OAuthClientBase.GetCurrentUser[TUserData]()
   at DotNetNuke.Authentication.LinkedIn.Login.GetCurrentUser() in c:\Websites\dnndev74_2\DesktopModules\AuthenticationServices\LinkedIn\Login.ascx.cs:line 103

下面是3个正在运行的类,有很多继承正在进行,所以我很难理解LinkedInUserData如何首先填充的机制。在笔记上。当我从GIT获取facebook代码库并将其作为提供商安装在我的本地时,并尝试注册Facebook帐户,我得到相同的错误。但是,如果我通过CMS安装提供程序它运行正常或使用dnn 7.4安装附带的DLL,Facebook工作。因此,我认为GIT代码存在根本性缺陷。

LinkedInClient.cs

    namespace DotNetNuke.Authentication.LinkedIn.Components
{
    public class LinkedInClient : OAuthClientBase
    {
        #region Constructors

        public LinkedInClient(int portalId, AuthMode mode) 
            : base(portalId, mode, "LinkedIn")
        {
            base.AuthorizationEndpoint = new Uri("https://www.linkedin.com/uas/oauth2/authorization");
            base.RequestTokenEndpoint = new Uri("https://api.linkedin.com/uas/oauth/requestToken?scope=r_emailaddress");
            base.TokenMethod = HttpMethod.POST;
            base.TokenEndpoint = new Uri("https://www.linkedin.com/uas/oauth2/accessToken");
            base.MeGraphEndpoint = new Uri("https://api.linkedin.com/v1/people/~:(id,first-name,last-name,email-address,formatted-name,picture-url)?format=json");
            base.AuthTokenName = "LinkedInUserToken";
            base.OAuthVersion = "2.0";
            base.LoadTokenCookie(string.Empty);
        }

        #endregion

        protected override TimeSpan GetExpiry(string responseText)
        {
            var jsonSerializer = new JavaScriptSerializer();
            var tokenDictionary = jsonSerializer.DeserializeObject(responseText) as Dictionary<string, object>;

            return new TimeSpan(0, 0, Convert.ToInt32(tokenDictionary["expires_in"]));
        }

        protected override string GetToken(string responseText)
        {
            var jsonSerializer = new JavaScriptSerializer();
            var tokenDictionary = jsonSerializer.DeserializeObject(responseText) as Dictionary<string, object>;
            return Convert.ToString(tokenDictionary["access_token"]);
        }
    }
}

LinkedInUserData.cs

namespace DotNetNuke.Authentication.LinkedIn.Components
{
    [DataContract]
    [Serializable]
    public class LinkedInUserData : UserData
    {
        #region Overrides

        public override string FirstName
        {
            get { return LinkedInFirstName; }
            set { }
        }

        public override string LastName
        {
            get { return LinkedInLastName; }
            set { }
        }

        public override string Email
        {
            get { return emailAddress; }
            set { }
        }

        public override string ProfileImage
        {
            get { return LinkedInPictureUrl; }
            set { }
        }

        #endregion

        [DataMember(Name = "first-name")]
        public string LinkedInFirstName { get; set; }

        [DataMember(Name = "last-name")]
        public string LinkedInLastName { get; set; }

        [DataMember(Name = "picture-url")]
        public string LinkedInPictureUrl { get; set; }

        [DataMember(Name = "email-address")]
        public string emailAddress { set; get; }

}

Login.cs

namespace DotNetNuke.Authentication.LinkedIn
{
    public partial class Login : OAuthLoginBase
    {
        protected override string AuthSystemApplicationName
        {
            get { return "LinkedIn"; }
        }

        public override bool SupportsRegistration
        {
            get { return true; }
        }

        protected override UserData GetCurrentUser()
        {
            return OAuthClient.GetCurrentUser<LinkedInUserData>();
        }

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            loginButton.Click += loginButton_Click;
            registerButton.Click += loginButton_Click;

            OAuthClient = new LinkedInClient(PortalId, Mode);

            loginItem.Visible = (Mode == AuthMode.Login);
            registerItem.Visible = (Mode == AuthMode.Register);
        }

        protected override void AddCustomProperties(NameValueCollection properties)
        {
            base.AddCustomProperties(properties);

            properties.Add("LinkedIn", OAuthClient.GetCurrentUser<LinkedInUserData>().Link.ToString());
        }

        private void loginButton_Click(object sender, EventArgs e)
        {
            AuthorisationResult result = OAuthClient.Authorize();
            if (result == AuthorisationResult.Denied)
            {
                UI.Skins.Skin.AddModuleMessage(this, Localization.GetString("PrivateConfirmationMessage", Localization.SharedResourceFile), ModuleMessage.ModuleMessageType.YellowWarning);

            }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

标记,

几年前我为Linkedin写了一个DNN提供商。将我的代码与您的代码进行比较,我的第一件事是重定向用户以获取访问令牌。用于获取访问令牌和用户许可的基本URL是:www.linkedin.com/uas/oauth2。我必须传递我的链接API密钥,重定向Url以及来自提供程序设置的一些其他数据。

我的重定向网址与加载我的提供商的默认门户网站登录页面相同。一旦用户允许LinkedIn允许我的应用程序访问并验证他已登录,重定向回我的提供者将在Request.Cookies中查找LinkedInAuthToken cookie。验证令牌有效后,我可以对/ v1 / people / API进行额外的API调用,以获取用户数据,以完成对DNN的任何类型的自动注册或自动配置文件更新。

在获取oauth访问cookie之前,您的提供商似乎会立即尝试用户数据查找API调用。

我的LinkedIn提供商的代码不是开源的,但我想我可以从我的工作中获得许可以公开它。如果您对此感兴趣,请给我留言。