Мне нужно использовать некоторую пользовательскую логику авторизации ролей с Spring Security и Jaxrs.Это означает, что я хочу использовать мою собственную аннотацию.У меня проблема с получением метода и класса, сопоставленных с текущим запросом, и они мне нужны, чтобы я мог извлечь аннотации к ним.Я пытался ввести ResourceInfo
, но это всегда кажется нулевым.Есть идеи, как получить эти данные в фильтре?(см. метод getAuthentication)
package com.concentric.scenarios.rest.auth.jwt;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.NotAuthorizedException;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.security.web.header.HeaderWriterFilter;
import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestWrapper;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.concentric.scenarios.domain.user.AppRole;
import com.concentric.scenarios.security.Authorized;
import com.concentric.scenarios.security.SecurityConstants;
import com.concentric.scenarios.util.JWTUtil;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
@SuppressWarnings("unused")
private AuthenticationManager authManager;
private SecurityConstants securityConstants;
public JWTAuthorizationFilter(AuthenticationManager authManager, SecurityConstants securityConstants) {
super(authManager);
this.securityConstants = securityConstants;
}
@Override
protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
throws IOException, ServletException {
String header = req.getHeader(securityConstants.getHeaderKey());
if (header == null || !header.startsWith(securityConstants.getTokenPrefix())) {
if(securityConstants.isMultipleProviders()) {
log.info("Missing or malformed JWT token. Continuing security authorization filtering.");
} else {
log.error("Missing or malformed JWT token. JWT is only registered security provider.");
}
chain.doFilter(req, res);
return;
}
UsernamePasswordAuthenticationToken authentication = getAuthentication(req);
SecurityContextHolder.getContext().setAuthentication(authentication);
chain.doFilter(req, res);
}
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
String authorizationHeader = request.getHeader(securityConstants.getHeaderKey());
if (authorizationHeader != null) {
DecodedJWT jwt = JWTUtil.verifyToken(
authorizationHeader,
securityConstants.getSecret(),
securityConstants.getTokenPrefix());
String principalRoleStr = jwt.getClaim("role").asString();
Class<?> resourceClass = // somehow obtain the class mapped to this request by jax-rs
Method resourceMethod = // somehow obtain the method mapped to this request by jax-rs
// no authentication is needed
if(!isAnnotationPresent(Authorized.class, resourceClass) && !isAnnotationPresent(Authorized.class, resourceMethod)) {
return null;
}
// extract roles from class
List<AppRole> classRoles = extractRoles(resourceClass);
// extract roles from method
List<AppRole> methodRoles = extractRoles(resourceMethod);
AppRole principalRole = AppRole.valueOf(principalRoleStr);
// Check if the user is allowed to execute the method
if (methodRoles.isEmpty()) {
checkPermissions(classRoles, principalRole);
} else {
checkPermissions(methodRoles, principalRole);
}
return new UsernamePasswordAuthenticationToken(jwt.getSubject(), null, new ArrayList<>());
}
return null;
}
private void checkPermissions(List<AppRole> allowedRoles, AppRole userRole) {
boolean hasRole = false;
for(AppRole allowed : allowedRoles) {
if(userRole.hasRights(allowed)) {
hasRole = true;
break;
}
}
if(hasRole == false) {
throw new NotAuthorizedException("User is not authorized to access resource with JWT auth!");
}
}
private List<AppRole> extractRoles(AnnotatedElement annotatedElement) {
if (annotatedElement == null) {
return new ArrayList<>();
} else {
Authorized secured = annotatedElement.getAnnotation(Authorized.class);
if (secured == null) {
return new ArrayList<AppRole>();
} else {
AppRole[] allowedRoles = secured.value();
return Arrays.asList(allowedRoles);
}
}
}
private boolean isAnnotationPresent(Class<? extends Annotation> annotation, AnnotatedElement annotatedElement) {
if (annotatedElement == null) {
return false;
} else if(annotatedElement.isAnnotationPresent(annotation)) {
return true;
}
return false;
}
}
@Component
@ApplicationPath("/api")
public class ScenariosRestConfig extends ResourceConfig {
public ScenariosRestConfig() {
packages(ScenariosRestConfig.class.getPackageName());
}
}