Golang与Angular搭配的后端开发实践
Golang与Angular搭配的后端开发实践 我有一个带有登录系统的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端点。


