Gt
Client (Angular) <-> API Gateway (Go) <-> Database (PostgreSQL)
↑
JWT Auth
- /cmd/api
- /internal
- /handlers
- /models
- /middleware
- /config
- /migrations
- /pkg
- /auth
CREATE TABLE users (
id UUID PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password_hash VARCHAR(255) NOT NULL,
role VARCHAR(20) CHECK (role IN ('admin', 'user', 'company')) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE TABLE vehicles (
id UUID PRIMARY KEY,
user_id UUID REFERENCES users(id),
make VARCHAR(255) NOT NULL,
model VARCHAR(255) NOT NULL,
year INTEGER NOT NULL,
vin VARCHAR(17) UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
package middleware
import (
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v4"
)
func AuthMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
tokenString := c.GetHeader("Authorization")
if tokenString == "" {
c.AbortWithStatusJSON(401, gin.H{"error": "Unauthorized"})
return
}
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
return []byte(config.JWTSecret), nil
})
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
c.Set("userID", claims["sub"])
c.Set("userRole", claims["role"])
c.Next()
} else {
c.AbortWithStatusJSON(401, gin.H{"error": "Invalid token", "details": err.Error()})
}
}
}
func RoleMiddleware(allowedRoles []string) gin.HandlerFunc {
return func(c *gin.Context) {
userRole, _ := c.Get("userRole")
for _, role := range allowedRoles {
if role == userRole {
c.Next()
return
}
}
c.AbortWithStatusJSON(403, gin.H{"error": "Forbidden"})
}
}
package handlers
func RegisterUser(c *gin.Context) {
var user models.User
if err := c.ShouldBindJSON(&user); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
// Validate role
if !isValidRole(user.Role) {
c.JSON(400, gin.H{"error": "Invalid role"})
return
}
// Hash password
hashedPassword, err := auth.HashPassword(user.Password)
if err != nil {
c.JSON(500, gin.H{"error": "Could not create user"})
return
}
// Save to database
newUser := models.User{
ID: uuid.New(),
Email: user.Email,
PasswordHash: hashedPassword,
Role: user.Role,
}
if err := config.DB.Create(&newUser).Error; err != nil {
c.JSON(500, gin.H{"error": "Could not create user"})
return
}
c.JSON(201, gin.H{"message": "User created successfully"})
}
// auth.service.ts
@Injectable({
providedIn: 'root'
})
export class AuthService {
private apiUrl = environment.apiUrl;
constructor(private http: HttpClient) {}
login(credentials: { email: string, password: string }): Observable {
return this.http.post(`${this.apiUrl}/login`, credentials).pipe(
tap((res: any) => {
localStorage.setItem('access_token', res.token);
})
);
}
register(user: { email: string, password: string, role: string }): Observable {
return this.http.post(`${this.apiUrl}/register`, user);
}
}
// auth.guard.ts
@Injectable({
providedIn: 'root'
})
export class AuthGuard implements CanActivate {
constructor(private authService: AuthService, private router: Router) {}
canActivate(
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot): Observable | Promise | boolean | UrlTree {
if (this.authService.isLoggedIn()) {
const requiredRoles = next.data['roles'] as Array;
const userRole = this.authService.getUserRole();
if (requiredRoles && !requiredRoles.includes(userRole)) {
this.router.navigate(['/forbidden']);
return false;
}
return true;
}
this.router.navigate(['/login']);
return false;
}
}
// jwt.interceptor.ts
@Injectable()
export class JwtInterceptor implements HttpInterceptor {
intercept(request: HttpRequest, next: HttpHandler): Observable> {
const token = localStorage.getItem('access_token');
if (token) {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${token}`
}
});
}
return next.handle(request);
}
}
JWT_SECRET=your_strong_secret_here
DB_HOST=your_db_host
DB_USER=your_db_user
DB_PASSWORD=your_db_password
func CORSMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
c.Writer.Header().Set("Access-Control-Allow-Origin", "http://your-angular-app:4200")
c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Authorization")
c.Writer.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
if c.Request.Method == "OPTIONS" {
c.AbortWithStatus(204)
return
}
c.Next()
}
}
Comments
Post a Comment