| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- package auth
- import (
- "testing"
- "time"
- "perms-system-server/internal/middleware"
- "github.com/golang-jwt/jwt/v4"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
- )
- const testSecret = "test-jwt-secret-key"
- // TC-0257: secret="s", expire=3600, userId=1, username="u", productCode="p", memberType="M"
- func TestGenerateAccessToken(t *testing.T) {
- tests := []struct {
- name string
- secret string
- expire int64
- userId int64
- username string
- productCode string
- memberType string
- tokenVersion int64
- }{
- {
- name: "normal generation",
- secret: testSecret,
- expire: 3600,
- userId: 1,
- username: "admin",
- productCode: "p1",
- memberType: "ADMIN",
- },
- {
- name: "empty productCode",
- secret: testSecret,
- expire: 3600,
- userId: 3,
- username: "user2",
- productCode: "",
- memberType: "",
- },
- {
- name: "super admin with tokenVersion",
- secret: testSecret,
- expire: 7200,
- userId: 100,
- username: "super",
- productCode: "p1",
- memberType: "SUPER_ADMIN",
- tokenVersion: 5,
- },
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- tokenStr, err := GenerateAccessToken(tt.secret, tt.expire, tt.userId, tt.username, tt.productCode, tt.memberType, tt.tokenVersion)
- require.NoError(t, err)
- assert.NotEmpty(t, tokenStr)
- token, err := jwt.ParseWithClaims(tokenStr, &middleware.Claims{}, func(token *jwt.Token) (interface{}, error) {
- return []byte(tt.secret), nil
- })
- require.NoError(t, err)
- assert.True(t, token.Valid)
- claims, ok := token.Claims.(*middleware.Claims)
- require.True(t, ok)
- assert.Equal(t, tt.userId, claims.UserId)
- assert.Equal(t, tt.username, claims.Username)
- assert.Equal(t, tt.productCode, claims.ProductCode)
- assert.Equal(t, tt.memberType, claims.MemberType)
- assert.Equal(t, tt.tokenVersion, claims.TokenVersion)
- assert.Nil(t, claims.Perms, "Perms should not be embedded in access token (audit #8)")
- })
- }
- }
- // TC-0261: expireSeconds=1, sleep 2s
- func TestGenerateAccessToken_Expiry(t *testing.T) {
- tokenStr, err := GenerateAccessToken(testSecret, 1, 1, "u", "", "", 0)
- require.NoError(t, err)
- time.Sleep(2 * time.Second)
- _, err = jwt.ParseWithClaims(tokenStr, &middleware.Claims{}, func(token *jwt.Token) (interface{}, error) {
- return []byte(testSecret), nil
- })
- assert.Error(t, err)
- assert.Contains(t, err.Error(), "token is expired")
- }
- // TC-0262: secret="s", expire=86400, userId=1, productCode="p"
- func TestGenerateRefreshToken(t *testing.T) {
- tests := []struct {
- name string
- secret string
- expire int64
- userId int64
- productCode string
- }{
- {"normal", testSecret, 86400, 1, "p1"},
- {"empty productCode", testSecret, 86400, 2, ""},
- }
- for _, tt := range tests {
- t.Run(tt.name, func(t *testing.T) {
- tokenStr, err := GenerateRefreshToken(tt.secret, tt.expire, tt.userId, tt.productCode, 0)
- require.NoError(t, err)
- assert.NotEmpty(t, tokenStr)
- claims, err := ParseRefreshToken(tokenStr, tt.secret)
- require.NoError(t, err)
- assert.Equal(t, tt.userId, claims.UserId)
- assert.Equal(t, tt.productCode, claims.ProductCode)
- })
- }
- }
- // TC-0265: 有效token+正确secret
- func TestParseRefreshToken(t *testing.T) {
- validToken, err := GenerateRefreshToken(testSecret, 3600, 42, "prod", 0)
- require.NoError(t, err)
- t.Run("valid token", func(t *testing.T) {
- claims, err := ParseRefreshToken(validToken, testSecret)
- require.NoError(t, err)
- assert.Equal(t, int64(42), claims.UserId)
- assert.Equal(t, "prod", claims.ProductCode)
- })
- t.Run("wrong secret", func(t *testing.T) {
- _, err := ParseRefreshToken(validToken, "wrong-secret")
- assert.Error(t, err)
- })
- t.Run("invalid token string", func(t *testing.T) {
- _, err := ParseRefreshToken("not-a-valid-token", testSecret)
- assert.Error(t, err)
- })
- t.Run("empty token", func(t *testing.T) {
- _, err := ParseRefreshToken("", testSecret)
- assert.Error(t, err)
- })
- t.Run("expired token", func(t *testing.T) {
- expiredToken, err := GenerateRefreshToken(testSecret, 1, 1, "p", 0)
- require.NoError(t, err)
- time.Sleep(2 * time.Second)
- _, err = ParseRefreshToken(expiredToken, testSecret)
- assert.Error(t, err)
- })
- // TC-0270: AccessToken误用 — TokenType校验拒绝
- t.Run("access token used as refresh - should be rejected", func(t *testing.T) {
- accessToken, err := GenerateAccessToken(testSecret, 3600, 1, "u", "p", "M", 0)
- require.NoError(t, err)
- _, err = ParseRefreshToken(accessToken, testSecret)
- assert.Error(t, err, "BUG-002: access token 不应被 ParseRefreshToken 接受,应通过 TokenType 字段区分")
- })
- }
- // TC-0259: secret=""
- func TestGenerateAccessToken_EmptySecret(t *testing.T) {
- tokenStr, err := GenerateAccessToken("", 3600, 1, "u", "p", "M", 0)
- require.NoError(t, err)
- assert.NotEmpty(t, tokenStr)
- token, err := jwt.ParseWithClaims(tokenStr, &middleware.Claims{}, func(token *jwt.Token) (interface{}, error) {
- return []byte(""), nil
- })
- require.NoError(t, err)
- assert.True(t, token.Valid)
- claims, ok := token.Claims.(*middleware.Claims)
- require.True(t, ok)
- assert.Equal(t, int64(1), claims.UserId)
- }
|