美文网首页
java和golang使用rsa jwt

java和golang使用rsa jwt

作者: EasyNetCN | 来源:发表于2022-06-20 08:25 被阅读0次

    在此示例中,使用了Spring Boot和Go gin架构,实现了java项目生成jwt token,go项目验证token。我们把jwt rsa相关信息配置在application.yml中。

    Spring Boot中的相关代码和配置

    JwtProperties

    import org.springframework.boot.context.properties.ConfigurationProperties;
    
    @ConfigurationProperties("jwt")
    public class JwtProperties {
        private String publicKey;
    
        private String privateKey;
    
        public String getPublicKey() {
            return publicKey;
        }
    
        public void setPublicKey(String publicKey) {
            this.publicKey = publicKey;
        }
    
        public String getPrivateKey() {
            return privateKey;
        }
    
        public void setPrivateKey(String privateKey) {
            this.privateKey = privateKey;
        }
    }
    

    JwtConfiguration

    import java.io.IOException;
    import java.security.KeyFactory;
    import java.security.NoSuchAlgorithmException;
    import java.security.interfaces.RSAPrivateKey;
    import java.security.interfaces.RSAPublicKey;
    import java.security.spec.EncodedKeySpec;
    import java.security.spec.InvalidKeySpecException;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.security.spec.X509EncodedKeySpec;
    import java.util.Base64;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.context.properties.EnableConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.oauth2.jwt.JwtDecoder;
    import org.springframework.security.oauth2.jwt.JwtEncoder;
    import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
    import org.springframework.security.oauth2.jwt.NimbusJwtEncoder;
    
    import com.nimbusds.jose.jwk.JWK;
    import com.nimbusds.jose.jwk.JWKSet;
    import com.nimbusds.jose.jwk.RSAKey;
    import com.nimbusds.jose.jwk.source.ImmutableJWKSet;
    import com.nimbusds.jose.jwk.source.JWKSource;
    import com.nimbusds.jose.proc.SecurityContext;
    
    @Configuration
    @EnableConfigurationProperties(JwtProperties.class)
    public class JwtConfiguration {
        @Autowired
        private JwtProperties jwtProperties;
    
        @Bean
        RSAPublicKey rsaPublicKey() throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
            String publicKeyPEM = jwtProperties.getPublicKey().replace("-----BEGIN PUBLIC KEY-----", "")
                    .replaceAll(System.lineSeparator(), "").replace("-----END PUBLIC KEY-----", "").replaceAll("\\s+", "");
    
            byte[] encoded = Base64.getDecoder().decode(publicKeyPEM);
    
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encoded);
            return (RSAPublicKey) keyFactory.generatePublic(keySpec);
        }
    
        @Bean
        public RSAPrivateKey rsaPrivateKey() throws NoSuchAlgorithmException, InvalidKeySpecException {
            String privateKeyPEM = jwtProperties.getPrivateKey().replace("-----BEGIN PRIVATE KEY-----", "")
                    .replaceAll(System.lineSeparator(), "").replace("-----END PRIVATE KEY-----", "").replaceAll("\\s+", "");
    
            byte[] encoded = Base64.getDecoder().decode(privateKeyPEM);
    
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    
            EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encoded);
    
            return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
        }
    
        @Bean
        public JwtDecoder jwtDecoder(RSAPublicKey rsaPublicKey) {
            return NimbusJwtDecoder.withPublicKey(rsaPublicKey).build();
        }
    
        @Bean
        public JwtEncoder jwtEncoder(RSAPublicKey rsaPublicKey, RSAPrivateKey rsaPrivateKey) {
            JWK jwk = new RSAKey.Builder(rsaPublicKey).privateKey(rsaPrivateKey).build();
            JWKSource<SecurityContext> jwks = new ImmutableJWKSet<>(new JWKSet(jwk));
    
            return new NimbusJwtEncoder(jwks);
        }
    }
    

    application.yml

    jwt:
      public-key: |-
        -----BEGIN PUBLIC KEY-----
        MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3FlqJr5TRskIQIgdE3Dd
        7D9lboWdcTUT8a+fJR7MAvQm7XXNoYkm3v7MQL1NYtDvL2l8CAnc0WdSTINU6IRv
        c5Kqo2Q4csNX9SHOmEfzoROjQqahEcve1jBXluoCXdYuYpx4/1tfRgG6ii4Uhxh6
        iI8qNMJQX+fLfqhbfYfxBQVRPywBkAbIP4x1EAsbC6FSNmkhCxiMNqEgxaIpY8C2
        kJdJ/ZIV+WW4noDdzpKqHcwmB8FsrumlVY/DNVvUSDIipiq9PbP4H99TXN1o746o
        RaNa07rq1hoCgMSSy+85SagCoxlmyE+D+of9SsMY8Ol9t0rdzpobBuhyJ/o5dfvj
        KwIDAQAB
        -----END PUBLIC KEY-----
      private-key: |-
        -----BEGIN PRIVATE KEY-----
        MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDcWWomvlNGyQhA
        iB0TcN3sP2VuhZ1xNRPxr58lHswC9Cbtdc2hiSbe/sxAvU1i0O8vaXwICdzRZ1JM
        g1TohG9zkqqjZDhyw1f1Ic6YR/OhE6NCpqERy97WMFeW6gJd1i5inHj/W19GAbqK
        LhSHGHqIjyo0wlBf58t+qFt9h/EFBVE/LAGQBsg/jHUQCxsLoVI2aSELGIw2oSDF
        oiljwLaQl0n9khX5ZbiegN3OkqodzCYHwWyu6aVVj8M1W9RIMiKmKr09s/gf31Nc
        3WjvjqhFo1rTuurWGgKAxJLL7zlJqAKjGWbIT4P6h/1Kwxjw6X23St3OmhsG6HIn
        +jl1++MrAgMBAAECggEBAMf820wop3pyUOwI3aLcaH7YFx5VZMzvqJdNlvpg1jbE
        E2Sn66b1zPLNfOIxLcBG8x8r9Ody1Bi2Vsqc0/5o3KKfdgHvnxAB3Z3dPh2WCDek
        lCOVClEVoLzziTuuTdGO5/CWJXdWHcVzIjPxmK34eJXioiLaTYqN3XKqKMdpD0ZG
        mtNTGvGf+9fQ4i94t0WqIxpMpGt7NM4RHy3+Onggev0zLiDANC23mWrTsUgect/7
        62TYg8g1bKwLAb9wCBT+BiOuCc2wrArRLOJgUkj/F4/gtrR9ima34SvWUyoUaKA0
        bi4YBX9l8oJwFGHbU9uFGEMnH0T/V0KtIB7qetReywkCgYEA9cFyfBIQrYISV/OA
        +Z0bo3vh2aL0QgKrSXZ924cLt7itQAHNZ2ya+e3JRlTczi5mnWfjPWZ6eJB/8MlH
        Gpn12o/POEkU+XjZZSPe1RWGt5g0S3lWqyx9toCS9ACXcN9tGbaqcFSVI73zVTRA
        8J9grR0fbGn7jaTlTX2tnlOTQ60CgYEA5YjYpEq4L8UUMFkuj+BsS3u0oEBnzuHd
        I9LEHmN+CMPosvabQu5wkJXLuqo2TxRnAznsA8R3pCLkdPGoWMCiWRAsCn979TdY
        QbqO2qvBAD2Q19GtY7lIu6C35/enQWzJUMQE3WW0OvjLzZ0l/9mA2FBRR+3F9A1d
        rBdnmv0c3TcCgYEAi2i+ggVZcqPbtgrLOk5WVGo9F1GqUBvlgNn30WWNTx4zIaEk
        HSxtyaOLTxtq2odV7Kr3LGiKxwPpn/T+Ief+oIp92YcTn+VfJVGw4Z3BezqbR8lA
        Uf/+HF5ZfpMrVXtZD4Igs3I33Duv4sCuqhEvLWTc44pHifVloozNxYfRfU0CgYBN
        HXa7a6cJ1Yp829l62QlJKtx6Ymj95oAnQu5Ez2ROiZMqXRO4nucOjGUP55Orac1a
        FiGm+mC/skFS0MWgW8evaHGDbWU180wheQ35hW6oKAb7myRHtr4q20ouEtQMdQIF
        snV39G1iyqeeAsf7dxWElydXpRi2b68i3BIgzhzebQKBgQCdUQuTsqV9y/JFpu6H
        c5TVvhG/ubfBspI5DhQqIGijnVBzFT//UfIYMSKJo75qqBEyP2EJSmCsunWsAFsM
        TszuiGTkrKcZy9G0wJqPztZZl2F2+bJgnA6nBEV7g5PA4Af+QSmaIhRwqGDAuROR
        47jndeyIaMTNETEmOnms+as17g==
        -----END PRIVATE KEY-----
    

    Go gin中相关代码和配置

    token_subject

    package model
    
    type TokenSubject struct {
        Id       int64  `json:"id"`
        Name     string `json:"name"`
        UserType int    `json:"userType"`
        Platform string `json:"platform"`
        App      string `json:"app"`
    }
    

    jwt_middleware

    package middleware
    
    import (
        "fmt"
        "net/http"
        "strings"
    
        "github.com/gin-gonic/gin"
    )
    
    func AuthorizeJWT() gin.HandlerFunc {
        return func(c *gin.Context) {
            const BEARER_SCHEMA = "Bearer"
    
            authHeader := c.GetHeader("Authorization")
    
            if len(authHeader) == 0 || len(authHeader) < len(BEARER_SCHEMA)+1 {
                c.AbortWithStatus(http.StatusUnauthorized)
    
                return
            }
    
            tokenStr := strings.TrimSpace(authHeader[len(BEARER_SCHEMA)+1:])
    
            if tokenSubject, err := service.JwtAuthService.ValidAuthToken(tokenStr); err != nil {
                fmt.Println(err)
    
                c.AbortWithStatus(http.StatusUnauthorized)
    
                return
            } else if tokenSubject == nil || tokenSubject.Id == 0 {
                c.AbortWithStatus(http.StatusUnauthorized)
    
                return
            } else {
                c.Set("tokenSubject", tokenSubject)
                c.Next()
            }
    
        }
    }
    

    jwt_auth_service

    package service
    
    import (
        "encoding/json"
        "log"
    
        "github.com/golang-jwt/jwt/v4"
    )
    
    type jwtAuthService struct {
    }
    
    var JwtAuthService = new(jwtAuthService)
    
    func (s *jwtAuthService) ValidAuthToken(tokenStr string) (*model.TokenSubject, error) {
        if tokenStr == "" {
            return nil, errors.New("参数tokenStr为空")
        }
    
        claims := &jwt.RegisteredClaims{}
    
        result, _, err := s.VerifyJWTRSA(tokenStr, config.GetConfig().Jwt.PublicKey, claims)
    
        if !result {
            return nil, errors.New("验证失败")
        }
    
        if err != nil {
            log.Println(tokenStr, config.GetConfig().Jwt.PublicKey, err)
    
            return nil, err
        }
    
        tokenSubject := &model.TokenSubject{}
    
        if err := json.Unmarshal([]byte(claims.Subject), &tokenSubject); err != nil {
            log.Println(err)
    
            return nil, err
        }
    
        if tokenSubject.Id == 0 {
            return nil, err
        }
    
        return tokenSubject, nil
    }
    
    func (s *jwtAuthService) VerifyJWTRSA(token, publicKey string, claims *jwt.RegisteredClaims) (bool, *jwt.Token, error) {
        var parsedToken *jwt.Token
    
        // parse token
        state, err := jwt.ParseWithClaims(token, claims, func(token *jwt.Token) (interface{}, error) {
    
            // ensure signing method is correct
            if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
                return nil, errors.New("unknown signing method")
            }
    
            parsedToken = token
    
            // verify
            key, err := jwt.ParseRSAPublicKeyFromPEM([]byte(publicKey))
    
            if err != nil {
                return nil, err
            }
    
            return key, nil
        })
    
        if err != nil {
            return false, &jwt.Token{}, err
        }
    
        if !state.Valid {
            return false, &jwt.Token{}, errors.New("invalid jwt token")
        }
    
        return true, parsedToken, nil
    }
    

    相关文章

      网友评论

          本文标题:java和golang使用rsa jwt

          本文链接:https://www.haomeiwen.com/subject/ktwdvrtx.html