package licence import ( "bytes" "encoding/json" "errors" "time" ) const dateLayout = "2006-01-02" var ( shanghaiLocation, shanghaiLocationErr = time.LoadLocationFromTZData("Asia/Shanghai", shanghaiTZData[:]) ) type Subject struct { PlatformName string `json:"platform_name"` Workspace string `json:"workspace"` } type Quotas struct { MaxDatabase int64 `json:"max_database"` MaxMiddleware int64 `json:"max_middleware"` MaxNetworkDevice int64 `json:"max_network_device"` MaxSecurity int64 `json:"max_security"` MaxStorage int64 `json:"max_storage"` MaxPC int64 `json:"max_pc"` MaxServer int64 `json:"max_server"` MaxUser int64 `json:"max_user"` MaxRole int64 `json:"max_role"` MaxPermission int64 `json:"max_permission"` MaxMenu int64 `json:"max_menu"` } // Date 表示 Asia/Shanghai 时区内的一个自然日。 type Date struct { value string } func ParseDate(value string) (Date, error) { if _, err := parseDateTime(value); err != nil { return Date{}, err } return Date{value: value}, nil } func NewDate(value time.Time) (Date, error) { location, err := locationShanghai() if err != nil { return Date{}, err } return ParseDate(value.In(location).Format(dateLayout)) } func (d Date) String() string { return d.value } func (d Date) Time() (time.Time, error) { return parseDateTime(d.value) } func (d Date) MarshalJSON() ([]byte, error) { if _, err := d.Time(); err != nil { return nil, err } return json.Marshal(d.value) } func (d *Date) UnmarshalJSON(data []byte) error { if d == nil { return errors.New("日期接收者不能为空") } if bytes.Equal(bytes.TrimSpace(data), []byte("null")) { return errors.New("日期必须是字符串") } var value string if err := json.Unmarshal(data, &value); err != nil { return errors.New("日期必须是字符串") } parsed, err := ParseDate(value) if err != nil { return err } *d = parsed return nil } func locationShanghai() (*time.Location, error) { if shanghaiLocationErr != nil { return nil, errors.New("加载 Asia/Shanghai 时区失败") } return shanghaiLocation, nil } func parseDateTime(value string) (time.Time, error) { if len(value) != len(dateLayout) || value[4] != '-' || value[7] != '-' { return time.Time{}, errors.New("日期格式必须为 YYYY-MM-DD") } for index := range value { if index == 4 || index == 7 { continue } if value[index] < '0' || value[index] > '9' { return time.Time{}, errors.New("日期格式必须为 YYYY-MM-DD") } } location, err := locationShanghai() if err != nil { return time.Time{}, err } parsed, err := time.ParseInLocation(dateLayout, value, location) if err != nil || parsed.Year() < 1 || parsed.Format(dateLayout) != value { return time.Time{}, errors.New("日期不是有效的自然日") } return parsed, nil } type Claims struct { ID string `json:"id"` PlatformName string `json:"platform_name"` Workspace string `json:"workspace"` IssuedOn Date `json:"issued_on"` ValidFrom Date `json:"valid_from"` ExpiresOn Date `json:"expires_on"` Quotas Quotas `json:"quotas"` SigningKeyID string `json:"signing_key_id"` } type Licence struct { ID string Subject Subject IssuedOn time.Time ValidFrom time.Time ExpiresOn time.Time Quotas Quotas }