2

Я хотел бы использовать Facebook Tokens для аутентификации моего REST-сервера с использованием Spring Security. Не могли бы вы рассказать, как я могу интегрировать эту безопасность в мое приложение Spring.Фильтр социальной фильтрации Spring для автономных конечных точек REST, которые используют токен Facebook для аутентификации

Я хотел бы использовать то же управление пользователями, что и Spring Social Security. UserConnection таблица таблицы и локального пользователя.

ответ

6

Вы можете скачать образец кода из:

https://github.com/ozgengunay/FBSpringSocialRESTAuth

Мы искали решение, «Весна», который крепит покоиться движки с использованием Facebook OAuth токен, что REST клиенты уже имеют в руках. Например: у вас есть мобильное приложение с Facebook Connect SDK, реализованное в самом приложении, а с другой стороны, у вас есть бэкэнд, который предоставляет API REST. Вы хотите аутентифицировать вызовы API REST с помощью токена OAuth Facebook. Решение реализует этот сценарий.

К сожалению, Spring Social Security Framework защищает только ваши HTTP-запросы, не связанные с вашим статусом, а не ваш бэкэнд REST.

Это расширение весеннего социального обеспечения, которое состоит из одного компонента: FacebookTokenAuthenticationFilter. Этот фильтр перехватывает все вызовы REST. Клиенты должны отправлять Facebook OAuth Token в URL-адрес в качестве параметра «input_token» в каждом запросе, поскольку API-интерфейсы REST являются беспроблемными по своей природе. Фильтр ищет этот токен и проверяет его на вызов «debug_token» Graph Api. Если токен подтвержден, фильтр пытается совместить пользователя с локальной системой управления пользователями. Если такого зарегистрированного пользователя еще нет, фильтр регистрирует пользователя как нового пользователя.

Вы можете использовать этот Фильтр вместе со стандартным социальным обеспечением SocialAuthenticationFilter of Spring Social Security, если у вас есть также службы, отличные от вашего REST API, такие как веб-сервер. Таким образом, вы можете использовать ту же систему управления пользователями.

1) Создайте свою пользовательскую таблицу следующим образом в MYSQL:

CREATE TABLE IF NOT EXISTS `user` (
    `id` varchar(50) NOT NULL, 
    `email` varchar(255) NOT NULL COMMENT 'unique', 
    `first_name` varchar(255) NOT NULL, 
    `last_name` varchar(255) NOT NULL, 
    `password` varchar(255) DEFAULT NULL, 
    `role` varchar(255) NOT NULL, 
    `sign_in_provider` varchar(20) DEFAULT NULL, 
    `creation_time` datetime NOT NULL, 
    `modification_time` datetime NOT NULL, 
    `status` varchar(20) NOT NULL COMMENT 'not used', 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `email` (`email`) 
); 

2) Настройка источника данных в context.xml:

context.xml в котом:

<Resource auth="Container" driverClassName="com.mysql.jdbc.Driver" maxActive="100" maxIdle="30" maxWait="10000" 
name="jdbc/thingabled" password="..." type="javax.sql.DataSource" url="jdbc:mysql://localhost:3306/..." username="..."/> 

3) Конфигурация пружины: мы настраиваем весеннюю безопасность для перехвата URL-адресов, начинающихся с «защищенных» FacebookTokenAuthenticationFilter для аутентификации. Авторизация будет выполняться с помощью роли «ROLE_USER_REST_MOBILE».

<security:http use-expressions="true" pattern="/protected/**" 
create-session="never" entry-point-ref="forbiddenEntryPoint"> 
    <security:intercept-url pattern="/**" 
    access="hasRole('ROLE_USER_REST_MOBILE')" /> 
<!-- Adds social authentication filter to the Spring Security filter chain. --> 
    <security:custom-filter ref="facebookTokenAuthenticationFilter" 
    before="FORM_LOGIN_FILTER" /> 
</security:http> 


<bean id="facebookTokenAuthenticationFilter" 
class="com.ozgen.server.security.oauth.FacebookTokenAuthenticationFilter"> 
    <constructor-arg index="0" ref="authenticationManager" /> 
    <constructor-arg index="1" ref="userIdSource" /> 
    <constructor-arg index="2" ref="usersConnectionRepository" /> 
    <constructor-arg index="3" ref="connectionFactoryLocator" /> 
</bean> 

<security:authentication-manager alias="authenticationManager"> 
    <security:authentication-provider 
    ref="socialAuthenticationProvider" /> 
</security:authentication-manager> 

<!-- Configures the social authentication provider which processes authentication 
requests made by using social authentication service (FB). --> 
<bean id="socialAuthenticationProvider" 
class="org.springframework.social.security.SocialAuthenticationProvider"> 
    <constructor-arg index="0" ref="usersConnectionRepository" /> 
    <constructor-arg index="1" ref="simpleSocialUserDetailsService" /> 
</bean> 

<bean id="forbiddenEntryPoint" 
class="org.springframework.security.web.authentication.Http403ForbiddenEntryPoint" /> 

<!-- This bean determines the account ID of the user.--> 
<bean id="userIdSource" 
class="org.springframework.social.security.AuthenticationNameUserIdSource" /> 

<!-- This is used to hash the password of the user. --> 
<bean id="passwordEncoder" 
class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"> 
    <constructor-arg index="0" value="10" /> 
</bean> 
<!-- This bean encrypts the authorization details of the connection. In 
our example, the authorization details are stored as plain text. DO NOT USE 
THIS IN PRODUCTION. --> 
<bean id="textEncryptor" class="org.springframework.security.crypto.encrypt.Encryptors" 
factory-method="noOpText" /> 

4) все запросы REST будет перехвачены FacebookTokenAuthenticationFilter для проверки подлинности запросов с использованием Facebook действующего токена. Проверяет, действителен ли токен Facebook. Если токен Facebook недействителен, запрос будет отклонен. Если токен Facebook isvalid, то фильтр попытается аутентифицировать запрос через SimpleSocialUserDetailsService. Если данные пользователя и пользователя не доступны, создается новый пользователь (через UserService) и UserConnection.

private Authentication attemptAuthService(...) { 
    if (request.getParameter("input_token") == null) { 
    throw new SocialAuthenticationException("No token in the request"); 
    } 
    URIBuilder builder = URIBuilder.fromUri(String.format("%s/debug_token", "https://graph.facebook.com")); 
    builder.queryParam("access_token", access_token); 
    builder.queryParam("input_token", request.getParameter("input_token")); 
    URI uri = builder.build(); 
    RestTemplate restTemplate = new RestTemplate(); 

    JsonNode resp = null; 
    try { 
    resp = restTemplate.getForObject(uri, JsonNode.class); 
    } catch (HttpClientErrorException e) { 
    throw new SocialAuthenticationException("Error validating token"); 
    } 
    Boolean isValid = resp.path("data").findValue("is_valid").asBoolean(); 
    if (!isValid) 
    throw new SocialAuthenticationException("Token is not valid"); 

    AccessGrant accessGrant = new AccessGrant(request.getParameter("input_token"), null, null, 
    resp.path("data").findValue("expires_at").longValue()); 

    Connection<?> connection = ((OAuth2ConnectionFactory<?>) authService.getConnectionFactory()) 
    .createConnection(accessGrant); 
    SocialAuthenticationToken token = new SocialAuthenticationToken(connection, null); 
    Assert.notNull(token.getConnection()); 

    Authentication auth = SecurityContextHolder.getContext().getAuthentication(); 
    if (auth == null || !auth.isAuthenticated()) { 
    return doAuthentication(authService, request, token); 
    } else { 
    addConnection(authService, request, token); 
    return null; 
    } 
} 

5) Другие важные разделы проекта:

Пользователь: Entity, который отображает таблицу 'пользователя'.

@Entity 
@Table(name = "user") 
public class User extends BaseEntity { 

    @Column(name = "email", length = 255, nullable = false, unique = true) 
    private String email; 

    @Column(name = "first_name", length = 255, nullable = false) 
    private String firstName; 

    @Column(name = "last_name", length = 255, nullable = false) 
    private String lastName; 

    @Column(name = "password", length = 255) 
    private String password; 

    @Column(name = "role", length = 255, nullable = false) 
    private String rolesString; 

    @Enumerated(EnumType.STRING) 
    @Column(name = "sign_in_provider", length = 20) 
    private SocialMediaService signInProvider; 

    ... 
} 

UserRepository: Spring Data JPA хранилище, которое позволит запускать операции CRUD на сущности 'Пользователь'.

public interface UserRepository extends JpaRepository<User, String> { 
    public User findByEmailAndStatus(String email,Status status); 
    public User findByIdAndStatus(String id,Status status); 
} 

UserService: Этой весной услуга будет использоваться для создания новой учетной записи пользователя вставляя данные в таблице «пользователя».

@Service 
public class UserService { 
    private static final Logger LOGGER = LoggerFactory.getLogger(UserService.class); 

    @Autowired 
    private UserRepository repository; 

    @Transactional 
    public User registerNewUserAccount(RegistrationForm userAccountData) throws DuplicateEmailException { 
     LOGGER.debug("Registering new user account with information: {}", userAccountData); 

     if (emailExist(userAccountData.getEmail())) { 
      LOGGER.debug("Email: {} exists. Throwing exception.", userAccountData.getEmail()); 
      throw new DuplicateEmailException("The email address: " + userAccountData.getEmail() + " is already in use."); 
     } 

     LOGGER.debug("Email: {} does not exist. Continuing registration.", userAccountData.getEmail()); 

     User registered =User.newEntity(); 
     registered.setEmail(userAccountData.getEmail()); 
     registered.setFirstName(userAccountData.getFirstName()); 
     registered.setLastName(userAccountData.getLastName()); 
     registered.setPassword(null); 
     registered.addRole(User.Role.ROLE_USER_WEB); 
     registered.addRole(User.Role.ROLE_USER_REST); 
     registered.addRole(User.Role.ROLE_USER_REST_MOBILE); 

     if (userAccountData.isSocialSignIn()) { 
      registered.setSignInProvider(userAccountData.getSignInProvider()); 
     } 

     LOGGER.debug("Persisting new user with information: {}", registered); 

     return repository.save(registered); 
    } 
    .... 
} 

SimpleSocialUserDetailsService: Этой весной услуга будет использоваться для аутентификации SocialAuthenticationProvider USERID пользователя.

@Service 
public class SimpleSocialUserDetailsService implements SocialUserDetailsService { 
    private static final Logger LOGGER = LoggerFactory.getLogger(SimpleSocialUserDetailsService.class); 
    @Autowired 
    private UserRepository repository; 

    @Override 
    public SocialUserDetails loadUserByUserId(String userId) throws UsernameNotFoundException, DataAccessException { 
     LOGGER.debug("Loading user by user id: {}", userId); 

     User user = repository.findByEmailAndStatus(userId, Status.ENABLED); 
     LOGGER.debug("Found user: {}", user); 

     if (user == null) { 
      throw new UsernameNotFoundException("No user found with username: " + userId); 
     } 

     ThingabledUserDetails principal = new ThingabledUserDetails(user.getEmail(),user.getPassword(),user.getAuthorities()); 
     principal.setFirstName(user.getFirstName()); 
     principal.setId(user.getId()); 
     principal.setLastName(user.getLastName()); 
     principal.setSocialSignInProvider(user.getSignInProvider()); 


     LOGGER.debug("Found user details: {}", principal); 

     return principal; 
    } 
} 

Вы можете скачать образец кода из:

https://github.com/ozgengunay/FBSpringSocialRESTAuth

+4

Можете ли вы добавить, как это реализовать с аннотациями? –