1

Unified identity authentication is the most basic part of the entire IT architecture, and accounts are the basis for unified identity authentication. The planning and design of accounts directly determines the convenience and difficulty of building an enterprise's entire information system, determines whether the system is sufficiently agile and quickly empowered, and determines the investment and efficiency in digital transformation. A user account is a representation of a user's identity. The traditional unified identity authentication system is often used as a peripheral system to integrate various application systems, rather than as a core basic system to be integrated by other application systems. Therefore, there are many problems in the construction of the traditional unified identity authentication system, which complicates the design, management, and integration.
Each enterprise may have multiple systems running at the same time, but each user has only one account in the enterprise, which can be applied to each system. Therefore, this involves how we apply a set of accounts to each system to ensure the permission system of the accounts.
Common method:
1. (The simplest but most abhorrent) copy the data and import it into each system. This will result in heavy maintenance workload and chaotic data. If it is a multi-level enterprise, unimaginable disasters will occur.
2. In identity integration, the development of custom security programs is integrated into each system with a set of user authentication programs.
This article will introduce how to write a custom security provider and configure references in the project from the following three points.

Write a custom security provider

The steps to write a custom security provider are as follows:
(1) Create a project

Use Microsoft Visual Studio 2017 (hereinafter referred to as VS2017), create a new project, select the type as Visual C# - .NET Standard - Class Library (.NET Standard), enter the project name, such as: MySecurityProvider:

(2) Add package dependencies The interface implemented by the custom security provider is defined by several packages, and dependencies on these packages need to be added for this purpose. Methods as below:
First download and save the following two files to the local hard disk, such as the C:\Temp\pkg folder:
grapecity.enterprise.identity.externalidentityprovider.1.0.2.nupkg

GrapeCity.Enterprise.Identity.SecurityProvider.1.0.3.nupkg

Click "NuGet Package Manager" > "Package Manager Settings" from the Tools menu of VS2017:

Select "Package Sources" and click the plus button:

Click the [...] button and specify the "source" path as the folder where the nupkg file is located, such as: C:\temp\pkg

Click the "OK" button to save the settings.
In the Solution Explorer pane on the right, right-click "Dependencies", click "Manage NuGet Packages", then click "Browse", select the newly added package source, and two dependencies will be listed. package:

GrapeCity.Enterprise.Identity.ExternalIdentityProvider and GrapeCity.Enterprise.Identity.SecurityProvider, as shown below:

Select the packages one by one and click "Install" to add the dependencies of this project on these two packages.
(3) Implementing the interface A custom security provider needs to implement two interfaces: ISecurityProviderFactory and ISecurityProvider.
Steps to implement the first interface:
Add a new class file, such as MySecurityProviderFactory.cs, to implement the ISecurityProviderFactory interface.
public class MySecurityProviderFactory: ISecurityProviderFactory
The interface specifies two properties and one method:

 public string Description // 本安全提供程序的描述字串。
public IEnumerable<ConfigurationItem> SupportedSettings // 本安全提供程序支持的用户配置项。

These user configuration items will appear in Wyn's management screen, allowing system administrators to set them up. A typical configuration item is the connection string of the user information database. By providing such a configuration item, you can avoid the problem of hardcoding the user information database connection string in the security provider.
public Task<ISecurityProvider> CreateAsync(IEnumerable<ConfigurationItem> settings) // Instance creation method of this security provider.
The content of this method is almost fixed, such as:

 public Task<ISecurityProvider> CreateAsync(IEnumerable<ConfigurationItem> settings)
{
    return Task.FromResult<ISecurityProvider>(new MySecurityProvider(settings));
}

Implement the ISecurityProvider interface

The ISecurityProvider interface is the core of the security provider, and its specified properties and methods are as follows:

member type name illustrate
Attributes ProviderName Returns the name of this security provider.
method GenerateTokenAsync Verify the username and password, and generate an access token for Wyn when passed.
method GetUserContextAsync Returns the context information of the user, generally based on the user name, the user's department and other business data are obtained from the database query.
method GetUserDescriptorAsync Returns the user's description information, which will be displayed for the currently logged-in user on the portal page.
method GetUserOrganizationsAsync Returns the organizational structure information of the user.
method GetUserRolesAsync Returns the user's role information, multiple roles are returned in the form of a string array.
method ValidateTokenAsync Verify the legitimacy of the token. In business system integration, when using Token to directly access the system, this method is used to check the correctness of the incoming Token.

In addition to the members listed in the above table, there are interfaces such as IExternalUserDescriptor and IExternalUserContext. These interfaces only specify the properties of the entity class, and you can use custom classes to implement these interfaces.

The file attachment below is sample code for a custom security provider.

MySecurityProvider.zip

The solution (.sln) in this sample code can be opened directly in Visual Studio 2017. The sample code folder \bin\debug also contains Build product DLLs that can be configured directly as Wyn's security provider. The user information of the example is saved in the SQL Server database. Please restore the db\MyUsers.bak file in this file package to the SQL Server database.

For a detailed description of the interface, please refer to the interface introduction below.

Interface introduction

ISecurityProviderFactory interface

definition

 public interface ISecurityProviderFactory 
{
    string ProviderName { get; }
    string Description { get; }
    IEnumerable<ConfigurationItem> SupportedSettings { get; }
    Task<ISecurityProvider> CreateAsync(IEnumerable<ConfigurationItem> settings);
}

Interface Description

properties and methods illustrate
ProviderName The name of the security provider, cannot be empty, and cannot have the same name as other security providers.
Description The description text of the security provider, which can be empty.
SupportedSettings Configuration items necessary for this security provider to load and run. For example, if the security provider needs to access the database, the database connection string is a necessary configuration item, which must be configured by the administrator on the security provider management page for the security provider to work properly. You can return an empty list without any required configuration items.
CreateAsync Create an instance of the security provider. The parameter settings is the list of configuration items that have been configured by the administrator, where the user can pass the list of configuration items into the constructed security provider instance through the constructor.

[ISecurityProvider interface]()

definition

 public interface ISecurityProvider
{
    string ProviderName { get; }
    Task DisposeTokenAsync(string token);
    Task<string> GenerateTokenAsync(string username, string password, object customizedParam = null);
    Task<IExternalUserContext> GetUserContextAsync(string token);
    Task<IExternalUserDescriptor> GetUserDescriptorAsync(string token);
    Task<string[]> GetUserOrganizationsAsync(string token);
    Task<string[]> GetUserRolesAsync(string token);
    Task<bool> ValidateTokenAsync(string token);
}

Interface Description

properties and methods illustrate
ProviderName The name of the security provider, cannot be empty, and cannot have the same name as other security providers.
DesposeTokenAsync Invalidate the given token.
GenerateTokenAsync Check whether the given username and password are valid, if valid, return a unique token; otherwise, return null or an empty string. Note: The token can be in any form, such as the user's id, or the encrypted string of the user's information, as long as the security provider can correctly return the relevant information of the user according to the token.
GetUserContextAsync Get the user's contextual information using the given token. What the user's contextual information contains can be arbitrary.
GetUserDescriptor Get the basic information of the user with the given token. The basic information includes the user's id, username and security provider's name, none of which can be empty.
GetUserOrganizationsAsync Use the given token to get the department information the user belongs to. (This interface is not used for the time being).
GetUserRolesAsync Get the user's role information using the given token. Returns the names of roles to which the user belongs. The names of these roles need to exactly match the role names listed in the admin portal, otherwise they will be ignored.
ValidateTokenAsync Verify that the given token is a valid and valid token provided by the security proposer.

IExternalUserDescriptor interface

definition

 public interface IExternalUserDescriptor
{
    string ExternalUserId { get; }
    string ExternalUserName { get; }
    string ExternalProvider { get; }
}

Interface Description

parameter illustrate
ExternalUserId User's unique identifier.
ExternalUserName username.
ExternalProvider The user's provider, which is the name of the security provider.

IExternalUserContext interface <br>definition

 public interface IExternalUserContext
{
    IEnumerable<string> Keys { get; }
    Task<string> GetValueAsync(string key);
    Task<IEnumerable<string>> GetValuesAsync(string key);
}

Interface Description

parameter illustrate
Keys Items contained in the user context information.
GetValueAsync For a given key, get the corresponding user information.
GetValuesAsync For a given key, get its corresponding user information, which is suitable for multi-value cases.

Notice

  • In the implementation function of each interface, there must be try-catch exception handling. In the exception handling part of catch, do not use the throw statement to throw the exception again, but return the Task object, for example: return Task.FromResult<T>(null ); where T is a type specified by the interface function.
  • Do not use the following strings for the user context key: sub, name, auth_time, idp, userid, email.

Configure a custom security provider
(1) File deployment Copy the compiled security provider DLL file to the SecurityProviders folder in the Wyn installation directory. In the Windows environment, the default path is:
C:\Program Files\Wyn\Server\SecurityProviders
Tip If the security provider also depends on other DLLs, please copy them to the same directory as well.
(2) Restart the service

(3) Add User Security Provider Log in to the system's background management website as an administrator, and click "+Add User Provider".

Save with custom security provider checked.

(4) Configure security provider Select the custom security provider you just added, and the configurable setting options will be displayed on the right. The specific options are determined in the security provider's code. Enter these options according to the actual configuration.

After entering, click the "Save" button.

(5) Restart the service To make the settings of the custom security provider take effect, you need to enter the task manager to restart the WynService service.

After that, you can enter the user name and password of the business system in the login window to log in to the Wyn portal.

Precautions In writing security programs, we need to pay attention to several methods

  1. The GenerateTokenAsync method in the MySecurityProvider.cs file, this method is used to verify the login information in the first login. Therefore, the function that needs to be completed in this step is to verify the username and password. The verification method given in the case is to determine the login after directly obtaining the user information from the database. Here you can implement custom authentication methods. It is only necessary to modify the called method of Database.GetUserInfo in this method.
    【Link database for verification】

 public Task<string> GenerateTokenAsync(string username, string password, object customizedParam = null)
        {
            string rst = null;
            try
            {
                var userInfo = Database.GetUserInfo(username, password);
                var roles = userInfo.RoleNames.Split(',');
                var tokenValues = new string[roles.Length + 1];
                tokenValues[0] = userInfo.UserName;
                roles.CopyTo(tokenValues, 1);
                var token = string.Join(Constants.TokenDelimiter, tokenValues);
                token = Convert.ToBase64String(Encoding.UTF8.GetBytes(token));

                rst = token;

                Database.WriteLogS("GenerateTokenAsync token=", token);
                return Task.FromResult(rst);
            }
            catch (Exception e)
            {
                Database.WriteLogS("GenerateTokenAsync", e.ToString());
                return null;
            }

        }

[Custom authentication, you can use api here, you can use encrypted strings and other operations]

 public Task<string> GenerateTokenAsync(string username, string password, object customizedParam = null)
        {
            string rst = null;
            try
            {
                if (customizedParam==null)
                {
                    return null;
                }
                Dictionary<string, string> parameters = (Dictionary<string, string>)customizedParam;
                var userInfo = RSAHelper.UserDecrypt(username, parameters["key"], keyFileName);
                if (userInfo == null)
                {
                    return null;
                }
                var roles = userInfo.RoleNames.Split(',');
                var tokenValues = new string[roles.Length + 1];
                tokenValues[0] = userInfo.UserName;
                roles.CopyTo(tokenValues, 1);
                var token = string.Join(Constants.TokenDelimiter, tokenValues);
                token = Convert.ToBase64String(Encoding.UTF8.GetBytes(token));

                rst = token;

                Database.WriteLogS("GenerateTokenAsync token=", token);
                return Task.FromResult(rst);
            }
            catch (Exception e)
            {
                Database.WriteLogS("GenerateTokenAsync", e.ToString());
                return null;
            }

        }

In the above method, we use custom parameters where key is our custom key-value pair content

It can be configured like this when using: (The custom parameter part must be configured with key:value)

  1. The GetUserContextAsync method in the MySecurityProvider.cs file, according to the method tracking, the method finally called is the GetUserInfoByName method in Database.cs, so the process is ignored and this method can be directly modified.
    Note: The user information returned here will be used directly after logging in in wyn, so pay attention to returning the result information here.
    (Figure 3) [Acquire user-related information based on user name]

【Customize return information】

  1. If other dlls are referenced in the program, you need to place the corresponding dlls in the specified folder when placing the security custom program.
    The path is this (the default installation path, if you change the installation path, you will find it by yourself)
    C:\Program Files\Wyn\Server\SecurityProviders
  2. For log printing, you need to set the path and create a log folder in the C drive, otherwise it will not be printed.

  1. Configure interface information settings


The link character seen on the current page is modified to the secret key (Base64). This can be configured directly in the program, and the content of this method can be directly configured in the MySecurityProviderFactory.cs file.

When getting it: MySecurityProvider.cs can be customized to get it.

  1. Set up the portal
  2. The returned organization, how are the roles handled?
    In the returned information, if there is no organization or role in the system, it cannot be accessed normally. You can set the corresponding organization and role in the background management, and assign the corresponding permissions to the role.
    Set up an organization:

The organization content passed is: "/A/B" The top-level organization information is "/"
Role configuration: set permissions for the corresponding role

  1. Process debugging ctrl+alt+p, select to display all processes of the user, select dotnet.exe to break the breakpoint. Click Attach. Select a breakpoint in the program.

The next step is to package and test. After the program is configured, it can be used for normal testing.

Login API Client Management
login api code example

Generate token through postman call, and generate corresponding security custom program.
In the request parameters: client_id, client_secret is the content generated in Client Management. For details, please refer to the login API client management default information:
client_id:integration
client_secret:eunGKas3Pqd6FMwx9eUpdS7xmz
You can modify it by yourself later.
Request a screenshot:

② The code request is as follows:

 fetch("http://localhost:51980/connect/token", {
"method": "POST",
"headers": {
"Content-type": "application/x-www-form-urlencoded"
},
"body": "grant_type=password&username=admin&password=admin&client_id=integration&client_secret=eunGKas3Pqd6FMwx9eUpdS7xmz"
}).then(function(res){
res.json()
.then(function(data){
console.log(data)
});
})

So far, the token can be obtained, and you can log in directly after obtaining it.
http://localhost:51980/integration?token= generated token

All user identity integration custom development has been implemented here. If you want to learn more about the selected templates in the commercial BI industry, you can visit:
https://www.grapecity.com.cn/solutions/wyn/demo


葡萄城技术团队
2.7k 声望29.3k 粉丝

葡萄城是专业的软件开发技术和低代码平台提供商,聚焦软件开发技术,以“赋能开发者”为使命,致力于通过表格控件、低代码和BI等各类软件开发工具和服务,一站式满足开发者需求,帮助企业提升开发效率并创新开发模式。