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电商系统(毕业论文)

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

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

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

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

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

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

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

    2024年02月04日
    浏览(71)
  • 【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日
    浏览(44)
  • 【严重】Grafana Azure AD环境身份认证绕过漏洞

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

    2024年02月17日
    浏览(45)
  • 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日
    浏览(41)
  • B2B2C商城系统怎么挑选好?

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

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

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

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

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

    2024年01月15日
    浏览(53)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包