Техника привязки имен Джерси в Spring Boot Rest

Я видел стратегию привязки имени из трикотажа для защиты api, это довольно круто для аутентификации, и довольно круто просто аннотировать конечные точки, которые вы хотите аутентифицировать, а в трикотажной форме вы можете привязать аннотацию к фильтру.

Кто-нибудь знает, как добиться этого при весенней загрузке?

Spring Boot не привязан к какой-либо структуре REST. Это просто начальный фреймворк. Вы можете использовать Jersey с Spring Boot так же, как вы можете использовать Spring MVC с Spring Boot. Вы действительно спрашиваете о Spring MVC?

Paul Samsotha 10.05.2018 00:03

Я знаю, что могу использовать трикотаж при весенней загрузке, но вы знаете, что по умолчанию есть некоторые загружаемые материалы, использование трикотажа добавляет сложности моему проекту, например, регистрация материала, я хочу сохранить это, используя Spring boot web для отдыха, поэтому я спрашиваю если я смогу добиться этого без майки;)

Ricardo 10.05.2018 00:14

Я хочу сказать, что Spring Boot - это не фреймворк для отдыха, а Spring MVC. Вы говорите о Spring MVC?

Paul Samsotha 10.05.2018 00:48

Ну да, это то, что пружинный ботинок использует сзади, так что да

Ricardo 10.05.2018 01:10

С Spring MVC вы можете использовать HandlerInterceptor и использовать HandlerMethod, чтобы получить Method и проверить Method на наличие аннотации. Я не уверен, есть ли способ просто аннотировать метод, чтобы определить, следует ли вызывать перехватчик для этого метода или нет.

Paul Samsotha 10.05.2018 07:46
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
5
655
1

Ответы 1

Проверить зависимости maven Убедитесь, что файл maven должен иметь зависимость spring-boot-starter-jersey.

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jersey</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

Создать REST API

Теперь создайте несколько ресурсов JAX-RS, к которым мы будем обращаться на этапе тестирования. Я создал класс UserResource.

UserResource.java

package com.howtodoinjava.jerseydemo;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name = "users")
@Path("/users")
public class UserResource 
{
    private static Map<Integer, User> DB = new HashMap<>(); 

    @GET
    @Produces("application/json")
    public Users getAllUsers() {
        Users users = new Users();
        users.setUsers(new ArrayList<>(DB.values()));
        return users;
    }

    @POST
    @Consumes("application/json")
    public Response createUser(User user) throws URISyntaxException 
    {
        if (user.getFirstName() == null || user.getLastName() == null) {
            return Response.status(400).entity("Please provide all mandatory inputs").build();
        }
        user.setId(DB.values().size()+1);
        user.setUri("/user-management/"+user.getId());
        DB.put(user.getId(), user);
        return Response.status(201).contentLocation(new URI(user.getUri())).build();
    }

    @GET
    @Path("/{id}")
    @Produces("application/json")
    public Response getUserById(@PathParam("id") int id) throws URISyntaxException 
    {
        User user = DB.get(id);
        if (user == null) {
            return Response.status(404).build();
        }
        return Response
                .status(200)
                .entity(user)
                .contentLocation(new URI("/user-management/"+id)).build();
    }

    @PUT
    @Path("/{id}")
    @Consumes("application/json")
    @Produces("application/json")
    public Response updateUser(@PathParam("id") int id, User user) throws URISyntaxException 
    {
        User temp = DB.get(id);
        if (user == null) {
            return Response.status(404).build();
        }
        temp.setFirstName(user.getFirstName());
        temp.setLastName(user.getLastName());
        DB.put(temp.getId(), temp);
        return Response.status(200).entity(temp).build();
    }

    @DELETE
    @Path("/{id}")
    public Response deleteUser(@PathParam("id") int id) throws URISyntaxException {
        User user = DB.get(id);
        if (user != null) {
            DB.remove(user.getId());
            return Response.status(200).build();
        }
        return Response.status(404).build();
    }

    static
    {
        User user1 = new User();
        user1.setId(1);
        user1.setFirstName("John");
        user1.setLastName("Wick");
        user1.setUri("/user-management/1");

        User user2 = new User();
        user2.setId(2);
        user2.setFirstName("Harry");
        user2.setLastName("Potter");
        user2.setUri("/user-management/2");

        DB.put(user1.getId(), user1);
        DB.put(user2.getId(), user2);
    }
}

Users.java

package com.howtodoinjava.jerseydemo;

import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;

@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name = "user")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    @XmlAttribute(name = "id")
    private int id;

    @XmlAttribute(name = "uri")
    private String uri;

    @XmlElement(name = "firstName")
    private String firstName;

    @XmlElement(name = "lastName")
    private String lastName;

    // Getters and Setters
}

Настроить Джерси

Теперь у нас есть ресурс JAX-RS, и мы хотим получить к нему доступ из приложения весенней загрузки, которое включает зависимость от Джерси. Зарегистрируем этот ресурс как ресурс Джерси.

пакет com.howtodoinjava.jerseydemo;

import org.glassfish.jersey.server.ResourceConfig; import org.springframework.stereotype.Component;

@Component
public class JerseyConfig extends ResourceConfig 
{
    public JerseyConfig() 
    {
        register(SecurityFilter.class);
        register(UserResource.class);
    }
}
  • Посмотрите аннотацию @Component. Это позволяет этому классу быть зарегистрировано, пока весенняя загрузка автоматически сканирует классы Java в исходном коде папка.

  • ResourceConfig предоставляет расширенные возможности для упрощения
    регистрация компонентов JAX-RS.

  • Класс SecurityFilter - это фактический процессор деталей аутентификации, который мы
    увидим позже в этом руководстве.

Extend spring boot application with SpringBootServletInitializer.

package com.howtodoinjava.jerseydemo;

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;

@SpringBootApplication
public class JerseydemoApplication extends SpringBootServletInitializer 
{
    public static void main(String[] args) 
    {
        new JerseydemoApplication().configure(new SpringApplicationBuilder(JerseydemoApplication.class)).run(args);
    }
}

Безопасные API REST с помощью аннотаций JAX-RS

Теперь, когда наши API готовы, мы приступим к их защите. Давайте аннотируем API с помощью Аннотации JAX-RS в зависимости от желаемого уровня доступа и ролей пользователей, которым разрешен к ним доступ.

package com.howtodoinjava.jerseydemo;

@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name = "users")
@Path("/users")
public class UserResource 
{
    private static Map<Integer, User> DB = new HashMap<>(); 

    @GET
    @PermitAll
    @Produces("application/json")
    public Users getAllUsers() {
        Users users = new Users();
        users.setUsers(new ArrayList<>(DB.values()));
        return users;
    }

    @POST
    @Consumes("application/json")
    @RolesAllowed("ADMIN")
    public Response createUser(User user) throws URISyntaxException 
    {
        if (user.getFirstName() == null || user.getLastName() == null) {
            return Response.status(400).entity("Please provide all mandatory inputs").build();
        }
        user.setId(DB.values().size()+1);
        user.setUri("/user-management/"+user.getId());
        DB.put(user.getId(), user);
        return Response.status(201).contentLocation(new URI(user.getUri())).build();
    }

    @GET
    @Path("/{id}")
    @Produces("application/json")
    @PermitAll
    public Response getUserById(@PathParam("id") int id) throws URISyntaxException 
    {
        User user = DB.get(id);
        if (user == null) {
            return Response.status(404).build();
        }
        return Response
                .status(200)
                .entity(user)
                .contentLocation(new URI("/user-management/"+id)).build();
    }

    @PUT
    @Path("/{id}")
    @Consumes("application/json")
    @Produces("application/json")
    @RolesAllowed("ADMIN")
    public Response updateUser(@PathParam("id") int id, User user) throws URISyntaxException 
    {
        User temp = DB.get(id);
        if (user == null) {
            return Response.status(404).build();
        }
        temp.setFirstName(user.getFirstName());
        temp.setLastName(user.getLastName());
        DB.put(temp.getId(), temp);
        return Response.status(200).entity(temp).build();
    }

    @DELETE
    @Path("/{id}")
    @RolesAllowed("ADMIN")
    public Response deleteUser(@PathParam("id") int id) throws URISyntaxException {
        User user = DB.get(id);
        if (user != null) {
            DB.remove(user.getId());
            return Response.status(200).build();
        }
        return Response.status(404).build();
    }

    static
    {
        User user1 = new User();
        user1.setId(1);
        user1.setFirstName("John");
        user1.setLastName("Wick");
        user1.setUri("/user-management/1");

        User user2 = new User();
        user2.setId(2);
        user2.setFirstName("Harry");
        user2.setLastName("Potter");
        user2.setUri("/user-management/2");

        DB.put(user1.getId(), user1);
        DB.put(user2.getId(), user2);
    }
}

You can see the security related JAX-RS annotations in above highlighted lines.

Написать фильтр безопасности с помощью JAX-RS ContainerRequestFilter


Теперь пришло время написать наш фильтр безопасности, который будет проверять входящие запросы, извлекать информацию об авторизации (базовая авторизация в этом примере), а затем сопоставлять имя пользователя и пароль, и, наконец, он будет проверять уровень доступа пользователя по его роли. Если все совпадает, будет выполнен доступ к API, иначе пользователь получит ответ об отказе в доступе.

package com.howtodoinjava.jerseydemo;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.StringTokenizer;

import javax.annotation.security.DenyAll;
import javax.annotation.security.PermitAll;
import javax.annotation.security.RolesAllowed;
import javax.ws.rs.container.ContainerRequestContext;
import javax.ws.rs.container.ResourceInfo;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.Provider;

/**
 * This filter verify the access permissions for a user based on 
 * user name and password provided in request
 * */
@Provider
public class SecurityFilter implements javax.ws.rs.container.ContainerRequestFilter
{
    private static final String AUTHORIZATION_PROPERTY = "Authorization";
    private static final String AUTHENTICATION_SCHEME = "Basic";
    private static final Response ACCESS_DENIED = Response.status(Response.Status.UNAUTHORIZED).build();
    private static final Response ACCESS_FORBIDDEN = Response.status(Response.Status.FORBIDDEN).build();
    private static final Response SERVER_ERROR = Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();

    @Context
    private ResourceInfo resourceInfo;

    @Override
    public void filter(ContainerRequestContext requestContext)
    {
        Method method = resourceInfo.getResourceMethod();
        //Access allowed for all 
        if ( ! method.isAnnotationPresent(PermitAll.class))
        {
            //Access denied for all 
            if (method.isAnnotationPresent(DenyAll.class))
            {
                requestContext.abortWith(ACCESS_FORBIDDEN);
                return;
            }

            //Get request headers
            final MultivaluedMap<String, String> headers = requestContext.getHeaders();

            //Fetch authorization header
            final List<String> authorization = headers.get(AUTHORIZATION_PROPERTY);

            //If no authorization information present; block access
            if (authorization == null || authorization.isEmpty())
            {
                requestContext.abortWith(ACCESS_DENIED);
                return;
            }

            //Get encoded username and password
            final String encodedUserPassword = authorization.get(0).replaceFirst(AUTHENTICATION_SCHEME + " ", "");

            //Decode username and password
            String usernameAndPassword = null;
            try {
                usernameAndPassword = new String(Base64.getDecoder().decode(encodedUserPassword));
            } catch (Exception e) {
                requestContext.abortWith(SERVER_ERROR);
                return;
            }

            //Split username and password tokens
            final StringTokenizer tokenizer = new StringTokenizer(usernameAndPassword, ":");
            final String username = tokenizer.nextToken();
            final String password = tokenizer.nextToken();

            //Verifying Username and password
            if (!(username.equalsIgnoreCase("admin") && password.equalsIgnoreCase("password"))){
                requestContext.abortWith(ACCESS_DENIED);
                return;
            }

            //Verify user access
            if (method.isAnnotationPresent(RolesAllowed.class))
            {
                RolesAllowed rolesAnnotation = method.getAnnotation(RolesAllowed.class);
                Set<String> rolesSet = new HashSet<String>(Arrays.asList(rolesAnnotation.value()));

                //Is user valid?
                if ( ! isUserAllowed(username, password, rolesSet))
                {
                    requestContext.abortWith(ACCESS_DENIED);
                    return;
                }
            }
        }
    }
    private boolean isUserAllowed(final String username, final String password, final Set<String> rolesSet) 
    {
        boolean isAllowed = false;

        //Step 1. Fetch password from database and match with password in argument
        //If both match then get the defined role for user from database and continue; else return isAllowed [false]
        //Access the database and do this part yourself
        //String userRole = userMgr.getUserRole(username);
        String userRole = "ADMIN";

        //Step 2. Verify user role
        if (rolesSet.contains(userRole))
        {
            isAllowed = true;
        }
        return isAllowed;
    }
}

Другие вопросы по теме