Opublikowane 12 marca 2017 5 minut
bookmark_border

DevLog #1

Ale to był pracowity tydzień! Podsumujmy go.

Workdone dostał logo

Własnoręcznie wykonane. Połączenie litery W i znaków wykonania (takie przedłużone w jedną stronę V). Do tego dodałem cień i powstało coś podobnego do loga TensorFlow a przynajmniej tak mi się skojarzyło.

Workdone logo

OAuth

Postanowiłem zrobić OAuth jako główny mechanizm autoryzacji. Implementacja OAuth to męczarnia. Konfiguracja Spring OAuth jest jeszcze gorsza. Jakieś wartości znikąd, tutorial nic nie tłumaczy, dokumentacja mówi o tym jak projekt działa, ale nie wspomina jak go używać. Masakra.

Jedyne źródło informacji to pytania na stackoverflow i jakieś dziwne przykłady, które podają różne konfiguracje. W końcu znalazłem działającą, ale dalej nie wiem skąd te wartości się wzięły. Oficjalna dokumentacja Google nic nie mówi, oprócz Użyj naszej biblioteki.

To był poziom łatwy, teraz jak zrobić aby dane użytkownika były przypisywane i dostępne później tzn. zrobić własne UserDetails tylko, że dla OAuth. Próbowałem za pomocą ClientDetails i etc. ale później wyczytałem z poradnika.

How to Add a Local User Database

Many applications need to hold data about their users locally, even if authentication is delegated to an external > provider. We don’t show the code here, but it is easy to do in two steps.

Choose a backend for your database, and set up some repositories (e.g. using Spring Data) for a custom User object that > suits your needs and can be populated, fully or partially, from the external authentication.

Provision a User object for each unique user that logs in by inspecting the repository in your /user endpoint. If there > is already a user with the identity of the current Principal, it can be updated, otherwise created.

Hint: add a field in the User object to link to a unique identifier in the external provider (not the user’s name, but > something that is unique to the account in the external provider).

Ręcznie? To nie pasuje do Springa, ale ok. Zrobiłem encje, repozytorium i zdałem sobie sprawę, że przy każdym użyciu użytkownika (czyli praktycznie zawsze) muszę pisać kod związany z wyciągnięciem użytkownika.

Ten problem rozwiązałem za pomocą implementacji HandlerMethodArgumentResolver.

@Component
public class UserMethodArgumentResolver implements HandlerMethodArgumentResolver {

    @Autowired
    private UserService userService;

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.getParameterType().equals(User.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter,
      ModelAndViewContainer mavContainer,
      NativeWebRequest webRequest,
      WebDataBinderFactory binderFactory) throws Exception {
        if (this.supportsParameter(parameter)) {
            if (webRequest.getUserPrincipal() instanceof OAuth2Authentication) {
                OAuth2Authentication auth2Authentication = (OAuth2Authentication) webRequest.getUserPrincipal();
                User user = userService.getUserForOAuthentication(auth2Authentication);
                return user;
            }
        }
        return WebArgumentResolver.UNRESOLVED;
    }
}

User to encja, UserService#getUserForOAuthentication zwraca użytkownika z bazy danych (może być nowo utworzony)

Teraz jedyne co muszę zrobić to w kontrolerze dodać do parametrów moją encje i gotowe! Wszystko fajnie? Mam nadzieje.

RESTpointy dla nawyków (habits)

CRUD --- create, read, update, delete. Podstawowe czynności, które wykonuje się na jakimś zbiorze danych.

Z tworzeniem i odczytem zazwyczaj nie ma żadnych problemów. Gorzej jest z aktualizowaniem, które można implementować zarówno za pomocą POST jak i PUT a samo repozytorium w Spring Data nie ma przydatnej do tego metody. To co ja ostatecznie stworzyłem jest niewydajne, ale działa.

@RequestMapping(value = "/{id}", method = RequestMethod.PUT)
public void editHabit(@PathVariable long id, @RequestBody Habit habit, User user) {
    Optional<Habit> habitOptional = habitRepository.findOneByIdAndOwner(id, user);
    if (habitOptional.isPresent()) {
        habit.setId(id);
        habit.setOwner(user);
        habitRepository.save(habit);
    }
}

Mimo tego, że kontroler powstał przed klasą User to nie było problemów z jego zabezpieczeniem, szczególnie po tym jak zrobiłem UserMethodArgumentResolver. Całość wygląda dość schludnie co mnie cieszy :)

EOF

Teraz czas na część list do zrobienia i dodawania punktów. Konieczne będą jakieś szablony i później frontend w Vue.js.

Ten tydzień: 60% OAuth, 40% dane użytkowników OAuth, 2% logo, 8% HabitXXX

Bartosz Wiśniewski

Full Stack do wszystkiego (serio). Z programowaniem mam do czynienia już od ponad 5 lat. Zajmowałem się tworzeniem aplikacji mobilnych i gier. Lubię Pythona, Go i JavaScript (ale tą dobrą stronę). Czasem buduję zabawki z Arduino.