如何最好地结合 SQL 服务器数据从 Active Directory 检索用户数据

How best to retrieve user data from Active Directory in conjunction with SQL Server data

我有一个 Web 应用程序,它将其数据存储在 Azure SQL 数据库中,并将有关经过身份验证的用户的数据存储在 Azure Active Directory B2C 中。 SQL 数据库中的数据通过 "oid" (GUID) 与 AD 用户相关。这意味着获取数据库不允许任何人识别特定用户。

但是,当我查询 SQL 数据以向访问者创建 table 或图表时,我显然想显示与拥有数据的用户相关的数据(即显示用户的全名,而不是他们的 oid!)。

我知道在网页上呈现 SQL 查询的结果时我可以使用 Azure Graph API 来获取用户数据,但这似乎是一种非常低效的方法。添加到其中,我不确定我如何在不使用长得离谱的查询字符串过滤器的情况下传入一批 oid 以取回所有用户对象!

我可以创建某种查询整个 AD 的同步过程) 并在定时过程(可能是 Azure 函数)上更新 SQL table,但这似乎也非常低效?

我查看了 Microsoft Graph API webhooks,但目前,似乎没有任何我可以挂钩的关于用户对象更改的订阅,他们不推荐使用 B2C 的 Graph。

我想另一个选择是在某个地方有一个缓存来存储数据以便更快地查找,但这必须更新为。

非常感谢任何建议。

实际上很简单(假设您已经通过身份验证)。使用此作为 GET 请求的模板:

{baseUrl}/{tenantId}/users/{oid}?api-version={api-version}

不要忘记将您的不记名令牌添加到授权中 header:

Authorization: Bearer {accessToken}

此外,这里有一个 object 的示例,您可以将其用于响应(在 Java 中),以及一些用于检索注册电子邮件的有用方法(假设您使用的是内置 B2C用户而不是第三方,例如 google):

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.ArrayList;
import java.util.List;

@JsonIgnoreProperties(ignoreUnknown = true)
public class GraphApiUserExample{

    @JsonProperty("objectId")
    private String id;

    private Boolean accountEnabled;

    private com.brmic.azure.graph.api.client.model.PasswordProfile PasswordProfile;

    private List<SignInName> signInNames;

    private String surname;

    private String displayName;

    private String givenName;

    @JsonProperty("userPrincipalName")
    private String userPrincipalName;

    public String getId(){

        return id;
    }

    public void setId(final String id){

        this.id = id;
    }

    public Boolean getAccountEnabled(){

        return accountEnabled;
    }

    public void setAccountEnabled(final Boolean accountEnabled){

        this.accountEnabled = accountEnabled;
    }

    public com.brmic.azure.graph.api.client.model.PasswordProfile getPasswordProfile(){

        return PasswordProfile;
    }

    public void setPasswordProfile(final com.brmic.azure.graph.api.client.model.PasswordProfile passwordProfile){

        PasswordProfile = passwordProfile;
    }

    public List<SignInName> getSignInNames(){

        return signInNames;
    }

    public void setSignInNames(final List<SignInName> signInNames){

        this.signInNames = signInNames;
    }

    public String getSurname(){

        return surname;
    }

    public void setSurname(final String surname){

        this.surname = surname;
    }

    public String getDisplayName(){

        return displayName;
    }

    public void setDisplayName(final String displayName){

        this.displayName = displayName;
    }

    public String getGivenName(){

        return givenName;
    }

    public void setGivenName(final String givenName){

        this.givenName = givenName;
    }

    public String getUserPrincipalName(){

        return userPrincipalName;
    }

    public void setUserPrincipalName(final String userPrincipalName){

        this.userPrincipalName = userPrincipalName;
    }

    @JsonIgnore
    public String getSignInEmail(){

        String email = "";
        if(signInNames != null){
            for(SignInName signInName : signInNames){
                if(signInName.getType().equals("emailAddress")){
                    email = signInName.getValue();
                    break;
                }
            }
        }
        return email;
    }

    @JsonIgnore
    public void setSignInEmail(String signInEmail){

        if(signInNames == null){
            signInNames = new ArrayList<>();
            signInNames.add(new SignInName("emailAddress", signInEmail));
            return;
        }

        for(SignInName signInName : signInNames){
            if(signInName.getType().equals("emailAddress")){
                signInName.setValue(signInEmail);
                break;
            }
        }
    }
}

如果您想拉取多个用户,您可以添加查询而不是 'oid' 来过滤和分页结果。

{baseUrl}/{tenantId}/users?api-version={api-version}&$skiptoken={skiptoken}&$top={top}&$filter={attributeOne} eq '{valueOne}'
{baseUrl}/{tenantId}/users?api-version={api-version}&$skiptoken={skiptoken}&$top={top}$filter=signInNames/any(x:x/value eq '{email}')

哪个returns一个JSONobject像这样:

{
    "users":[...],
    "odata":{
        "nextLink": "{baseUrl}/{tenantId}/users?api-version={api-version}&$skiptoken={skiptoken}&$top={top}&$filter={attributeOne} eq '{valueOne}'"
        "metadata": "I forget if this is just a string or a parsable JSON object."
    }

}

您仍然会遇到将查询结果与数据库结果进行匹配的问题,这将是一项繁重的操作。 如果您需要 运行 更快的操作,我建议您将结果缓存在 table 中进行连接。 它确实感觉很笨拙,但只是因为它是。

您还可以使用来自 B2C azure powershell 模块的一些 powershell 命令,并且您可以使用 ADAL 在 SQL 服务器中创建作业以更新 table 或视图的内容.

文档在这里:https://docs.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-devquickstarts-graph-dotnet