TokenRequiredAspect.java
package no.ntnu.idatt2105.l4.demo.aop;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import no.ntnu.idatt2105.l4.demo.service.SecurityService;
import no.ntnu.idatt2105.l4.demo.service.SecurityServiceImpl;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.server.ResponseStatusException;
import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.DatatypeConverter;
@Aspect
@Component
public class TokenRequiredAspect {
@Autowired
SecurityService securityService;
// @Before("execution(* no.ntnu.idatt2105.l4.demo.web.Lesson4Controller.openEndpoint())")
// public void tokenRequiredWithoutAnnoation() throws Throwable{
// System.out.println("Before tokenRequiredWithExecution");
// }
@Before("@annotation(tokenRequired)")
public void tokenRequiredWithAnnotation(TokenRequired tokenRequired) throws Throwable {
System.out.println("Before tokenRequiredWithAnnotation");
ServletRequestAttributes reqAttributes = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
HttpServletRequest request = reqAttributes.getRequest();
// checks for token in request header
String tokenInHeader = request.getHeader("Authorization");
if (tokenInHeader.startsWith("Bearer")) {
tokenInHeader = tokenInHeader.substring("Bearer ".length());
}
if(ObjectUtils.isEmpty(tokenInHeader)){
// throw new IllegalArgumentException("Empty token");
// Instead of using a "more correct" exception here, like IllegalArgumentException,
// we cheat a little and directly throw a ResponseStatusException. This is due
// to the fact that otherwise Spring Boot will return a "500 - Internal Server
// Error". Directly returning the ResponseStatusException here is
// something I consider OK, even if it's not optimal, given that this advice
// is exclusively meant to be used in conjunction with Controllers.
System.out.println("Empty token received");
throw new ResponseStatusException(HttpStatus.I_AM_A_TEAPOT, "Empty token");
}
Claims claims = Jwts.parser()
.setSigningKey(DatatypeConverter.parseBase64Binary(SecurityServiceImpl.secretKey))
.parseClaimsJws(tokenInHeader).getBody();
if(claims == null || claims.getSubject() == null){
// throw new IllegalArgumentException("Token Error : Claim is null");
System.out.println("Claim is null");
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Token Error : Claim is null");
}
if (!securityService.validToken(tokenInHeader)) {
System.out.println("Could not find token among valid ones");
throw new ResponseStatusException(HttpStatus.UNAUTHORIZED, "Token error: could not find token among valid ones");
// throw new IllegalArgumentException("Token error: could find token among valid ones");
}
// Here we probably should have checked the expiration, as well, and if it's too close to
// expiry, refresh it. If it's after expiry, call SecurityService and tell it to
// remove the token from the list of valid tokens.
}
}