0

Annotaion:

@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE, ElementType.METHOD})
public @interface HasRole {
    String[] value();
}

Aspect:


@Aspect
@Component
public class SecurityAspect {
    private final Logger logger = LoggerFactory.getLogger(SecurityAspect.class);

    private final JwtUtil jwtUtil;

    private final UserRepo userRepo;

    public SecurityAspect(JwtUtil jwtUtil, UserRepo userRepo) {
        this.jwtUtil = jwtUtil;
        this.userRepo = userRepo;
    }

    @Pointcut("@annotation(hasRole)")
    public void hasRoleAnnotation(HasRole hasRole) {}

    @Before("hasRoleAnnotation(hasRole)")
    public void hasRole(HasRole hasRole) {
        HttpServletRequest request =
            ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String authorizationHeader = request.getHeader(Constants.AUTHORIZATION_HEADER);
        if (authorizationHeader == null || !authorizationHeader.startsWith(Constants.TOKEN_PREFIX)) {
            throw new ForbiddenException("Unauthorized", "Authentication token is required");
        }
        String token = authorizationHeader.replace(Constants.TOKEN_PREFIX, "");
        logger.info("Token : {}", token);
        Claims claims = jwtUtil.validateAndExtractClaims(token);
        Integer userId = claims.get(Constants.SUBJECT, Integer.class);
        UserDto userDto = new UserDto().get(userRepo.findById(userId));
        List<String> roles = userDto.getRoles().stream().map(RoleDto::getName).collect(Collectors.toList());
        if(!roles.containsAll(Arrays.stream(hasRole.value()).collect(Collectors.toList()))){
            throw new ForbiddenException("Unauthorized", "you are not " + Arrays.toString(hasRole.value()));
        }
    }
}

Controller:

@RestController
public class AuthenticationController {

    @HasRole("ADMIN")
    @GetMapping
    public String getInit() {
        Integer userId = SecurityUtils.getCurrentUserUserId()
            .orElseThrow(() -> new ForbiddenException("Unauthorized", "Authentication token is required"));
        return "WELCOME " + userId;
    }
}

The output for the request is "WELCOME 1"

@HasRole("ADMIN")
@RestController
public class AuthenticationController {

    @GetMapping
    public String getInit() {
        Integer userId = SecurityUtils.getCurrentUserUserId()
            .orElseThrow(() -> new ForbiddenException("Unauthorized", "Authentication token is required"));
        return "WELCOME " + userId;
    }
}

but for the class annotation it is throwing the error How to solve it? And how do I determine the order of execution of the annotations if more than one annotation is specified on a single class or method

Sai Uttej
  • 199
  • 7
  • 1
    Please don't go down this path. Don't write your own security library but use an existing one, like Spring Security, Apache Shiro etc. Don't re-invent this all important security wheel. – M. Deinum Jan 06 '22 at 12:53
  • It is just an example. I might face the same problem in any other scenario. Can you give a solution for this? – Sai Uttej Jan 06 '22 at 17:32
  • 1
    You can find the (technical) explanation of why your aspect fails to intercept methods in annotated classes in the answer of the question I marked this one as a duplicate of. Otherwise, I am supporting @M.Deinum's statement. But you can for now extend your pointcut to cover both class- and method-level annotations in order to prove that it technically works like that. Let me know if you have problems doing this. – kriegaex Jan 07 '22 at 00:45

0 Answers0