Ответ 1
Есть две вещи, когда вы пытаетесь реализовать REST. Одна из них - это аутентификация (которая кажется, что у вас есть ее работа), а другая - авторизация (вот что я считаю вашим вопросом).
Как я уже справился с этим в dropwizard, с каждым подписчиком пользователя вы возвращаете какой-то access_token (это доказывает, что они аутентифицированы) обратно клиенту, который должен быть возвращен ими в КАЖДОМ последовательном вызове, который они делают как часть некоторого заголовка (обычно это делается через заголовок "Авторизация" ). На стороне сервера вам нужно будет сохранить/сопоставить этот access_token с этим пользователем, прежде чем возвращать его клиенту, и когда все последующие вызовы будут сделаны с помощью этого access_token, вы посмотрите на пользователя, сопоставленного с этим access_token, и определите, является ли этот пользователь имеет право доступа к этому ресурсу или нет. Теперь пример:
1) Пользователь подписывается с помощью /myapp/signin
2) Вы аутентифицируете пользователя и отправляете обратно access_token в качестве ответа, сохраняя его на своей стороне, например access_token → userIdABCD
3) Клиент возвращается к /myapp/ {username}/getstuff. Если клиент не предоставил заголовок "Авторизация" с предоставленным вами access_token, вы должны сразу же отправить 401 Несанкционированный код.
4) Если клиент действительно предоставляет access_token, вы можете найти пользователя на основе этого access_token, который вы сохранили на шаге 2, и проверить, имеет ли этот userId доступ к этому ресурсу. Если это не так, верните 401 несанкционированный код, и если у него есть доступ, верните фактические данные обратно.
Теперь выходим из части заголовка "Авторизация" . Вы можете получить доступ к заголовку "Authoroziation" во всех своих вызовах, используя параметр "@Context HttpServletRequest hsr", но имеет ли смысл добавить этот параметр в каждый вызов? Нет, нет. Здесь защитные фильтры помогают в dropwizard. Вот пример того, как добавить фильтр безопасности.
public class SecurityFilter extends OncePerRequestFilter{
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException{
String accessToken = request.getHeader("Authorization");
// Do stuff here based on the access token (check for user authorization to the resource ...
}
Теперь, какой ресурс этот защитный фильтр действительно защищает? Для этого вам нужно будет добавить этот фильтр к определенным ресурсам, которые вы хотите защитить, что можно сделать следующим образом:
environment.addFilter(SecurityFilter, "/myapp/*");
Помните о том, что как ваши URL/myapp/signin, так и /myapp/ {username}/getstuff, оба будут проходить через этот фильтр безопасности, НО, /myapp/signin НЕ будет иметь access_token, очевидно, t, предоставленных клиенту. Это необходимо позаботиться в самом фильтре, например:
String url = request.getRequestURL().toString();
if(url.endsWith("signin"))
{
// Don't look for authorization header, and let the filter pass without any checks
}
else
{
// DO YOUR NORMAL AUTHORIZATION RELATED STUFF HERE
}
URL, который вы защищаете, будет зависеть от того, как структурированы ваши URL-адреса и что вы хотите защитить. Лучшие URL-адреса, которые вы разрабатываете, тем легче будет писать фильтры защиты для их защиты. С добавлением этого фильтра безопасности поток будет выглядеть следующим образом:
1) Пользователь переходит в /myapp/signin. Вызов будет проходить через фильтр, и из-за этого оператора "if" он будет продолжать ваш ACTUAL-ресурс/myapp/signin, и вы назначите access_token на основе успешной аутентификации
2) Пользователь делает вызов /myapp/ {username}/mystuff с помощью access_token. Этот вызов будет проходить через тот же фильтр безопасности и будет проходить через инструкцию else, где вы фактически выполняете авторизацию. Если авторизация пройдет, вызов продолжит ваш фактический обработчик ресурсов, и если он не авторизован, ему необходимо вернуть 401.
public class SecurityFilter extends OncePerRequestFilter
{
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException
{
String url = request.getRequestURL().toString();
String accessToken = request.getHeader("Authorization");
try
{
if (accessToken == null || accessToken.isEmpty())
{
throw new Exception(Status.UNAUTHORIZED.getStatusCode(), "Provided access token is either null or empty or does not have permissions to access this resource." + accessToken);
}
if (url.endsWith("/signin"))
{
//Don't Do anything
filterChain.doFilter(request, response);
}
else
{
//AUTHORIZE the access_token here. If authorization goes through, continue as normal, OR throw a 401 unaurhtorized exception
filterChain.doFilter(request, response);
}
}
catch (Exception ex)
{
response.setStatus(401);
response.setCharacterEncoding("UTF-8");
response.setContentType(MediaType.APPLICATION_JSON);
response.getWriter().print("Unauthorized");
}
}
}
Надеюсь, это поможет! Принял меня около двух дней, чтобы понять это сам!