Megosztás a következőn keresztül:


Szolgáltatások bevezetése a célközönségek számára egy Go Gin-webalkalmazásban

Ebben az útmutatóban a célzási szűrővel fog létrehozni egy funkciót a Go Gin-webalkalmazás célközönségei számára. A célzási szűrővel kapcsolatos további információkért lásd : Szolgáltatások bevezetése a célközönségek számára.

Prerequisites

Webalkalmazás létrehozása funkciójelölővel

Ebben a szakaszban egy webalkalmazást hoz létre, amely lehetővé teszi a felhasználók számára, hogy bejelentkezhessenek, és a korábban létrehozott bétafunkció-jelzőt használják.

  1. Hozzon létre egy új könyvtárat a Go-projekthez, és navigáljon hozzá:

    mkdir gin-targeting-quickstart
    cd gin-targeting-quickstart
    
  2. Új Go-modul inicializálása:

    go mod init gin-targeting-quickstart
    
  3. Telepítse a szükséges Go-csomagokat:

    go get github.com/gin-gonic/gin
    go get github.com/gin-contrib/sessions
    go get github.com/gin-contrib/sessions/cookie
    go get github.com/microsoft/Featuremanagement-Go/featuremanagement
    go get github.com/microsoft/Featuremanagement-Go/featuremanagement/providers/azappconfig
    
  4. Hozzon létre egy sablonkönyvtárat a HTML-sablonokhoz, és adja hozzá a szükséges HTML-fájlokat:

    mkdir templates
    

    Adja hozzá a következő HTML-sablonfájlokat a GitHub-adattárból , és helyezze őket a templates könyvtárba:

  5. Hozzon létre egy fájlt appconfig.go az alábbi tartalommal. Az alkalmazáskonfigurációs áruházhoz a Microsoft Entra-azonosító (ajánlott) vagy egy kapcsolati sztring használatával csatlakozhat.

    package main
    
    import (
        "context"
        "log"
        "os"
    
        "github.com/Azure/AppConfiguration-GoProvider/azureappconfiguration"
        "github.com/Azure/azure-sdk-for-go/sdk/azidentity"
    )
    
    func loadAzureAppConfiguration(ctx context.Context) (*azureappconfiguration.AzureAppConfiguration, error) {
        // Get the endpoint from environment variable
        endpoint := os.Getenv("AZURE_APPCONFIG_ENDPOINT")
        if endpoint == "" {
            log.Fatal("AZURE_APPCONFIG_ENDPOINT environment variable is not set")
        }
    
        // Create a credential using DefaultAzureCredential
        credential, err := azidentity.NewDefaultAzureCredential(nil)
        if err != nil {
            log.Fatalf("Failed to create credential: %v", err)
        }
    
        // Set up authentication options with endpoint and credential
        authOptions := azureappconfiguration.AuthenticationOptions{
            Endpoint:   endpoint,
            Credential: credential,
        }
    
        // Set up options to enable feature flags
        options := &azureappconfiguration.Options{
            FeatureFlagOptions: azureappconfiguration.FeatureFlagOptions{
                Enabled: true,
                RefreshOptions: azureappconfiguration.RefreshOptions{
                    Enabled: true,
                },
            },
        }
    
        // Load configuration from Azure App Configuration
        appConfig, err := azureappconfiguration.Load(ctx, authOptions, options)
        if err != nil {
            log.Fatalf("Failed to load configuration: %v", err)
        }
    
        return appConfig, nil
    }
    

Célzás használata funkciójelzőkkel

  1. Hozzon létre egy fájlt main.go az alábbi tartalommal.

    package main
    
    import (
        "context"
        "fmt"
        "log"
        "net/http"
        "strings"
    
        "github.com/gin-contrib/sessions"
        "github.com/gin-contrib/sessions/cookie"
        "github.com/gin-gonic/gin"
        "github.com/microsoft/Featuremanagement-Go/featuremanagement"
        "github.com/microsoft/Featuremanagement-Go/featuremanagement/providers/azappconfig"
    )
    
    type WebApp struct {
        featureManager *featuremanagement.FeatureManager
        appConfig      *azureappconfiguration.AzureAppConfiguration
    }
    
    func main() {
        // Load Azure App Configuration
        appConfig, err := loadAzureAppConfiguration(context.Background())
        if err != nil {
            log.Fatalf("Error loading Azure App Configuration: %v", err)
        }
    
        // Create feature flag provider
        featureFlagProvider, err := azappconfig.NewFeatureFlagProvider(appConfig)
        if err != nil {
            log.Fatalf("Error creating feature flag provider: %v", err)
        }
    
        // Create feature manager
        featureManager, err := featuremanagement.NewFeatureManager(featureFlagProvider, nil)
        if err != nil {
            log.Fatalf("Error creating feature manager: %v", err)
        }
    
        // Create web app
        app := &WebApp{
            featureManager: featureManager,
            appConfig:      appConfig,
        }
    
        // Setup Gin with default middleware (Logger and Recovery)
        r := gin.Default()
    
        // Start server
        if err := r.Run(":8080"); err != nil {
            log.Fatalf("Failed to start server: %v", err)
        }
    
        fmt.Println("Starting server on http://localhost:8080")
        fmt.Println("Open http://localhost:8080 in your browser")
        fmt.Println()
    }
    
  2. Engedélyezze a konfigurálást és a funkciójelző frissítését az Azure App Configuration-ból a köztes szoftverrel.

    // Existing code
    // ... ...
    
    func (app *WebApp) refreshMiddleware() gin.HandlerFunc {
        return func(c *gin.Context) {
            go func() {
                if err := app.appConfig.Refresh(context.Background()); err != nil {
                    log.Printf("Error refreshing configuration: %v", err)
                }
            }()
            c.Next()
        }
    }
    
    func (app *WebApp) featureMiddleware() gin.HandlerFunc {
        return func(c *gin.Context) {
            // Get current user from session
            session := sessions.Default(c)
            username := session.Get("username")
    
            var betaEnabled bool
            var targetingContext featuremanagement.TargetingContext
            if username != nil {
                // Evaluate Beta feature with targeting context
                var err error
                targetingContext = createTargetingContext(username.(string))
                betaEnabled, err = app.featureManager.IsEnabledWithAppContext("Beta", targetingContext)
                if err != nil {
                    log.Printf("Error checking Beta feature with targeting: %v", err)
                }
            }
    
            c.Set("betaEnabled", betaEnabled)
            c.Set("user", username)
            c.Set("targetingContext", targetingContext)
            c.Next()
        }
    }
    
    // Helper function to create TargetingContext
    func createTargetingContext(userID string) featuremanagement.TargetingContext {
        targetingContext := featuremanagement.TargetingContext{
            UserID: userID,
            Groups: []string{},
        }
    
        if strings.Contains(userID, "@") {
            parts := strings.Split(userID, "@")
            if len(parts) == 2 {
                targetingContext.Groups = append(targetingContext.Groups, parts[1]) // Add domain as group
            }
        }
    
        return targetingContext
    }
    
    // The rest of existing code
    //... ...
    
  3. Állítsa be az útvonalakat a következő tartalommal:

    // Existing code
    // ... ...
    
    func (app *WebApp) setupRoutes(r *gin.Engine) {
        // Setup sessions
        store := cookie.NewStore([]byte("secret-key-change-in-production"))
        store.Options(sessions.Options{
            MaxAge:   3600, // 1 hour
            HttpOnly: true,
            Secure:   false, // Set to true in production with HTTPS
        })
        r.Use(sessions.Sessions("session", store))
    
    
        r.Use(app.refreshMiddleware())
        r.Use(app.featureMiddleware())
    
        // Load HTML templates
        r.LoadHTMLGlob("templates/*.html")
    
        // Routes
        r.GET("/", app.homeHandler)
        r.GET("/beta", app.betaHandler)
        r.GET("/login", app.loginPageHandler)
        r.POST("/login", app.loginHandler)
        r.GET("/logout", app.logoutHandler)
    }
    
    // Home page handler
    func (app *WebApp) homeHandler(c *gin.Context) {
        betaEnabled := c.GetBool("betaEnabled")
        user := c.GetString("user")
    
        c.HTML(http.StatusOK, "index.html", gin.H{
            "title":       "TestFeatureFlags",
            "betaEnabled": betaEnabled,
            "user":        user,
        })
    }
    
    // Beta page handler
    func (app *WebApp) betaHandler(c *gin.Context) {
        betaEnabled := c.GetBool("betaEnabled")
        if !betaEnabled {
            return
        }
    
        c.HTML(http.StatusOK, "beta.html", gin.H{
            "title": "Beta Page",
        })
    }
    
    func (app *WebApp) loginPageHandler(c *gin.Context) {
        c.HTML(http.StatusOK, "login.html", gin.H{
            "title": "Login",
        })
    }
    
    func (app *WebApp) loginHandler(c *gin.Context) {
        username := c.PostForm("username")
    
        // Basic validation - ensure username is not empty
        if strings.TrimSpace(username) == "" {
            c.HTML(http.StatusOK, "login.html", gin.H{
                "title": "Login",
                "error": "Username cannot be empty",
            })
            return
        }
    
        // Store username in session - any valid username is accepted
        session := sessions.Default(c)
        session.Set("username", username)
        session.Save()
        c.Redirect(http.StatusFound, "/")
    }
    
    func (app *WebApp) logoutHandler(c *gin.Context) {
        session := sessions.Default(c)
        session.Clear()
        session.Save()
        c.Redirect(http.StatusFound, "/")
    }
    
    // The rest of existing code
    //... ...
    
  4. Frissítse a main.go következő tartalommal:

    // Existing code
    // ... ...
     r := gin.Default()
    
     // Setup routes
     app.setupRoutes(r)
    
     // Start server
     if err := r.Run(":8080"); err != nil {
        log.Fatalf("Failed to start server: %v", err)
    }
    // The rest of existing code
    // ... ...
    
  5. Az előző lépések elvégzése után a main.go fájlnak tartalmaznia kell a teljes implementációt az alábbiak szerint:

    package main
    
    import (
        "context"
        "fmt"
        "log"
        "net/http"
        "strings"
    
        "github.com/gin-contrib/sessions"
        "github.com/gin-contrib/sessions/cookie"
        "github.com/gin-gonic/gin"
        "github.com/microsoft/Featuremanagement-Go/featuremanagement"
        "github.com/microsoft/Featuremanagement-Go/featuremanagement/providers/azappconfig"
    )
    
    type WebApp struct {
        featureManager *featuremanagement.FeatureManager
        appConfig      *azureappconfiguration.AzureAppConfiguration
    }
    
    func (app *WebApp) refreshMiddleware() gin.HandlerFunc {
        return func(c *gin.Context) {
            go func() {
                if err := app.appConfig.Refresh(context.Background()); err != nil {
                    log.Printf("Error refreshing configuration: %v", err)
                }
            }()
            c.Next()
        }
    }
    
    func (app *WebApp) featureMiddleware() gin.HandlerFunc {
        return func(c *gin.Context) {
            // Get current user from session
            session := sessions.Default(c)
            username := session.Get("username")
    
            var betaEnabled bool
            var targetingContext featuremanagement.TargetingContext
            if username != nil {
                // Evaluate Beta feature with targeting context
                var err error
                targetingContext = createTargetingContext(username.(string))
                betaEnabled, err = app.featureManager.IsEnabledWithAppContext("Beta", targetingContext)
                if err != nil {
                    log.Printf("Error checking Beta feature with targeting: %v", err)
                }
            }
    
            c.Set("betaEnabled", betaEnabled)
            c.Set("user", username)
            c.Set("targetingContext", targetingContext)
            c.Next()
        }
    }
    
    // Helper function to create TargetingContext
    func createTargetingContext(userID string) featuremanagement.TargetingContext {
        targetingContext := featuremanagement.TargetingContext{
            UserID: userID,
            Groups: []string{},
        }
    
        if strings.Contains(userID, "@") {
            parts := strings.Split(userID, "@")
            if len(parts) == 2 {
                targetingContext.Groups = append(targetingContext.Groups, parts[1]) // Add domain as group
            }
        }
    
        return targetingContext
    }
    
    func (app *WebApp) setupRoutes(r *gin.Engine) {
        // Setup sessions
        store := cookie.NewStore([]byte("secret-key-change-in-production"))
        store.Options(sessions.Options{
            MaxAge:   3600, // 1 hour
            HttpOnly: true,
            Secure:   false, // Set to true in production with HTTPS
        })
        r.Use(sessions.Sessions("session", store))
    
    
        r.Use(app.refreshMiddleware())
        r.Use(app.featureMiddleware())
    
        // Load HTML templates
        r.LoadHTMLGlob("templates/*.html")
    
        // Routes
        r.GET("/", app.homeHandler)
        r.GET("/beta", app.betaHandler)
        r.GET("/login", app.loginPageHandler)
        r.POST("/login", app.loginHandler)
        r.GET("/logout", app.logoutHandler)
    }
    
    // Home page handler
    func (app *WebApp) homeHandler(c *gin.Context) {
        betaEnabled := c.GetBool("betaEnabled")
        user := c.GetString("user")
    
        c.HTML(http.StatusOK, "index.html", gin.H{
            "title":       "TestFeatureFlags",
            "betaEnabled": betaEnabled,
            "user":        user,
        })
    }
    
    // Beta page handler
    func (app *WebApp) betaHandler(c *gin.Context) {
        betaEnabled := c.GetBool("betaEnabled")
        if !betaEnabled {
            return
        }
    
        c.HTML(http.StatusOK, "beta.html", gin.H{
            "title": "Beta Page",
        })
    }
    
    func (app *WebApp) loginPageHandler(c *gin.Context) {
        c.HTML(http.StatusOK, "login.html", gin.H{
            "title": "Login",
        })
    }
    
    func (app *WebApp) loginHandler(c *gin.Context) {
        username := c.PostForm("username")
    
        // Basic validation - ensure username is not empty
        if strings.TrimSpace(username) == "" {
            c.HTML(http.StatusOK, "login.html", gin.H{
                "title": "Login",
                "error": "Username cannot be empty",
            })
            return
        }
    
        // Store username in session - any valid username is accepted
        session := sessions.Default(c)
        session.Set("username", username)
        session.Save()
        c.Redirect(http.StatusFound, "/")
    }
    
    func (app *WebApp) logoutHandler(c *gin.Context) {
        session := sessions.Default(c)
        session.Clear()
        session.Save()
        c.Redirect(http.StatusFound, "/")
    }
    
    func main() {
        // Load Azure App Configuration
        appConfig, err := loadAzureAppConfiguration(context.Background())
        if err != nil {
            log.Fatalf("Error loading Azure App Configuration: %v", err)
        }
    
        // Create feature flag provider
        featureFlagProvider, err := azappconfig.NewFeatureFlagProvider(appConfig)
        if err != nil {
            log.Fatalf("Error creating feature flag provider: %v", err)
        }
    
        // Create feature manager
        featureManager, err := featuremanagement.NewFeatureManager(featureFlagProvider, nil)
        if err != nil {
            log.Fatalf("Error creating feature manager: %v", err)
        }
    
        // Create web app
        app := &WebApp{
            featureManager: featureManager,
            appConfig:      appConfig,
        }
    
        // Setup Gin with default middleware (Logger and Recovery)
        r := gin.Default()
    
        // Setup routes
        app.setupRoutes(r)
    
        // Start server
        if err := r.Run(":8080"); err != nil {
            log.Fatalf("Failed to start server: %v", err)
        }
    
        fmt.Println("Starting server on http://localhost:8080")
        fmt.Println("Open http://localhost:8080 in your browser")
        fmt.Println()
    }
    

Célzási szűrő működés közben

  1. Állítsa be a környezeti változót a hitelesítéshez , és futtassa az alkalmazást:

    go mod tidy
    go run .
    
  2. Nyisson meg egy ablakot a böngészőben, és menjen a http://localhost:8080. Kezdetben a bétaelem nem jelenik meg az eszköztáron, mert az Alapértelmezett százalék beállítás értéke 0.

    Képernyőkép a Gin webalkalmazásról a felhasználói bejelentkezés előtt, amely nem mutat bétaverziós hozzáférést.

  3. Kattintson a bejelentkezési hivatkozásra a jobb felső sarokban. Próbálja meg bejelentkezni a következővel: test@contoso.com.

  4. A bejelentkezés test@contoso.com után a Beta elem megjelenik az eszköztáron, mert test@contoso.com célfelhasználóként van megadva.

    Képernyőkép a Gin webalkalmazásról a célzott felhasználói bejelentkezés után, bétaverziós hozzáféréssel.

  5. Most jelentkezzen ki és jelentkezzen be a következőként testuser@contoso.com: . A bétaelem nem jelenik meg az eszköztáron, mert testuser@contoso.com kizárt felhasználóként van megadva.

Következő lépések

A funkciószűrőkről a következő dokumentumokban olvashat bővebben.

A Go szolgáltatásfelügyeleti kódtárával kapcsolatos további információkért tekintse meg a következő dokumentumot: