Я пытаюсь реализовать какую-то аутентификацию на основе ролей. Я использую токены JWT. Я просматривал руководства, но все они упоминают использование «Spring boot». Как мне настроить аутентификацию на основе ролей на моей конечной точке покоя в Java? Желательно через какой-нибудь фильтр.
Я ищу способ просто добавить: @Role(Role.ADMIN)
перед конечной точкой.
У меня уже настроены следующие классы:
Перечисленная роль:
public enum Role {
User,
Admin
}
Простой токен JWT:
{
"sub": "users/TzMUocMF4p",
"exp": 1554646441,
"username": "[email protected]",
"ID": 6,
"Role": "Admin",
"iat": 1554641041
}
Простая конечная точка CRUD
@Path("User")
public class UserResource {
@EJB
private UserDAO userappDAO;
@GET
@JWTTokenNeeded
@Produces("application/json")
public List<Userapp> all() {
return userappDAO.getAll();
}
}
JWT проверяет (@JWTTokenNeeded
) класс ниже:
@javax.ws.rs.NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface JWTTokenNeeded {
}
Собственно фильтр:
@Provider
@JWTTokenNeeded
@Priority(Priorities.AUTHENTICATION)
public class JWTTokenNeededFilter implements ContainerRequestFilter {
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// Get the HTTP Authorization header from the request
String authorizationHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
try {
// Extract the token from the HTTP Authorization header
String token = authorizationHeader.substring("Bearer".length()).trim();
// Validate the token
Jwts.parser().setSigningKey("MYSECRET".getBytes("UTF-8")).parseClaimsJws(token);
}
catch (Exception e) {
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
}
}
}
Если пользователь не авторизован, я хочу выйти с помощью:
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
Если пользователь авторизован, конечная точка должна делать свое дело.
Взгляните на MicroProfile JWT (eclipse.org/community/eclipse_newsletter/2017/сентябрь/…). При этом вы получаете java.security.Principal
, проанализированный из токена JWT, и можете использовать @RolesAllowed
на своих конечных точках JAX-RS. Для получения дополнительной информации взгляните на следующий пост: rickpil.de/…
Я нашел рабочее решение. Он включает в себя добавление нескольких строк в интерфейс @JWTTokenNeeded
и класс JWTTokenNeededFilter
.
В итоге я получил следующий код:
JWTTokeNeededФильтр:
@Provider
@JWTTokenNeeded
@Priority(Priorities.AUTHENTICATION)
public class JWTTokenNeededFilter implements ContainerRequestFilter {
@Context
private ResourceInfo resourceInfo;
@Override
public void filter(ContainerRequestContext requestContext) throws IOException {
// Get the HTTP Authorization header from the request
String authorizationHeader = requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
try {
// Extract the token from the HTTP Authorization header
String token = authorizationHeader.substring("Bearer".length()).trim();
// Validate the token
Claims claims = Jwts.parser().setSigningKey("MYSECRET".getBytes("UTF-8")).parseClaimsJws(token).getBody();
Method method =resourceInfo.getResourceMethod();
if ( method != null){
// Get allowed permission on method
JWTTokenNeeded JWTContext = method.getAnnotation(JWTTokenNeeded.class);
Role permission = JWTContext.Permissions();
if (permission != Role.NoRights ) {
// Get Role from jwt
String roles = claims.get("Role", String.class);
Role roleUser = Role.valueOf(roles);
// if role allowed != role jwt -> UNAUTHORIZED
if (!permission.equals(roleUser)) {
throw new Exception("no roles");
}
}
}
}
catch (Exception e) {
e.printStackTrace();
requestContext.abortWith(Response.status(Response.Status.UNAUTHORIZED).build());
}
}
}
Интерфейс @JWTTokenNeeded:
@javax.ws.rs.NameBinding
@Retention(RUNTIME)
@Target({TYPE, METHOD})
public @interface JWTTokenNeeded {
Role Permissions() default Role.NoRights;
}
Разрешить роли доступ к конечной точке так же просто, как добавить @JWTTokenNeeded(Permissions = Role.Admin)
Вот пример:
@Path("User")
public class UserResource {
@EJB
private UserappDAO userDAO;
@GET
@JWTTokenNeeded(Permissions = Role.Admin)
@Produces("application/json")
public List<Userapp> all() {
return userDAO.getAll();
}
}
Я думаю, что вы ищете реализацию
@Interceptor
stackoverflow.com/questions/18853221/…