diff --git a/pom.xml b/pom.xml index 6938e2b..3c0848f 100644 --- a/pom.xml +++ b/pom.xml @@ -20,6 +20,7 @@ 2.3.0 1.1.6 3.17 + 0.9.0 @@ -46,10 +47,8 @@ commons-lang3 ${commons-lang3} - + com.fasterxml.jackson.core jackson-databind @@ -127,6 +126,11 @@ poi ${poi.version} + + io.jsonwebtoken + jjwt + ${jwt.version} + diff --git a/src/main/java/com/boot/security/server/service/impl/TokenServiceImpl.java b/src/main/java/com/boot/security/server/service/impl/TokenServiceImpl.java index 968a4c2..089d63f 100644 --- a/src/main/java/com/boot/security/server/service/impl/TokenServiceImpl.java +++ b/src/main/java/com/boot/security/server/service/impl/TokenServiceImpl.java @@ -5,7 +5,6 @@ import java.util.concurrent.TimeUnit; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Primary; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Service; @@ -15,12 +14,12 @@ import com.boot.security.server.service.SysLogService; import com.boot.security.server.service.TokenService; /** - * token存到redis的实现类 + * token存到redis的实现类
+ * 普通token,uuid * * @author 小威老师 * */ -@Primary @Service public class TokenServiceImpl implements TokenService { diff --git a/src/main/java/com/boot/security/server/service/impl/TokenServiceJWTImpl.java b/src/main/java/com/boot/security/server/service/impl/TokenServiceJWTImpl.java new file mode 100644 index 0000000..d79570a --- /dev/null +++ b/src/main/java/com/boot/security/server/service/impl/TokenServiceJWTImpl.java @@ -0,0 +1,161 @@ +package com.boot.security.server.service.impl; + +import java.security.Key; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import javax.crypto.spec.SecretKeySpec; +import javax.xml.bind.DatatypeConverter; + +import org.apache.commons.collections4.MapUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Primary; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import com.boot.security.server.dto.LoginUser; +import com.boot.security.server.dto.Token; +import com.boot.security.server.service.SysLogService; +import com.boot.security.server.service.TokenService; + +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; + +/** + * token存到redis的实现类
+ * jwt实现的token + * + * @author 小威老师 + * + */ +@Primary +@Service +public class TokenServiceJWTImpl implements TokenService { + + private static final Logger log = LoggerFactory.getLogger("adminLogger"); + + /** + * token过期秒数 + */ + @Value("${token.expire.seconds}") + private Integer expireSeconds; + @Autowired + private RedisTemplate redisTemplate; + @Autowired + private SysLogService logService; + /** + * 私钥 + */ + @Value("${token.jwtSecret}") + private String jwtSecret; + + private static Key KEY = null; + private static final String LOGIN_USER_KEY = "LOGIN_USER_KEY"; + + @Override + public Token saveToken(LoginUser loginUser) { + loginUser.setToken(UUID.randomUUID().toString()); + String jwtToken = createJWTToken(loginUser); + cacheLoginUser(loginUser); + // 登陆日志 + logService.save(loginUser.getId(), "登陆", true, null); + + return new Token(jwtToken, loginUser.getLoginTime()); + } + + /** + * 生成jwt + * + * @param loginUser + * @return + */ + public String createJWTToken(LoginUser loginUser) { + Map claims = new HashMap<>(); + claims.put(LOGIN_USER_KEY, loginUser.getToken());// 放入一个随机字符串,通过该串可找到登陆用户 + + String jwtToken = Jwts.builder().setClaims(claims).signWith(SignatureAlgorithm.HS256, getKeyInstance()) + .compact(); + + return jwtToken; + } + + private void cacheLoginUser(LoginUser loginUser) { + loginUser.setLoginTime(System.currentTimeMillis()); + loginUser.setExpireTime(loginUser.getLoginTime() + expireSeconds * 1000); + // 根据uuid将loginUser缓存 + redisTemplate.boundValueOps(getTokenKey(loginUser.getToken())).set(loginUser, expireSeconds, TimeUnit.SECONDS); + } + + /** + * 更新缓存的用户信息 + */ + @Override + public void refresh(LoginUser loginUser) { + cacheLoginUser(loginUser); + } + + @Override + public LoginUser getLoginUser(String token) { + String string = getUUIDFromJWT(token); + if (string != null) { + return redisTemplate.boundValueOps(getTokenKey(string)).get(); + } + + return null; + } + + @Override + public boolean deleteToken(String token) { + String string = getUUIDFromJWT(token); + if (string != null) { + String key = getTokenKey(string); + LoginUser loginUser = redisTemplate.opsForValue().get(key); + if (loginUser != null) { + redisTemplate.delete(key); + // 退出日志 + logService.save(loginUser.getId(), "退出", true, null); + + return true; + } + } + + return false; + } + + private String getTokenKey(String token) { + return "tokens:" + token; + } + + private Key getKeyInstance() { + if (KEY == null) { + synchronized (TokenServiceJWTImpl.class) { + if (KEY == null) {// 双重锁 + byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(jwtSecret); + KEY = new SecretKeySpec(apiKeySecretBytes, SignatureAlgorithm.HS256.getJcaName()); + } + } + } + + return KEY; + } + + private String getUUIDFromJWT(String jwt) { + Map jwtClaims = null; + try { + jwtClaims = Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(jwt).getBody(); + } catch (ExpiredJwtException e) { + log.error("{}已过期", jwt); + return null; + } catch (Exception e) { + throw e; + } + + return MapUtils.getString(jwtClaims, LOGIN_USER_KEY); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index fa4f68c..33bb04d 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -57,5 +57,6 @@ log: token: expire: seconds: 7200 + jwtSecret: (XIAO:)_$^11244^%$_(WEI:)_@@++--(LAO:)_++++_.sds_(SHI:) server: port: 8080 \ No newline at end of file