2021与蓝度共同重构项目,服务端
fix
zhanzhiqin
2022-05-12 9f21969b69703a35bde9d659be19f3e39795010d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package com.sandu.common.security.token;
 
import com.sandu.common.enums.AdminStatusStatus;
import com.sandu.common.execption.BusinessException;
import com.sandu.common.redis.RedisService;
import com.sandu.common.security.LoginUserInfo;
import com.sandu.common.security.config.SecurityProperties;
import com.sandu.common.util.SpringContextHolder;
import io.jsonwebtoken.*;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.io.DecodingException;
import io.jsonwebtoken.security.Keys;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.boot.autoconfigure.cache.CacheProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
 
import java.security.Key;
import java.util.Date;
import java.util.stream.Collectors;
 
/**
 * @author chenjiantian
 * @date 2022/1/8 18:12
 */
@Component
@Slf4j
@ConditionalOnProperty(prefix = "sandu.jwt", name = "cache-online", havingValue = "false")
public class JwtTokenProvider implements TokenProvider, InitializingBean {
 
    private static final String AUTHORITIES_KEY = "auth";
    private static final String CREDENTIALS_KEY = "cred";
    private static final String ADMINISTRATOR_KEY = "admin";
    private final SecurityProperties properties;
    private Key key;
 
    public JwtTokenProvider(SecurityProperties properties) {
        this.properties = properties;
    }
 
    @Override
    public void afterPropertiesSet() {
        byte[] keyBytes = Decoders.BASE64.decode(properties.getBase64Secret());
        this.key = Keys.hmacShaKeyFor(keyBytes);
    }
 
    @Override
    public String createToken(LoginUserInfo loginUserInfo) {
        if (loginUserInfo.getUserId() == null) {
            throw new IllegalArgumentException("用户id不能为空");
        }
        RedisService redisService = SpringContextHolder.getBean(RedisService.class);
        String authorities = loginUserInfo.getAuthorities().stream()
                .map(GrantedAuthority::getAuthority)
                .collect(Collectors.joining(","));
 
        long now = (new Date()).getTime();
        Date expiration = new Date(now + properties.getTokenValidityInSeconds());
        String token = Jwts.builder()
                .setSubject(loginUserInfo.getUserId().toString())
                .claim(AUTHORITIES_KEY, authorities)
                .claim(CREDENTIALS_KEY, loginUserInfo.getAccount())
                .claim(ADMINISTRATOR_KEY, loginUserInfo.getAdministratorType())
                .setExpiration(expiration)
                .signWith(key, SignatureAlgorithm.HS512)
                .compact();
 
        String key = String.format("%d_%d", loginUserInfo.getUserId(), loginUserInfo.getAdministratorType());
        redisService.set(key, token, 2592000);
        return token;
    }
 
    @Override
    public LoginUserInfo validateToken(String token) {
        try {
            RedisService redisService = SpringContextHolder.getBean(RedisService.class);
 
            Claims claims = Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token).getBody();
            LoginUserInfo loginUserInfo = new LoginUserInfo();
            loginUserInfo.setUserId(Long.valueOf(claims.getSubject()));
            loginUserInfo.setAccount(String.valueOf(claims.get(CREDENTIALS_KEY)));
            loginUserInfo.setPermission(claims.get(AUTHORITIES_KEY).toString());
            loginUserInfo.setAdministratorType(Integer.parseInt(claims.get(ADMINISTRATOR_KEY).toString()));
            loginUserInfo.setToken(token);
            loginUserInfo.setStatus(AdminStatusStatus.NORMAL.getCode());
            String key = String.format("%d_%d", loginUserInfo.getUserId(), loginUserInfo.getAdministratorType());
            String redisToken = String.valueOf(redisService.get(key));
            if (redisToken == null || !token.equals(redisToken)) {
                throw new BusinessException("token无效");
            }
            return loginUserInfo;
        } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) {
            log.info("Invalid JWT signature.");
//            e.printStackTrace();
        } catch (ExpiredJwtException e) {
            log.info("Expired JWT token.");
//            e.printStackTrace();
        } catch (UnsupportedJwtException | DecodingException e) {
            log.info("Unsupported JWT token.");
//            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            log.info("JWT token compact of handler are invalid.");
//            e.printStackTrace();
        }
 
        return null;
    }
}