Share via


Anpassa anspråk som utfärdats i JSON-webbtoken (JWT) för företagsprogram

Microsofts identitetsplattform stöder enkel inloggning (SSO) med de flesta förintegrerade program i Microsoft Entra-programgalleriet och anpassade program. När en användare autentiserar till ett program via Microsofts identitetsplattform med hjälp av OIDC-protokollet skickar Microsofts identitetsplattform en token till programmet. Programmet validerar och använder token för att logga in användaren i stället för att fråga efter ett användarnamn och lösenord.

Dessa JSON-webbtoken (JWT) som används av OIDC- och OAuth-program innehåller information om användaren som kallas anspråk. Ett anspråk är information som en identitetsprovider anger om en användare i den token som de utfärdar för den användaren. I ett OIDC-svar finns anspråksdata vanligtvis i ID-token som utfärdats av identitetsprovidern i form av en JWT.

Visa eller redigera anspråk

Dricks

Stegen i den här artikeln kan variera något beroende på vilken portal du börjar från.

Så här visar eller redigerar du anspråken som utfärdats i JWT till programmet:

  1. Logga in på administrationscentret för Microsoft Entra som minst molnprogramadministratör.
  2. Bläddra till Identity>Applications Enterprise-program>>Alla program.
  3. Välj programmet, välj Enkel inloggning på den vänstra menyn och välj sedan Redigera i avsnittet Attribut och anspråk .

Ett program kan behöva anpassning av anspråk av olika skäl. Till exempel när ett program kräver en annan uppsättning anspråks-URI:er eller anspråksvärden. Med hjälp av avsnittet Attribut och anspråk kan du lägga till eller ta bort ett anspråk för ditt program. Du kan också skapa ett anpassat anspråk som är specifikt för ett program baserat på användningsfallet.

Följande steg beskriver hur du tilldelar ett konstant värde:

  1. Välj det anspråk som du vill ändra.
  2. Ange det konstanta värdet utan citattecken i källattributet enligt din organisation och välj sedan Spara.

Översikten Attribut visar konstantvärdet.

Omvandlingar av särskilda anspråk

Du kan använda följande funktioner för särskilda anspråkstransformeringar.

Function beskrivning
ExtractMailPrefix() Tar bort domänsuffixet från antingen e-postadressen eller användarens huvudnamn. Den här funktionen extraherar endast den första delen av användarnamnet. I stället joe_smith@contoso.comför joe_smith .
ToLower() Konverterar tecknen i det markerade attributet till gemener.
ToUpper() Konverterar tecknen i det markerade attributet till versaler.

Lägga till programspecifika anspråk

Så här lägger du till programspecifika anspråk:

  1. I Användarattribut och anspråk väljer du Lägg till nytt anspråk för att öppna sidan Hantera användaranspråk .
  2. Ange namnetanspråken. Värdet behöver inte följa ett URI-mönster. Om du behöver ett URI-mönster kan du placera det i fältet Namnområde .
  3. Välj den källa där anspråket ska hämta dess värde. Du kan välja ett användarattribut i listrutan för källattributet eller tillämpa en transformering på användarattributet innan du skickar det som ett anspråk.

Anspråkstransformeringar

Så här tillämpar du en transformering på ett användarattribut:

  1. I Hantera anspråk väljer du Transformering som anspråkskälla för att öppna sidan Hantera transformering .
  2. Välj funktionen i listrutan transformering. Beroende på vilken funktion som valts anger du parametrar och ett konstant värde som ska utvärderas i omvandlingen.
  3. Behandla källan som flervärdesvärde anger om transformeringen tillämpas på alla värden eller bara den första. Som standard används transformeringarna som det första elementet i ett anspråk med flera värden. När du markerar den här kryssrutan ser den till att den tillämpas på alla. Den här kryssrutan är endast aktiverad för flervärdesattribut. Exempel: user.proxyaddresses
  4. Om du vill tillämpa flera transformeringar väljer du Lägg till transformering. Du kan använda högst två transformeringar för ett anspråk. Du kan till exempel först extrahera e-postprefixet för user.mail. Gör sedan strängens versaler.

Du kan använda följande funktioner för att transformera anspråk.

Function beskrivning
ExtractMailPrefix() Tar bort domänsuffixet från antingen e-postadressen eller användarens huvudnamn. Den här funktionen extraherar endast den första delen av användarnamnet. I stället joe_smith@contoso.comför joe_smith .
Join() Skapar ett nytt värde genom att koppla två attribut. Du kan också använda en avgränsare mellan de två attributen. För NameID-anspråkstransformering har funktionen Join() ett specifikt beteende när transformeringsindata har en domändel. Den tar bort domändelen från indata innan den kopplas till avgränsaren och den valda parametern. Om till exempel transformeringens indata är joe_smith@contoso.com och avgränsaren är @ och parametern är fabrikam.comresulterar den här indatakombinationen i joe_smith@fabrikam.com.
ToLowercase() Konverterar tecknen i det markerade attributet till gemener.
ToUppercase() Konverterar tecknen i det markerade attributet till versaler.
Contains() Matar ut ett attribut eller en konstant om indata matchar det angivna värdet. Annars kan du ange ytterligare utdata om det inte finns någon matchning.
Om du till exempel vill generera ett anspråk där värdet är användarens e-postadress om det innehåller domänen @contoso.com, vill du annars ange användarens huvudnamn. För att utföra den här funktionen konfigurerar du följande värden:
Parameter 1(indata): user.email
Värde: "@contoso.com"
Parameter 2 (utdata): user.email
Parameter 3 (utdata om det inte finns någon matchning): user.userprincipalname
EndWith() Matar ut ett attribut eller en konstant om indata slutar med det angivna värdet. Annars kan du ange ytterligare utdata om det inte finns någon matchning.
Om du till exempel vill generera ett anspråk där värdet är användarens medarbetar-ID om medarbetar-ID:t slutar med 000, vill du annars mata ut ett tilläggsattribut. För att utföra den här funktionen konfigurerar du följande värden:
Parameter 1(input): user.employeeid
Värde: "000"
Parameter 2 (utdata): user.employeeid
Parameter 3 (utdata om det inte finns någon matchning): user.extensionattribute1
StartWith() Matar ut ett attribut eller en konstant om indata börjar med det angivna värdet. Annars kan du ange ytterligare utdata om det inte finns någon matchning.
Om du till exempel vill generera ett anspråk där värdet är användarens medarbetar-ID om landet/regionen börjar med US, vill du annars mata ut ett tilläggsattribut. För att utföra den här funktionen konfigurerar du följande värden:
Parameter 1(input): user.country
Värde: "US"
Parameter 2 (utdata): user.employeeid
Parameter 3 (utdata om det inte finns någon matchning): user.extensionattribute1
Extract() – Efter matchning Returnerar delsträngen efter att den matchar det angivna värdet.
Om till exempel indatavärdet är Finance_BSimon, är Finance_matchande värde , är BSimonanspråkets utdata .
Extract() – Före matchning Returnerar delsträngen tills den matchar det angivna värdet.
Om till exempel indatavärdet är BSimon_US, är _USmatchande värde , är BSimonanspråkets utdata .
Extract() – mellan matchning Returnerar delsträngen tills den matchar det angivna värdet.
Om till exempel indatavärdet är Finance_BSimon_US, är Finance_det första matchande värdet , det andra matchande värdet är _US, så är BSimonanspråkets utdata .
ExtractAlpha() – prefix Returnerar prefixets alfabetiska del av strängen.
Om till exempel indatavärdet är BSimon_123returnerar BSimondet .
ExtractAlpha() – Suffix Returnerar suffixets alfabetiska del av strängen.
Om till exempel indatavärdet är 123_Simonreturnerar Simondet .
ExtractNumeric() – prefix Returnerar prefixets numeriska del av strängen.
Om till exempel indatavärdet är 123_BSimonreturnerar 123det .
ExtractNumeric() – Suffix Returnerar suffixets numeriska del av strängen.
Om till exempel indatavärdet är BSimon_123returnerar 123det .
IfEmpty() Matar ut ett attribut eller en konstant om indata är null eller tomma.
Om du till exempel vill mata ut ett attribut som lagras i ett tilläggsattribut om medarbetar-ID:t för en viss användare är tomt. Konfigurera följande värden för att utföra den här funktionen:
Parameter 1(input): user.employeeid
Parameter 2 (utdata): user.extensionattribute1
Parameter 3 (utdata om det inte finns någon matchning): user.employeeid
IfNotEmpty() Matar ut ett attribut eller en konstant om indata inte är null eller tomma.
Om du till exempel vill mata ut ett attribut som lagras i ett tilläggsattribut om medarbetar-ID:t för en viss användare inte är tomt. För att utföra den här funktionen konfigurerar du följande värden:
Parameter 1(input): user.employeeid
Parameter 2 (utdata): user.extensionattribute1
Delsträng() – Fast längd Extraherar delar av en stränganspråkstyp med början vid tecknet vid den angivna positionen och returnerar det angivna antalet tecken.
SourceClaim – anspråkskällan för den transformering som ska köras.
StartIndex – den nollbaserade startteckenpositionen för en delsträng i den här instansen.
Längd – längden i tecken i delsträngen.
Till exempel:
sourceClaim – PleaseExtractThisNow
StartIndex - 6
Längd - 11
Utdata: ExtractThis
Substring() – EndOfString Extraherar delar av en stränganspråkstyp med början vid tecknet vid den angivna positionen och returnerar resten av anspråket från det angivna startindexet.
SourceClaim – anspråkskällan för transformering.
StartIndex – den nollbaserade startteckenpositionen för en delsträng i den här instansen.
Till exempel:
sourceClaim – PleaseExtractThisNow
StartIndex - 6
Utdata: ExtractThisNow
RegexReplace() RegexReplace()-transformering accepterar som indataparametrar:
– Parameter 1: ett användarattribut som regex-indata
– Ett alternativ för att lita på källan som flervärdes
– Regex-mönster
- Ersättningsmönster. Ersättningsmönstret kan innehålla statiskt textformat tillsammans med en referens som pekar på regex-utdatagrupper och fler indataparametrar.

Om du behöver andra transformeringar skickar du din idé i feedbackforumet i Microsoft Entra-ID under kategorin SaaS-program .

Regex-baserad anspråkstransformering

Följande bild visar ett exempel på den första omvandlingsnivån:

Screenshot of the first level of transformation.

Följande tabell innehåller information om den första nivån av transformeringar. De åtgärder som anges i tabellen motsvarar etiketterna i föregående bild. Välj Redigera för att öppna bladet för anspråkstransformering.

Åtgärd Fält beskrivning
1 Transformation Välj alternativet RegexReplace() från transformeringsalternativen för att använda den regex-baserade anspråkstransformeringsmetoden för anspråkstransformering.
2 Parameter 1 Indata för transformering av reguljära uttryck. Till exempel user.mail som har en e-postadress för användaren, admin@fabrikam.comtill exempel .
3 Treat source as multivalued Vissa indataanvändarattribut kan vara användarattribut med flera värden. Om det valda användarattributet stöder flera värden och användaren vill använda flera värden för omvandlingen måste de välja Behandla källa som flervärdesvärde. Om du väljer det här alternativet används alla värden för regex-matchningen, annars används endast det första värdet.
4 Regex pattern Ett reguljärt uttryck som utvärderas mot värdet för användarattributet som valts som Parameter 1. Ett reguljärt uttryck för att extrahera användaraliaset från användarens e-postadress representeras till exempel som (?'domain'^.*?)(?i)(\@fabrikam\.com)$.
5 Add additional parameter Mer än ett användarattribut kan användas för omvandlingen. Värdena för attributen sammanfogas sedan med regex-transformeringsutdata. Upp till fem parametrar stöds.
6 Replacement pattern Ersättningsmönstret är textmallen som innehåller platshållare för regex-utfall. Alla gruppnamn måste omslutas i klammerparenteserna, till exempel {gruppnamn}. Anta att administrationen vill använda användaralias med något annat domännamn, till exempel xyz.com och koppla landsnamn med det. I det här fallet skulle ersättningsmönstret vara {country}.{domain}@xyz.com, där {country} är värdet för indataparametern och {domain} är grupputdata från utvärderingen av reguljära uttryck. I sådana fall är US.swmal@xyz.comdet förväntade resultatet .

Följande bild visar ett exempel på den andra omvandlingsnivån:

Screenshot of second level of claims transformation.

Följande tabell innehåller information om den andra nivån av transformeringar. De åtgärder som anges i tabellen motsvarar etiketterna i föregående bild.

Åtgärd Fält beskrivning
1 Transformation Regex-baserade anspråkstransformeringar är inte begränsade till den första omvandlingen och kan även användas som transformering på andra nivån. Alla andra transformeringsmetoder kan användas som den första omvandlingen.
2 Parameter 1 Om RegexReplace() väljs som en transformering på andra nivån används utdata från transformering på första nivån som indata för omvandlingen på andra nivån. Om du vill tillämpa transformeringen ska regex-uttrycket på andra nivån matcha utdata från den första omvandlingen.
3 Regex pattern Regex-mönstret är det reguljära uttrycket för transformering på andra nivån.
4 Parameter input Användarattributindata för omvandlingar på andra nivån.
5 Parameter input Administratörer kan ta bort den valda indataparametern om de inte längre behöver den.
6 Replacement pattern Ersättningsmönstret är textmallen, som innehåller platshållare för regex-resultatgruppnamn, indataparametergruppnamn och statiskt textvärde. Alla gruppnamn måste omslutas i klammerparenteserna, till exempel {group-name}. Anta att administrationen vill använda användaralias med något annat domännamn, till exempel xyz.com och koppla landsnamn med det. I det här fallet skulle ersättningsmönstret vara {country}.{domain}@xyz.com, där {country} är värdet för indataparametern och {domain} är grupputdata från utvärderingen av reguljära uttryck. I sådana fall är US.swmal@xyz.comdet förväntade resultatet .
7 Test transformation Transformering av RegexReplace() utvärderas endast om värdet för det valda användarattributet för Parameter 1 matchar det reguljära uttrycket som anges i textrutan Regex-mönster . Om de inte matchar läggs standardanspråkvärdet till i token. För att validera reguljära uttryck mot indataparametervärdet är en testupplevelse tillgänglig på transformeringsbladet. Den här testupplevelsen fungerar endast på dummy-värden. När fler indataparametrar används läggs namnet på parametern till i testresultatet i stället för det faktiska värdet. Om du vill komma åt testavsnittet väljer du Testtransformering.

Följande bild visar ett exempel på hur du testar transformeringarna:

Screenshot of testing the transformation.

Följande tabell innehåller information om hur du testar transformeringarna. De åtgärder som anges i tabellen motsvarar etiketterna i föregående bild.

Åtgärd Fält beskrivning
1 Test transformation Välj knappen stäng eller (X) för att dölja testavsnittet och åter återge knappen Testtransformering igen på bladet.
2 Test regex input Accepterar indata som används för utvärdering av reguljära uttryckstest. Om regex-baserad anspråkstransformering konfigureras som en transformering på andra nivån anger du ett värde som är förväntade utdata från den första omvandlingen.
3 Run test När regex-testindata har angetts och Regex-mönstret, ersättningsmönstret och indataparametrarna har konfigurerats kan uttrycket utvärderas genom att välja Kör test.
4 Test transformation result Om utvärderingen lyckas renderas utdata från testtransformeringen mot resultatetiketten Testtransformering.
5 Remove transformation Den andra nivåtransformeringen kan tas bort genom att välja Ta bort transformering.
6 Specify output if no match När ett regex-indatavärde konfigureras mot parametern 1 som inte matchar reguljära uttryck hoppas transformeringen över. I sådana fall kan det alternativa användarattributet konfigureras, vilket läggs till i token för anspråket genom att kontrollera Ange utdata om det inte finns någon matchning.
7 Parameter 3 Om ett alternativt användarattribut måste returneras när det inte finns någon matchning och Ange utdata om ingen matchning är markerad kan ett alternativt användarattribut väljas med listrutan. Den här listrutan är tillgänglig mot Parameter 3 (utdata om ingen matchning).
8 Summary Längst ned på bladet visas en fullständig sammanfattning av formatet som förklarar innebörden av omvandlingen i enkel text.
9 Add När konfigurationsinställningarna för omvandlingen har verifierats kan den sparas i en anspråksprincip genom att välja Lägg till. Spara ändringarna genom att välja Spara på bladet Hantera anspråk.

RegexReplace()-transformering är också tillgänglig för omvandlingar av gruppanspråk.

Transformeringsvalidering

Ett meddelande innehåller mer information när följande villkor inträffar när du har valt Lägg till eller Kör test:

  • Indataparametrar med duplicerade användarattribut användes.
  • Oanvända indataparametrar hittades. Definierade indataparametrar ska ha respektive användning i text för ersättningsmönster.
  • Angivna regex-indata för test matchar inte det angivna reguljära uttrycket.
  • Inga källor för grupperna i ersättningsmönstret hittas.

Generera anspråk baserat på villkor

Du kan ange källan för ett anspråk baserat på användartyp och den grupp som användaren tillhör.

Användartypen kan vara:

  • Alla – Alla användare får åtkomst till programmet.
  • Medlemmar: Intern medlem i klientorganisationen
  • Alla gäster: Användaren har flyttat från en extern organisation med eller utan Microsoft Entra-ID.
  • Microsoft Entra-gäster: Gästanvändare tillhör en annan organisation med hjälp av Microsoft Entra-ID.
  • Externa gäster: Gästanvändaren tillhör en extern organisation som inte har Microsoft Entra-ID.

Ett scenario där användartypen är användbar är när källan till ett anspråk skiljer sig för en gäst och en anställd som har åtkomst till ett program. Du kan ange att om användaren är anställd hämtar du NameID från user.email. Om användaren är gäst kommer NameID från user.extensionattribute1.

Så här lägger du till ett anspråksvillkor:

  1. I Hantera anspråk expanderar du anspråksvillkoren.
  2. Välj användartyp.
  3. Välj de grupper som användaren ska tillhöra. Du kan välja upp till 50 unika grupper för alla anspråk för ett visst program.
  4. Välj den källa där anspråket ska hämta dess värde. Du kan välja ett användarattribut i listrutan för källattributet eller tillämpa en transformering på användarattributet innan du skickar det som ett anspråk.

I vilken ordning du lägger till villkoren är viktigt. Microsoft Entra utvärderar först alla villkor med källan Attribute och utvärderar sedan alla villkor med källan Transformation för att bestämma vilket värde som ska genereras i anspråket. Microsoft Entra ID utvärderar villkor med samma källa uppifrån och ned. Anspråket genererar det sista värdet som matchar uttrycket i anspråket. Transformeringar som IsNotEmpty och Contains fungerar som begränsningar.

Britta Simon är till exempel gästanvändare i Contoso-klientorganisationen. Britta tillhör en annan organisation som också använder Microsoft Entra-ID. Med följande konfiguration för Fabrikam-programmet utvärderar Microsofts identitetsplattform villkoren när Britta försöker logga in på Fabrikam.

Först kontrollerar Microsofts identitetsplattform om Brittas användartyp är Alla gäster. Eftersom typen är Alla gäster tilldelar Microsofts identitetsplattform källan för anspråket till user.extensionattribute1. För det andra kontrollerar Microsofts identitetsplattform om Brittas användartyp är Microsoft Entra-gäster. Eftersom typen är Alla gäster tilldelar Microsofts identitetsplattform källan för anspråket till user.mail. Slutligen genereras anspråket med värdet user.mail för för Britta.

Som ett annat exempel bör du överväga när Britta Simon försöker logga in med hjälp av följande konfiguration. Microsoft Entra utvärderar först alla villkor med källan Attribute. Källan för anspråket är user.mail när Brittas användartyp är Microsoft Entra-gäster. Därefter utvärderar Microsoft Entra-ID omvandlingarna. Eftersom Britta är gäst user.extensionattribute1 är den nya källan för anspråket. Eftersom Britta finns i Microsoft Entra-gäster är user.othermail den nya källan för det här anspråket. Slutligen genereras anspråket med värdet user.othermail för för Britta.

Som ett sista exempel bör du tänka på vad som händer om Britta inte har konfigurerats user.othermail eller om det är tomt. Anspråket återgår till att user.extensionattribute1 ignorera villkorsposten i båda fallen.

Säkerhetsfrågor

Program som tar emot token förlitar sig på anspråksvärden som inte kan manipuleras. När du ändrar tokeninnehållet via anspråksanpassning kanske dessa antaganden inte längre är korrekta. Program måste uttryckligen bekräfta att token har ändrats för att skydda sig mot anpassningar som skapats av skadliga aktörer. Skydda mot olämpliga anpassningar på något av följande sätt:

Utan detta returnerar Microsoft Entra-ID en AADSTS50146 felkod.

Konfigurera en anpassad signeringsnyckel

För appar med flera klientorganisationer ska en anpassad signeringsnyckel användas. Ange inte acceptMappedClaims i appmanifestet. När du konfigurerar en app i Azure-portalen får du ett appregistreringsobjekt och ett huvudnamn för tjänsten i din klientorganisation. Den appen använder den globala inloggningsnyckeln i Azure, som inte kan användas för att anpassa anspråk i token. Om du vill hämta anpassade anspråk i token skapar du en anpassad inloggningsnyckel från ett certifikat och lägger till den i tjänstens huvudnamn. I testsyfte kan du använda ett självsignerat certifikat. När du har konfigurerat den anpassade signeringsnyckeln måste programkoden verifiera tokensigneringsnyckeln.

Lägg till följande information i tjänstens huvudnamn:

Extrahera den privata och offentliga nyckeln base-64 som kodas från PFX-filexporten av certifikatet. Kontrollera att keyId för det keyCredential som används för "Sign" matchar keyIdpasswordCredentialför . Du kan generera customkeyIdentifier genom att hämta hashen för certifikatets tumavtryck.

Begär

Kommentar

Inaktivera först konfigurationen av tjänsthuvudnamnslås på nyligen skapade appar från bladet Appregistreringar i Microsoft Entra Administrationscenter innan du försöker göra en PATCH på tjänstens huvudnamn, vilket resulterar i en 400 felaktig begäran.

I följande exempel visas formatet för HTTP PATCH-begäran om att lägga till en anpassad signeringsnyckel i tjänstens huvudnamn. Värdet "nyckel" i egenskapen keyCredentials förkortas för läsbarhet. Värdet är base-64-kodat. För den privata nyckeln är Signegenskapsanvändningen . För den offentliga nyckeln är Verifyegenskapsanvändningen .

PATCH https://graph.microsoft.com/v1.0/servicePrincipals/f47a6776-bca7-4f2e-bc6c-eec59d058e3e

Content-type: servicePrincipals/json
Authorization: Bearer {token}

{
    "keyCredentials":[
        {
            "customKeyIdentifier": "lY85bR8r6yWTW6jnciNEONwlVhDyiQjdVLgPDnkI5mA=", 
            "endDateTime": "2021-04-22T22:10:13Z",
            "keyId": "4c266507-3e74-4b91-aeba-18a25b450f6e",
            "startDateTime": "2020-04-22T21:50:13Z",
            "type": "X509CertAndPassword",
            "usage": "Sign",
            "key":"MIIKIAIBAz.....HBgUrDgMCERE20nuTptI9MEFCh2Ih2jaaLZBZGeZBRFVNXeZmAAgIH0A==",
            "displayName": "CN=contoso"
        },
        {
            "customKeyIdentifier": "lY85bR8r6yWTW6jnciNEONwlVhDyiQjdVLgPDnkI5mA=",
            "endDateTime": "2021-04-22T22:10:13Z",
            "keyId": "e35a7d11-fef0-49ad-9f3e-aacbe0a42c42",
            "startDateTime": "2020-04-22T21:50:13Z",
            "type": "AsymmetricX509Cert",
            "usage": "Verify",
            "key": "MIIDJzCCAg+gAw......CTxQvJ/zN3bafeesMSueR83hlCSyg==",
            "displayName": "CN=contoso"
        }

    ],
    "passwordCredentials": [
        {
            "customKeyIdentifier": "lY85bR8r6yWTW6jnciNEONwlVhDyiQjdVLgPDnkI5mA=",
            "keyId": "4c266507-3e74-4b91-aeba-18a25b450f6e",
            "endDateTime": "2022-01-27T19:40:33Z",
            "startDateTime": "2020-04-20T19:40:33Z",
            "secretText": "mypassword"
        }
    ]
}

Konfigurera en anpassad signeringsnyckel med PowerShell

Använd PowerShell för att instansiera ett offentligt MSAL-klientprogram och använda flödet Bevilja auktoriseringskod för att hämta en delegerad behörighetsåtkomsttoken för Microsoft Graph. Använd åtkomsttoken för att anropa Microsoft Graph och konfigurera en anpassad signeringsnyckel för tjänstens huvudnamn. När du har konfigurerat den anpassade signeringsnyckeln måste programkoden verifiera tokensigneringsnyckeln.

Om du vill köra det här skriptet behöver du:

  • Objekt-ID:t för programmets tjänsthuvudnamn finns på översiktsbladet för programmets post i Företagsprogram i Azure-portalen.
  • En appregistrering för att logga in en användare och få en åtkomsttoken för att anropa Microsoft Graph. Hämta appens program-ID (klient) på bladet Översikt för programmets post i Appregistreringar i Azure-portalen. Appregistreringen bör ha följande konfiguration:
    • En omdirigerings-URI för "http://localhost" i plattformskonfigurationen för mobil- och skrivbordsprogram .
    • I API-behörigheter har Microsoft Graph delegerade behörigheter Application.ReadWrite.All och User.Read (se till att du ger administratörsmedgivande till dessa behörigheter).
  • En användare som loggar in för att hämta Åtkomsttoken för Microsoft Graph. Användaren bör vara en av följande administrativa Roller för Microsoft Entra (krävs för att uppdatera tjänstens huvudnamn):
    • Molnappadministratör
    • Appadministratör
    • Global administratör för
  • Ett certifikat som ska konfigureras som en anpassad signeringsnyckel för vårt program. Du kan antingen skapa ett självsignerat certifikat eller hämta ett från din betrodda certifikatutfärdare. Följande certifikatkomponenter används i skriptet:
    • offentlig nyckel (vanligtvis en .cer fil)
    • privat nyckel i PKCS#12-format (i .pfx-fil)
    • lösenord för den privata nyckeln (pfx-fil)

Viktigt!

Den privata nyckeln måste vara i PKCS#12-format eftersom Microsoft Entra ID inte stöder andra formattyper. Om du använder fel format kan det resultera i felet "Ogiltigt certifikat: Nyckelvärdet är ogiltigt certifikat" när du använder Microsoft Graph för att KORRIGERA tjänstens huvudnamn med en keyCredentials som innehåller certifikatinformationen.

$fqdn="fourthcoffeetest.onmicrosoft.com" # this is used for the 'issued to' and 'issued by' field of the certificate
$pwd="mypassword" # password for exporting the certificate private key
$location="C:\\temp" # path to folder where both the pfx and cer file will be written to

# Create a self-signed cert
$cert = New-SelfSignedCertificate -certstorelocation cert:\currentuser\my -DnsName $fqdn
$pwdSecure = ConvertTo-SecureString -String $pwd -Force -AsPlainText
$path = 'cert:\currentuser\my\' + $cert.Thumbprint
$cerFile = $location + "\\" + $fqdn + ".cer"
$pfxFile = $location + "\\" + $fqdn + ".pfx"
 
# Export the public and private keys
Export-PfxCertificate -cert $path -FilePath $pfxFile -Password $pwdSecure
Export-Certificate -cert $path -FilePath $cerFile

$ClientID = "<app-id>"
$loginURL       = "https://login.microsoftonline.com"
$tenantdomain   = "fourthcoffeetest.onmicrosoft.com"
$redirectURL = "http://localhost" # this reply URL is needed for PowerShell Core 
[string[]] $Scopes = "https://graph.microsoft.com/.default"
$pfxpath = $pfxFile # path to pfx file
$cerpath = $cerFile # path to cer file
$SPOID = "<service-principal-id>"
$graphuri = "https://graph.microsoft.com/v1.0/serviceprincipals/$SPOID"
$password = $pwd  # password for the pfx file
 
 
# choose the correct folder name for MSAL based on PowerShell version 5.1 (.Net) or PowerShell Core (.Net Core)
 
if ($PSVersionTable.PSVersion.Major -gt 5)
    { 
        $core = $true
        $foldername =  "netcoreapp2.1"
    }
else
    { 
        $core = $false
        $foldername = "net45"
    }
 
# Load the MSAL/microsoft.identity/client assembly -- needed once per PowerShell session
[System.Reflection.Assembly]::LoadFrom((Get-ChildItem C:/Users/<username>/.nuget/packages/microsoft.identity.client/4.32.1/lib/$foldername/Microsoft.Identity.Client.dll).fullname) | out-null
  
$global:app = $null
  
$ClientApplicationBuilder = [Microsoft.Identity.Client.PublicClientApplicationBuilder]::Create($ClientID)
[void]$ClientApplicationBuilder.WithAuthority($("$loginURL/$tenantdomain"))
[void]$ClientApplicationBuilder.WithRedirectUri($redirectURL)
 
$global:app = $ClientApplicationBuilder.Build()
  
Function Get-GraphAccessTokenFromMSAL {
    [Microsoft.Identity.Client.AuthenticationResult] $authResult  = $null
    $AquireTokenParameters = $global:app.AcquireTokenInteractive($Scopes)
    [IntPtr] $ParentWindow = [System.Diagnostics.Process]::GetCurrentProcess().MainWindowHandle
    if ($ParentWindow)
    {
        [void]$AquireTokenParameters.WithParentActivityOrWindow($ParentWindow)
    }
    try {
        $authResult = $AquireTokenParameters.ExecuteAsync().GetAwaiter().GetResult()
    }
    catch {
        $ErrorMessage = $_.Exception.Message
        Write-Host $ErrorMessage
    }
     
    return $authResult
}
  
$myvar = Get-GraphAccessTokenFromMSAL
if ($myvar)
{
    $GraphAccessToken = $myvar.AccessToken
    Write-Host "Access Token: " $myvar.AccessToken
    #$GraphAccessToken = "eyJ0eXAiOiJKV1QiL ... iPxstltKQ"
    
 
    #  this is for PowerShell Core
    $Secure_String_Pwd = ConvertTo-SecureString $password -AsPlainText -Force
 
    # reading certificate files and creating Certificate Object
    if ($core)
    {
        $pfx_cert = get-content $pfxpath -AsByteStream -Raw
        $cer_cert = get-content $cerpath -AsByteStream -Raw
        $cert = Get-PfxCertificate -FilePath $pfxpath -Password $Secure_String_Pwd
    }
    else
    {
        $pfx_cert = get-content $pfxpath -Encoding Byte
        $cer_cert = get-content $cerpath -Encoding Byte
        # Write-Host "Enter password for the pfx file..."
        # calling Get-PfxCertificate in PowerShell 5.1 prompts for password
        # $cert = Get-PfxCertificate -FilePath $pfxpath
        $cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new($pfxpath, $password)
    }
 
    # base 64 encode the private key and public key
    $base64pfx = [System.Convert]::ToBase64String($pfx_cert)
    $base64cer = [System.Convert]::ToBase64String($cer_cert)
 
    # getting id for the keyCredential object
    $guid1 = New-Guid
    $guid2 = New-Guid
 
    # get the custom key identifier from the certificate thumbprint:
    $hasher = [System.Security.Cryptography.HashAlgorithm]::Create('sha256')
    $hash = $hasher.ComputeHash([System.Text.Encoding]::UTF8.GetBytes($cert.Thumbprint))
    $customKeyIdentifier = [System.Convert]::ToBase64String($hash)
 
    # get end date and start date for our keycredentials
    $endDateTime = ($cert.NotAfter).ToUniversalTime().ToString( "yyyy-MM-ddTHH:mm:ssZ" )
    $startDateTime = ($cert.NotBefore).ToUniversalTime().ToString( "yyyy-MM-ddTHH:mm:ssZ" )
 
    # building our json payload
    $object = [ordered]@{    
    keyCredentials = @(       
         [ordered]@{            
            customKeyIdentifier = $customKeyIdentifier
            endDateTime = $endDateTime
            keyId = $guid1
            startDateTime = $startDateTime 
            type = "X509CertAndPassword"
            usage = "Sign"
            key = $base64pfx
            displayName = "CN=fourthcoffeetest" 
        },
        [ordered]@{            
            customKeyIdentifier = $customKeyIdentifier
            endDateTime = $endDateTime
            keyId = $guid2
            startDateTime = $startDateTime 
            type = "AsymmetricX509Cert"
            usage = "Verify"
            key = $base64cer
            displayName = "CN=fourthcoffeetest"   
        }
        )  
    passwordCredentials = @(
        [ordered]@{
            customKeyIdentifier = $customKeyIdentifier
            keyId = $guid1           
            endDateTime = $endDateTime
            startDateTime = $startDateTime
            secretText = $password
        }
    )
    }
 
    $json = $object | ConvertTo-Json -Depth 99
    Write-Host "JSON Payload:"
    Write-Output $json
 
    # Request Header
    $Header = @{}
    $Header.Add("Authorization","Bearer $($GraphAccessToken)")
    $Header.Add("Content-Type","application/json")
 
    try 
    {
        Invoke-RestMethod -Uri $graphuri -Method "PATCH" -Headers $Header -Body $json
    } 
    catch 
    {
        # Dig into the exception to get the Response details.
        # Note that value__ is not a typo.
        Write-Host "StatusCode:" $_.Exception.Response.StatusCode.value__ 
        Write-Host "StatusDescription:" $_.Exception.Response.StatusDescription
    }
 
    Write-Host "Complete Request"
}
else
{
    Write-Host "Fail to get Access Token"
}

Verifiera tokensigneringsnyckel

Appar som har aktiverat anspråksmappning måste verifiera sina tokensigneringsnycklar genom att lägga appid={client_id} till sina OpenID-Anslut metadatabegäranden. I följande exempel visas formatet för det OpenID-Anslut metadatadokument som du bör använda:

https://login.microsoftonline.com/{tenant}/v2.0/.well-known/openid-configuration?appid={client-id}

Uppdatera programmanifestet

För appar för en enskild klientorganisation kan du ange acceptMappedClaims egenskapen till true i programmanifestet. Enligt beskrivningen i apiApplication resurstypen. Om du anger egenskapen kan ett program använda anspråksmappning utan att ange en anpassad signeringsnyckel.

Varning

Ange inte egenskapen acceptMappedClaims till true för appar med flera klientorganisationer, vilket kan göra det möjligt för skadliga aktörer att skapa principer för anspråksmappning för din app.

Den begärda tokenpubliken måste använda ett verifierat domännamn för din Microsoft Entra-klientorganisation, vilket innebär att du bör ange Application ID URI (representeras av identifierUris i programmanifestet) till exempel till https://contoso.com/my-api eller (helt enkelt med standardklientnamnet) https://contoso.onmicrosoft.com/my-api.

Om du inte använder en verifierad domän returnerar Microsoft Entra-ID en AADSTS501461 felkod med meddelandet "_AcceptMappedClaims stöds endast för en tokenpublik som matchar programmets GUID eller en målgrupp inom klientorganisationens verifierade domäner. Ändra antingen resursidentifieraren eller använd en programspecifik signeringsnyckel."

Avancerade anspråksalternativ

Konfigurera avancerade anspråksalternativ för OIDC-program för att exponera samma anspråk som SAML-token. Även för program som tänker använda samma anspråk för både SAML2.0- och OIDC-svarstoken.

Konfigurera avancerade anspråksalternativ genom att markera kryssrutan under Avancerade anspråksalternativbladet Hantera anspråk .

Nästa steg