Golang与Angular搭配的后端开发实践

Golang与Angular搭配的后端开发实践 我有一个带有登录系统的Angular应用程序。我想用Go作为后端。但我不知道如何从Angular获取登录信息。我对这两种语言都是初学者。

7 回复

虽然不多,但我已经编写了一些代码

更多关于Golang与Angular搭配的后端开发实践的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


或许你可以分享一下你的学习心得?😊 这样其他人也能看到你的帖子,而且向他人讲述所学内容也是加深记忆的好方法。

你需要将信息从Angular发送到Go服务器的请求中,从请求中解析出需要处理的信息,然后从服务器返回响应给Angular。希望这对你有所帮助。

好的,如果我完成了完整的 API,我会在我的 GitHub 仓库中发布链接,之后我会在这里发布链接。我还会解释我是如何以及在何处获取信息的。😊 好吗?

哈哈。抱歉。是我的错。我没写清楚,我已经完成了代码。我想说的是,你的帖子只是帮助我理解了整个过程,但并没有直接帮我写出代码。我一周前开始学习Golang,今天终于完成了 🙂 。不过还是非常感谢你。

天啊,我觉得那像是某种讽刺的回击。谷歌是你的好帮手,我只花了两秒钟就找到了这个用代码展示如何实现你需求的链接:https://www.thepolyglotdeveloper.com/2017/02/build-a-full-stack-movie-database-with-golang-angular-and-nosql/

在Go后端与Angular前端集成时,处理登录认证的最佳实践是使用JWT(JSON Web Token)结合HTTP拦截器。以下是完整的实现方案:

1. Go后端实现(Gin框架示例):

package main

import (
    "net/http"
    "time"
    
    "github.com/gin-gonic/gin"
    "github.com/golang-jwt/jwt/v4"
)

type LoginRequest struct {
    Username string `json:"username"`
    Password string `json:"password"`
}

type Claims struct {
    Username string `json:"username"`
    jwt.RegisteredClaims
}

var jwtKey = []byte("your-secret-key")

func loginHandler(c *gin.Context) {
    var req LoginRequest
    if err := c.BindJSON(&req); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request"})
        return
    }
    
    // 验证用户名和密码(这里简化处理)
    if req.Username != "admin" || req.Password != "password" {
        c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"})
        return
    }
    
    // 创建JWT token
    expirationTime := time.Now().Add(24 * time.Hour)
    claims := &Claims{
        Username: req.Username,
        RegisteredClaims: jwt.RegisteredClaims{
            ExpiresAt: jwt.NewNumericDate(expirationTime),
        },
    }
    
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    tokenString, err := token.SignedString(jwtKey)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not generate token"})
        return
    }
    
    c.JSON(http.StatusOK, gin.H{
        "token": tokenString,
        "expires": expirationTime,
    })
}

func protectedHandler(c *gin.Context) {
    tokenString := c.GetHeader("Authorization")
    if tokenString == "" {
        c.JSON(http.StatusUnauthorized, gin.H{"error": "Missing token"})
        return
    }
    
    // 移除"Bearer "前缀
    if len(tokenString) > 7 && tokenString[:7] == "Bearer " {
        tokenString = tokenString[7:]
    }
    
    claims := &Claims{}
    token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {
        return jwtKey, nil
    })
    
    if err != nil || !token.Valid {
        c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid token"})
        return
    }
    
    c.JSON(http.StatusOK, gin.H{
        "message": "Welcome " + claims.Username,
        "data": "Protected resource",
    })
}

func main() {
    r := gin.Default()
    
    r.POST("/login", loginHandler)
    r.GET("/protected", protectedHandler)
    
    r.Run(":8080")
}

2. Angular前端实现:

// auth.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  private apiUrl = 'http://localhost:8080';
  private tokenKey = 'auth_token';
  
  private loggedIn = new BehaviorSubject<boolean>(this.hasToken());

  constructor(private http: HttpClient) {}

  login(username: string, password: string): Observable<any> {
    return this.http.post(`${this.apiUrl}/login`, { username, password })
      .pipe(
        tap((response: any) => {
          localStorage.setItem(this.tokenKey, response.token);
          this.loggedIn.next(true);
        })
      );
  }

  logout(): void {
    localStorage.removeItem(this.tokenKey);
    this.loggedIn.next(false);
  }

  getToken(): string | null {
    return localStorage.getItem(this.tokenKey);
  }

  isLoggedIn(): Observable<boolean> {
    return this.loggedIn.asObservable();
  }

  private hasToken(): boolean {
    return !!localStorage.getItem(this.tokenKey);
  }
}
// auth.interceptor.ts
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';
import { AuthService } from './auth.service';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  
  constructor(private authService: AuthService) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const token = this.authService.getToken();
    
    if (token) {
      const cloned = req.clone({
        headers: req.headers.set('Authorization', `Bearer ${token}`)
      });
      return next.handle(cloned);
    }
    
    return next.handle(req);
  }
}
// login.component.ts
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { AuthService } from '../services/auth.service';

@Component({
  selector: 'app-login',
  template: `
    <div class="login-container">
      <form (ngSubmit)="onSubmit()">
        <input type="text" [(ngModel)]="username" name="username" placeholder="Username" required>
        <input type="password" [(ngModel)]="password" name="password" placeholder="Password" required>
        <button type="submit">Login</button>
      </form>
      <div *ngIf="error" class="error">{{ error }}</div>
    </div>
  `
})
export class LoginComponent {
  username = '';
  password = '';
  error = '';

  constructor(private authService: AuthService, private router: Router) {}

  onSubmit(): void {
    this.authService.login(this.username, this.password).subscribe({
      next: () => {
        this.router.navigate(['/dashboard']);
      },
      error: (err) => {
        this.error = 'Login failed';
      }
    });
  }
}
// app.module.ts (配置拦截器)
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { LoginComponent } from './login.component';
import { AuthInterceptor } from './auth.interceptor';

@NgModule({
  declarations: [
    AppComponent,
    LoginComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule,
    FormsModule
  ],
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi: true
    }
  ],
  bootstrap: [AppComponent]
})
export class AppModule { }

3. 测试流程:

// 在需要调用受保护API的组件中
import { Component } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  template: `
    <button (click)="getProtectedData()">Get Protected Data</button>
    <div>{{ protectedData }}</div>
  `
})
export class DashboardComponent {
  protectedData: any;

  constructor(private http: HttpClient) {}

  getProtectedData(): void {
    this.http.get('http://localhost:8080/protected').subscribe({
      next: (data: any) => {
        this.protectedData = data;
      },
      error: (err) => {
        console.error('Failed to fetch protected data', err);
      }
    });
  }
}

这个实现方案提供了完整的认证流程:Angular前端发送登录请求到Go后端,后端验证凭据并返回JWT token,前端将token存储在localStorage中,并通过HTTP拦截器自动在所有后续请求中包含token。Go后端验证token的有效性并保护API端点。

回到顶部