Azure AD认证和Azure AD B2C的token获取

这篇具有很好参考价值的文章主要介绍了Azure AD认证和Azure AD B2C的token获取。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Azure AD认证和Azure AD B2C的token获取


工作当中使用过Azure AD认证和B2C的认证,今天抽时间再回顾一下。

个人理解比较浅显,我认为Azure AD和Azure AD B2C都可作为用户管理的系统,他们提供了自己的登录认证画面,统一使用Graph API对自己的用户和其他功能做管理。

Azure AD功能强大,微软的老牌认证方式,可以很方便跟其他三方应用集成,可做单点登录。
而Azure AD B2C更像是三方的用户系统,最大的特点是可自定义UI画面。

感觉总结的不是很好,纯纯自己的理解,这里就不多说了,让我们进入正题。

这里主要贴一下,当时使用的认证相关获取token的代码。

一、Azure AD

1、获取认证登录地址
下面的代码是nodejs的示例,需要用到msal-node库·,当然可以根据官网自己拼接URL也是可以的,在之前曾经尝试过,没有任何问题。
只是在当时不知道为什么,老是提示我需要change_codeverifier两个参数,因为不明白这两个参数的原理,所以采用了msal-node库去生成。
msal参考地址: https://azuread.github.io/microsoft-authentication-library-for-js/ref/classes/_azure_msal_browser.publicclientapplication.html

const msal = require("@azure/msal-node");

function getAuthCodeUrl (){
  return new Promise((resolve, reject) => {
    const cryptoProvider = new msal.CryptoProvider();
    cryptoProvider.generatePkceCodes().then(({ verifier, challenge }) => {
	  const publiClient= new msal.PublicClientApplication({
	    auth: {
	      "clientId": SETTINGS.AD_CLIENT_ID,
	      "authority": `https://login.microsoftonline.com/${SETTINGS.AD_TENANT_ID}`
	    }
	  });
      publiClient.getAuthCodeUrl({
        scopes: ["user.read"],
        redirectUri: SETTINGS.REDIRECT_URL,
        codeChallenge: challenge,
        codeChallengeMethod: "S256"
      }).then((response) => {
        let result = {
          authUrl: response,
          verifier: verifier,
        };
        resolve(result);
      }).catch((error) => {
        reject(JSON.stringify(error));
      });
    });
  });
}

2、access_token的获取
① 通过认证code获取access_token。
在通过认证地址登录后,会跳转到重定向地址,附带client_infocode参数,verifier参数由1、中获取。
官方参考地址: https://learn.microsoft.com/zh-cn/graph/auth-v2-user

const rp = require("request-promise");

function getADToken (code, clientInfo, verifier) {
  return new Promise((resolve, reject) => {
    let options = {
      method: "POST",
      uri: `https://login.microsoftonline.com/${SETTINGS.AD_TENANT_ID}/oauth2/v2.0/token`,
      form: {
        "client_id": SETTINGS.AD_CLIENT_ID,
        "scope": "openid offline_access profile",
        "grant_type": "authorization_code",
        "redirect_uri": SETTINGS.REDIRECT_URL,
        "code": code,
        "client_secret": SETTINGS.AD_SECRIT_ID,
        "client_info": clientInfo,
        "code_verifier": verifier,
      },
      headers: {
        "Content-Type": "application/x-www-form-urlencoded",
      },
    };

    rp(options)
      .then((res) => {
        resolve(JSON.parse(res)["access_token"]);
      })
      .catch((err) => {
        reject(err);
      });
  });
}

二、Azure AD B2C

1、获取认证登录地址

// B2C配置对象
 const b2cConfig= {
    auth: {
      clientId: SETTINGS.B2C_CLIENT_ID,
      authority: `https://${SETTINGS.B2C_TENANT_NAME}.b2clogin.com/${SETTINGS.B2C_TENANT_NAME}.onmicrosoft.com/${SETTINGS.B2C_POLICY}`,
      knownAuthorities: [`${SETTINGS.B2C_TENANT_NAME}.b2clogin.com`],
      redirectUri: SETTINGS.REDIRECT_URL,
    }
  };

// 创建msal对象
const publicClient = new msal.PublicClientApplication(b2cConfig);

function getAuthCodeUrl (){
  return new Promise((resolve, reject) => {
    const cryptoProvider = new msal.CryptoProvider();
    cryptoProvider.generatePkceCodes().then(({ verifier, challenge }) => {
      publicClient.getAuthCodeUrl({
        redirectUri: b2cConfig.auth.redirectUri,
        authority: b2cConfig.auth.authority,
        scopes: ["openid", "offline_access"],
        state: "login",
        codeChallenge: challenge,
        codeChallengeMethod: "S256",
      }).then((response) => {
        let result = {
          authUrl: response,
          verifier: verifier,
        };
        resolve(result);
      }).catch((error) => {
        reject(JSON.stringify(error));
      });
    });
  });
}

2、获取IdToken
B2C认证拿到的code只能换取idToken, 就算拿到了access_token也是属于web_token,不能用于调用graph api。这是跟微软support确认后的结果。

function getIdToken (code, codeVerifier) {
  return new Promise((resolve, reject) => {
    // prepare the request for authentication
    const tokenRequest = {
      redirectUri: b2cConfig.auth.redirectUri,
      code: code,
      codeVerifier: codeVerifier,
    };
    pca.acquireTokenByCode(tokenRequest).then((response) => {
      resolve(response);
    }).catch((error) => {
      reject(error);
    });
  });
}

3、解析IdToken
IdToken中包含用户的相关信息,但是没法查看,需要用到jwt-decode库解析。

const jwtDecode = require("jwt-decode");
let tokenObj = jwtDecode(idToken);

4、获取access_token
B2C不能使用认证code获取access_token,所以采用了Azure AD免登录的方式获取了access_token。
官方参考地址: https://learn.microsoft.com/zh-cn/graph/auth-v2-service

const confidentialClientPca = new msal.ConfidentialClientApplication({
	auth: {
      "clientId": SETTINGS.B2C_CLIENT_ID,
      "authority": `https://login.microsoftonline.com/${SETTINGS.B2C_TENANT_ID}`,
      "clientSecret": SETTINGS.B2C_SECRIT_ID,
    }
  });

function getClientCredentialsToken () {
  return new Promise((resolve, reject) => {
    const clientCredentialRequest = {
      scopes: ["https://graph.microsoft.com/.default"],
      azureRegion: null, // (optional) specify the region you will deploy your application to here (e.g. "westus2")
      skipCache: false, // (optional) this skips the cache and forces MSAL to get a new token from Azure AD
    };
    confidentialClientPca.acquireTokenByClientCredential(clientCredentialRequest)
      .then((response) => {
        resolve(response.accessToken);
      }).catch((error) => {
        reject(JSON.stringify(error));
      });
  });
}

三、C# 操作示例

依赖包<PackageReference Include="Microsoft.Graph.Beta" Version="4.35.0-preview" />文章来源地址https://www.toymoban.com/news/detail-470584.html

using System;
using System.Collections.Generic;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Microsoft.Graph;
using Microsoft.Identity.Client;
using System.IO;

namespace AZ.Functuon
{
    public class GraphAPI
    {
        public GraphServiceClient client = null;
        public StreamWriter logWriter;
        public string tenantName;

        public GraphAPI(string tenantId,string tenantName,string clientId,string clientSecret,StreamWriter logWriter)
        {
            try
            {
                this.tenantName = tenantName;
                this.logWriter = logWriter;
                string[] scopes = new[] { "https://graph.microsoft.com/.default" };
                IConfidentialClientApplication cca = ConfidentialClientApplicationBuilder
                    .Create(clientId)
                    .WithTenantId(tenantId)
                    .WithClientSecret(clientSecret)
                    .Build();
                Task<AuthenticationResult> taskResult = cca.AcquireTokenForClient(scopes).ExecuteAsync();
                taskResult.Wait();
                InitClint(cca, scopes);
            }
            catch (Exception e)
            {
                CommonFunction.WriteLog(logWriter, "ERROR", $"{e.Message} | {e.StackTrace}");
                this.client = null;
            }
        }
        
        public void InitClint(IConfidentialClientApplication cca,string[] scopes)
        {
            DelegateAuthenticationProvider authProvider = new DelegateAuthenticationProvider(async (request) =>
            {
                AuthenticationResult result = await cca.AcquireTokenForClient(scopes).ExecuteAsync();
                request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", result.AccessToken);
            });
            this.client = new GraphServiceClient(authProvider);
        }

        // ユーザのObjectIdを取得する
        public async Task<string> GetObjectId(string employeeId)
        {
            try
            {
                var result = await this.client.Users
                    .Request()
                    .Filter($"identities/any(c:c/issuerAssignedId eq '{employeeId}' and c/issuer eq '{this.tenantName}@onmicrosoft.com')")
                    .Select(e => new
                    {
                        e.DisplayName,
                        e.Id,
                        e.Identities
                    })
                    .GetAsync();
                if (result != null)
                {
                    JObject jo = (JObject)JsonConvert.DeserializeObject(System.Text.Json.JsonSerializer.Serialize(result).Substring(1, System.Text.Json.JsonSerializer.Serialize(result).Length-2));
                    return jo["id"].ToString();
                }
                else
                {
                    return null;
                }
            }
            catch(Exception e)
            {
                CommonFunction.WriteLog(logWriter, "ERROR", $"{e.Message} | {e.StackTrace}");
                return null;
            }
        }

        // ユーザのObjectIdをtest取得する
        public async Task<string> GetObjectIdByUserprincipalname(string userPrincipalName)
        {
            try
            {
                String [] userPrincipalNamefirst=userPrincipalName.Split("@");
                var result = await this.client.Users[$"{userPrincipalNamefirst[0]}@{this.tenantName}.onmicrosoft.com"]
                    .Request(new Option[] { new QueryOption("$count", "true")})
                    .Header("ConsistencyLevel", "eventual")
                    .GetAsync();
                if (result != null)
                {
                    JObject jo = (JObject)JsonConvert.DeserializeObject(System.Text.Json.JsonSerializer.Serialize(result));
                    return jo["id"].ToString();
                }
                else
                {
                    return null;
                }
            }
            catch(Exception e)
            {
                CommonFunction.WriteLog(logWriter, "ERROR", $"{e.Message} | {e.StackTrace}");
                return null;
            }
        }

        // B2Cにユーザを新規追加する
        public async Task<bool> CreateB2CUser(string employeeId, string userName,string userPrincipalName, string birthday)
        {
            try
            {
                userPrincipalName = userPrincipalName.Split("@")[0];
                var user = new User
                {
                    AccountEnabled = true,
                    DisplayName = userName,
                    MailNickname = userPrincipalName,
                    UserPrincipalName = $"{userPrincipalName}@{this.tenantName}.onmicrosoft.com",
                    PasswordProfile = new PasswordProfile
                    {
                        ForceChangePasswordNextSignIn = false,
                        Password = $"Fj_{birthday}"
                    },
                    Identities = new List<ObjectIdentity>()
                    {
                        new ObjectIdentity
                        {
                            SignInType = "userName",
                            Issuer = "{this.tenantName}.onmicrosoft.com",
                            IssuerAssignedId = employeeId
                        },
                    }
                };
                var result = await this.client.Users
                    .Request()
                    .AddAsync(user);
                return true;
            }
            catch(Exception e)
            {
                CommonFunction.WriteLog(logWriter, "ERROR", $"{e.Message} | {e.StackTrace}");
                return false;
            }
        }

        // B2Cユーザの認証電話番号追加
        public async Task<bool> AddAuthPhoneNumber(string objectID, string phone)
        {
            try
            {
                var phoneAuthenticationMethod = new PhoneAuthenticationMethod
                {
                    PhoneNumber = $"+81 {phone}",
                    PhoneType = AuthenticationPhoneType.Mobile
                };
                await this.client.Users[objectID].Authentication.PhoneMethods
                    .Request()
                    .AddAsync(phoneAuthenticationMethod);
                return true;
            }
            catch(Exception e)
            {
                CommonFunction.WriteLog(logWriter, "ERROR", $"{e.Message} | {e.StackTrace}");
                return false;
            }
        }

        // 人事情報システム側で更新したB2Cユーザの認証電話番号を更新する
        public async Task<bool> UpdateAuthPhoneNumber(string objectID, string phone)
        {
            try
            {
                var phoneAuthenticationMethod = new PhoneAuthenticationMethod
                {
                    PhoneNumber = $"+81 {phone}",
                    PhoneType = AuthenticationPhoneType.Mobile
                };

                await this.client.Users[objectID].Authentication.PhoneMethods["3179e48a-750b-4051-897c-87b9720928f7"]
                    .Request()
                    .PutAsync(phoneAuthenticationMethod);
                return true;
            }
            catch(Exception e)
            {
                CommonFunction.WriteLog(logWriter, "ERROR", $"{e.Message} | {e.StackTrace}");
                return false;
            }
        }

        // 明細照会サービス側で追加したB2CユーザのユーザIDを更新する
        public async Task<bool> UpdateUserId(string objectID, string userId, string singleName)
        {
            try
            {
            var user = new User
            {
                Identities = new List<ObjectIdentity>()
                {
                    new ObjectIdentity
                    {
                        SignInType = "userName",
                        Issuer = "{this.tenantName}.onmicrosoft.com",
                        IssuerAssignedId = userId
                    },
                },
            };
            await this.client.Users[objectID]
                .Request()
                .UpdateAsync(user);
                return true;
            }
            catch(Exception e)
            {
                CommonFunction.WriteLog(logWriter, "ERROR", $"{e.Message} | {e.StackTrace}");
                return false;
            }
        }

        // B2Cにユーザを削除する
        public async Task<bool> DeleteUserByObjId(string objectId)
        {
            try
            {
                await this.client.Users[objectId]
                    .Request()
                    .DeleteAsync();
                return true;
            }
            catch(Exception e)
            {
                CommonFunction.WriteLog(logWriter, "ERROR", $"{e.Message} | {e.StackTrace}");
                return false;
            }
        }
    }
}

到了这里,关于Azure AD认证和Azure AD B2C的token获取的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 微信小程序+Vue+SpringBoot实现B2C电商系统(毕业论文)

    微信小程序+Vue+SpringBoot实现B2C电商系统(毕业论文)

    5月份答辩完了,顺利通过,现在回头看整个过程其实收获还是很多的,从去年9月份确定选题,11月开始进行需求分析和设计,到12月开始进入开发,一直到今年2月底,然后3月都在写论文,4月修改初稿、录制演示视频、制作PPT,前后经历了大概半年时间,最终做出的成果也基

    2024年02月11日
    浏览(8)
  • Java多用B2C商城平台系统设计与实现(Idea+Springboot+mysql)

    Java多用B2C商城平台系统设计与实现(Idea+Springboot+mysql)

     博主介绍 :黄菊华老师《Vue.js入门与商城开发实战》《微信小程序商城开发》图书作者,CSDN博客专家,在线教育专家,CSDN钻石讲师;专注大学生毕业设计教育和辅导。 所有项目都配有从入门到精通的基础知识视频课程,学习后应对毕业设计答辩。 项目配有对应开发文档、

    2024年03月10日
    浏览(11)
  • 基于J2EE的B2C电子商务系统开发与实现

    摘要 当今社会,科学技术突飞猛进,知识经济初见端倪。电子商务作为一种新型的贸易方式,极大地促进了全球经济贸易的发展,同时也正在改变人们的生活方式和思想观念。电子商务是指整个贸易活动实现电子化,交易各方以电子交易方式而进行的商业交易。世界贸易组织电子商

    2024年02月03日
    浏览(15)
  • 毕业设计——基于SSM架构实现的大型分布式购物网站-B2C项目

    毕业设计——基于[SSM架构]实现的大型分布式购物网站-B2C项目 大型[分布式]购物网站-B2C项目 完整项目地址:https://download.csdn.net/download/lijunhcn/88430551 电商行业模式 B2B:企业到企业、商家到商家。例如阿里巴巴。 B2C:商家到客户。例如京东、淘宝商城 C2C:客户到客户。闲鱼。

    2024年02月04日
    浏览(14)
  • 【Azure Developer】Azure AD 注册应用的 OAuth 2.0 v2 终结点获取的 Token 解析出来依旧为v1, 这是什么情况!

    【Azure Developer】Azure AD 注册应用的 OAuth 2.0 v2 终结点获取的 Token 解析出来依旧为v1, 这是什么情况!

    使用 Azure AD 注册应用 Oauth2 v2.0的终结点(OAuth 2.0 token endpoint (v2): https://login.partner.microsoftonline.cn/your tenant id/oauth2/v2.0/token ) 获取Token,解析出来依旧为v1.0,如何解决呢? 请求Method: POST 请求URL :  https://login.partner.microsoftonline.cn/your tenant id/oauth2/v2.0/token 请求的Body : tenant:

    2024年02月02日
    浏览(17)
  • 【严重】Grafana Azure AD环境身份认证绕过漏洞

    【严重】Grafana Azure AD环境身份认证绕过漏洞

     Grafana 是一个跨平台、开源的数据可视化网络应用平台。Azure AD 是由微软提供的一种云身份验证和访问管理服务。 在 Azure AD 中,多个用户可以拥有相同的电子邮件地址。攻击者可以创建一个与目标 Grafana 账户相同的电子邮件地址的恶意帐户,并且在 Azure AD 中配置支持多租户

    2024年02月17日
    浏览(13)
  • Splunk 成功获取 MS Azure AD 数据

    Splunk 成功获取 MS Azure AD 数据

    1: 背景: 最近客户的Azure AD 的数据在splunk 数据获取失败,我来trouble shooting 发现是splunk 和Azure AD 直接的连接出了问题,正好来回顾一下这个case: 通过Splunk 的日志查找: index=_internal, host=ABC, failed, 就可以看到取Azure AD  的密码报错。 2: 解决问题: 2.1: 先到Splunk 上获取这个Az

    2024年02月13日
    浏览(13)
  • B2B2C商城系统怎么挑选好?

    B2B2C商城系统怎么挑选好?

    B2B2C商城它不仅提供B2B模式下的批量交易,还为消费者提供了B2C模式的优质购物体验,因此,越来越多的企业或商家开始重视B2B2C商城系统的搭建,如目前的SHOP++、Magento等商城系统。那么,如何挑选合适的B2B2C商城系统呢?   一、从功能性考虑 1、支持定制化: B2B2C商城系统需

    2024年02月05日
    浏览(20)
  • 全开源B2B2C商城搭建--H5+小程序+源码定制

    全开源B2B2C商城搭建--H5+小程序+源码定制

    全开源B2B2C商城搭建--H5+小程序+源码定制 随着互联网的快速发展,越来越多的企业开始搭建自己的B2B2C商城。其中,全开源的B2B2C商城因为其灵活性和可定制性,备受企业青睐。本文将详细介绍如何搭建全开源的B2B2C商城,包括H5、小程序和源码定制的步骤。 一、商城系统选择

    2024年02月03日
    浏览(17)
  • S2B2C平台协同管理业务详解 | 数商云S2B2C系统赋能新能源汽车行业高价值增长

    S2B2C平台协同管理业务详解 | 数商云S2B2C系统赋能新能源汽车行业高价值增长

    今年上半年,我国新能源汽车产业依然保持着高速发展的强劲态势,根据中国汽车工业协会发布的汽车产业半年报,2022上半年我国新能源汽车产销同比增长1.2倍,市场占有率已达21.6%。面对新能源汽车大蓝海市场,新能源汽车赛道也不断迎来新的入局者,除了传统造车企业,

    2024年01月15日
    浏览(12)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包