Skip to content

Commit

Permalink
feat($AuthCenter): add logout API
Browse files Browse the repository at this point in the history
  • Loading branch information
Johnny Miller (锺俊) committed Dec 29, 2020
1 parent 562da5a commit 66c6717
Show file tree
Hide file tree
Showing 13 changed files with 72 additions and 378 deletions.
2 changes: 2 additions & 0 deletions api-gateway/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,9 @@ maf:
configuration:
ignored-url:
post:
- "/auth-center/users/signup"
- "/auth-center/users/login"
- "/auth-center/users/logout"
get:
- "/favicon.ico"
- "/auth/check-username-uniqueness"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,8 @@ public interface JwtService {
* @param authentication the authentication
* @param rememberMe the remember me
* @return the string
* @throws SecurityException the security exception
*/
String createJwt(Authentication authentication, Boolean rememberMe) throws SecurityException;
String createJwt(Authentication authentication, Boolean rememberMe);

/**
* Create JWT string.
Expand All @@ -41,10 +40,9 @@ public interface JwtService {
* @param roles the roles
* @param authorities the authorities
* @return the JWT string
* @throws SecurityException the security exception
*/
String createJwt(Boolean rememberMe, Long id, String subject, List<String> roles, Collection<?
extends GrantedAuthority> authorities) throws SecurityException;
extends GrantedAuthority> authorities);

/**
* Parse JWT.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import cn.hutool.core.util.StrUtil;
import com.jmsoftware.maf.authcenter.security.service.JwtService;
import com.jmsoftware.maf.authcenter.universal.configuration.JwtConfiguration;
import com.jmsoftware.maf.authcenter.universal.service.RedisService;
import com.jmsoftware.maf.common.domain.authcenter.security.ParseJwtPayload;
import com.jmsoftware.maf.common.domain.authcenter.security.ParseJwtResponse;
import com.jmsoftware.maf.common.domain.authcenter.security.UserPrincipal;
Expand All @@ -15,6 +14,9 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
Expand Down Expand Up @@ -44,7 +46,7 @@
@SuppressWarnings("unused")
public class JwtServiceImpl implements JwtService {
private final JwtConfiguration jwtConfiguration;
private final RedisService redisService;
private final RedisTemplate<Object, Object> redisTemplate;
private SecretKey secretKey;
private JwtParser jwtParser;

Expand All @@ -54,18 +56,20 @@ private void init() {
secretKey = Keys.hmacShaKeyFor(jwtConfiguration.getSigningKey().getBytes(StandardCharsets.UTF_8));
log.warn("Secret key for JWT was generated. Algorithm: {}", secretKey.getAlgorithm());
jwtParser = Jwts.parserBuilder().setSigningKey(secretKey).build();
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer());
}

@Override
public String createJwt(Authentication authentication, Boolean rememberMe) throws SecurityException {
public String createJwt(Authentication authentication, Boolean rememberMe) {
val userPrincipal = (UserPrincipal) authentication.getPrincipal();
return createJwt(rememberMe, userPrincipal.getId(), userPrincipal.getUsername(), userPrincipal.getRoles(),
userPrincipal.getAuthorities());
}

@Override
public String createJwt(Boolean rememberMe, Long id, String subject, List<String> roles,
Collection<? extends GrantedAuthority> authorities) throws SecurityException {
Collection<? extends GrantedAuthority> authorities) {
val now = new Date();
val builder = Jwts.builder()
.setId(id.toString())
Expand All @@ -82,13 +86,10 @@ public String createJwt(Boolean rememberMe, Long id, String subject, List<String
}
val jwt = builder.compact();
// Store new JWT in Redis
val redisOperationResult = redisService.set(jwtConfiguration.getJwtRedisKeyPrefix() + subject, jwt, ttl,
TimeUnit.MILLISECONDS);
if (redisOperationResult) {
return jwt;
} else {
throw new SecurityException(HttpStatus.INTERNAL_SERVER_ERROR, "Cannot persist JWT into Redis", null);
}
String redisKeyOfJwt = String.format("%s%s", jwtConfiguration.getJwtRedisKeyPrefix(), subject);
redisTemplate.opsForValue().set(redisKeyOfJwt, jwt, ttl, TimeUnit.MILLISECONDS);
log.info("Storing JWT in Redis. Key: {}, Value: {}", redisKeyOfJwt, jwt);
return jwt;
}

@Override
Expand All @@ -114,14 +115,14 @@ public Claims parseJwt(String jwt) throws SecurityException {
val username = claims.getSubject();
val redisKeyOfJwt = jwtConfiguration.getJwtRedisKeyPrefix() + username;
// Check if JWT exists
val expire = redisService.getExpire(redisKeyOfJwt, TimeUnit.MILLISECONDS);
val expire = redisTemplate.opsForValue().getOperations().getExpire(redisKeyOfJwt, TimeUnit.MILLISECONDS);
if (ObjectUtil.isNull(expire) || expire <= 0) {
throw new SecurityException(HttpStatus.UNAUTHORIZED, "JWT is expired (Redis expiration)");
}
// Check if the current JWT is equal to the one in Redis.
// If it's noe equal, that indicates current user has signed out or logged in before.
// Both situations reveal the JWT has expired.
val jwtInRedis = redisService.get(redisKeyOfJwt);
val jwtInRedis = (String) redisTemplate.opsForValue().get(redisKeyOfJwt);
if (!StrUtil.equals(jwt, jwtInRedis)) {
throw new SecurityException(HttpStatus.UNAUTHORIZED, "JWT is expired (Not equaled)");
}
Expand All @@ -133,8 +134,9 @@ public void invalidateJwt(HttpServletRequest request) throws SecurityException {
val jwt = getJwtFromRequest(request);
val username = getUsernameFromJwt(jwt);
// Delete JWT from redis
val deletedKeyNumber = redisService.delete(jwtConfiguration.getJwtRedisKeyPrefix() + username);
log.error("Invalidate JWT. Username = {}, deleted = {}", username, deletedKeyNumber);
String redisKeyOfJwt = String.format("%s%s", jwtConfiguration.getJwtRedisKeyPrefix(), username);
val deletedKeyNumber = redisTemplate.opsForValue().getOperations().delete(redisKeyOfJwt);
log.error("Invalidate JWT. Redis key of JWT = {}, deleted = {}", redisKeyOfJwt, deletedKeyNumber);
}

@Override
Expand All @@ -151,7 +153,7 @@ public String getUsernameFromRequest(HttpServletRequest request) throws Security

@Override
public String getJwtFromRequest(HttpServletRequest request) {
val bearerToken = request.getHeader(JwtConfiguration.TOKEN_PREFIX);
val bearerToken = request.getHeader(HttpHeaders.AUTHORIZATION);
if (StrUtil.isNotBlank(bearerToken) && bearerToken.startsWith(JwtConfiguration.TOKEN_PREFIX)) {
return bearerToken.substring(JwtConfiguration.TOKEN_PREFIX.length());
}
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

Loading

0 comments on commit 66c6717

Please sign in to comment.