Как связать Social Login, как Google и Facebook, с токеном JWT в Spring Boot? - PullRequest
0 голосов
/ 23 апреля 2019

Я использую WebSecurityConfigurerAdapter вот так

@EnableWebSecurity
public class WebSecurity extends WebSecurityConfigurerAdapter {
    private UserDetailServiceImpl userDetailsService;
    private BCryptPasswordEncoder bCryptPasswordEncoder;
    private ApplicationUserRepository applicationUserRepository;

    public WebSecurity(UserDetailServiceImpl userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder, ApplicationUserRepository applicationUserRepository) {
        this.userDetailsService = userDetailsService;
        this.bCryptPasswordEncoder = bCryptPasswordEncoder;
        this.applicationUserRepository = applicationUserRepository;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling().authenticationEntryPoint(new AuthExceptionEntryPoint());
        http.cors().and().csrf().disable().authorizeRequests()
                .antMatchers(""/configuration/ui",
                        "/configuration/security" 
                        "/webjars/**", "/users/social-sign-up", "client/**","/actuator/**",
                        "/instances","/assets/**","/home","/tables","/resources/**","/static/**",
                        "/css/**","/js/**","/scss/**","/templates").permitAll()
                .antMatchers(HttpMethod.POST, SecurityConstants.SIGN_UP_VERIFY_URL).permitAll()
                .antMatchers(HttpMethod.POST, SecurityConstants.SIGN_UP_URL).permitAll().anyRequest().authenticated()
                .and().addFilter(new JWTAuthenticationFilter(authenticationManager(), applicationUserRepository))
                .addFilter(new JWTAuthorizationFilter(authenticationManager()))
                // this disables session creation on Spring Security

                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
        return source;
    }



}

Тогда у меня есть BasicAuthenticationFilter вот так

public class JWTAuthorizationFilter extends BasicAuthenticationFilter {

    public JWTAuthorizationFilter(AuthenticationManager authManager) {
        super(authManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        String header = req.getHeader(SecurityConstants.HEADER_STRING);

        if (header == null || !header.startsWith(SecurityConstants.TOKEN_PREFIX)) {
            chain.doFilter(req, res);
            return;
        }

        UsernamePasswordAuthenticationToken authentication = getAuthentication(req);

        SecurityContextHolder.getContext().setAuthentication(authentication);
        chain.doFilter(req, res);
    }

    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        String token = request.getHeader(SecurityConstants.HEADER_STRING);
        if (token != null) {
            // parse the token.
            String user = JWT.require(Algorithm.HMAC512(SecurityConstants.SECRET.getBytes())).build()
                    .verify(token.replace(SecurityConstants.TOKEN_PREFIX, "")).getSubject();

            if (user != null) {
                return new UsernamePasswordAuthenticationToken(user, null, new ArrayList<>());
            }
            return null;
        }
        return null;
    }
}

А потом у меня UsernamePasswordAuthenticationFilter вот так

public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private AuthenticationManager authenticationManager;
    private ApplicationUserRepository applicationUserRepository;
    public JWTAuthenticationFilter(AuthenticationManager authenticationManager,ApplicationUserRepository applicationUserRepository) {
        this.authenticationManager = authenticationManager;
        this.applicationUserRepository = applicationUserRepository;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res)
            throws AuthenticationException {
        try {

            ApplicationUser creds = new ObjectMapper().readValue(req.getInputStream(), ApplicationUser.class);
            System.err.println("Creds " + creds.getUsername() + ", " + creds.getPassword());

            return authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(creds.getUsername(),
                    creds.getPassword(), new ArrayList<>()));
        } catch (Exception e) {
            // e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,
            Authentication auth) throws IOException, ServletException {

        String token = JWT.create().withSubject(((User) auth.getPrincipal()).getUsername())
                .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRATION_TIME)).sign(HMAC512(SECRET.getBytes()));
        res.addHeader(HEADER_STRING, TOKEN_PREFIX + token);
        res.setStatus(HttpServletResponse.SC_OK);
        String userName = ((User)auth.getPrincipal()).getUsername();
        ApplicationUser au= applicationUserRepository.findByUsername(userName);
        String json = new ObjectMapper().writeValueAsString(au);
        res.getWriter().write(json);
        res.getWriter().flush();
        res.getWriter().close();



    }
}

Это нормально работает для обычной регистрации и входа в систему.Я авторизую пользователей и отправляю токен JWT в заголовок.Вот так

Authorization →Bearer awgaagarbrqe342tewrbwrewh.23tebvre34h4wbseb43qberqbqv.23gwrwvw4hw5445jmet76e-gqgqggq323t9003qgnibqp2389bvqp9q83bv9

ApplicationUser.class вот так

@Entity
public class ApplicationUser {
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid",strategy = "uuid2")
    private String id;
    @Column(name = "username")
    private String username;
    @Column(name = "password")
    private String password;
    @Column(name = "name")
    private String name;
    @Column(name = "email")
    private String email;
    @Column(name = "verification_code")
    private String verificationCode;
    @Column(name = "verified")
    private boolean verified=false;
    @Column(name = "balance")
    private double balance;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    String accessToken,kun,userSocialId;

    public String getAccessToken() {
        return accessToken;
    }

    public void setAccessToken(String accessToken) {
        this.accessToken = accessToken;
    }

    public String getKun() {
        return kun;
    }

    public void setKun(String kun) {
        this.kun = kun;
    }

    public String getUserSocialId() {
        return userSocialId;
    }

    public void setUserSocialId(String userSocialId) {
        this.userSocialId = userSocialId;
    }

    public String getId() {
        return id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getVerificationCode() {
        return verificationCode;
    }

    public void setVerificationCode(String verificationCode) {
        this.verificationCode = verificationCode;
    }



    public boolean isVerified() {
        return verified;
    }

    public void setVerified(boolean verified) {
        this.verified = verified;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

}

Но теперь мне нужно добавить социальный логин / регистрацию (Google и Facebook).Поэтому я создал метод в контроллере, подобный этому

@PostMapping("/social-sign-up")
    public ResponseEntity<ApplicationUser> signUp(String username, String name, String email, String userId, String userToken, String from) {

        ApplicationUser user = new ApplicationUser();
        if (from.equalsIgnoreCase("google")) {

            try {

                String googleTokenVerifyUrl = "https://oauth2.googleapis.com/tokeninfo?id_token="+userToken;
                RestTemplate restTemplate = new RestTemplate();
                GoogleVerifier googleVerifier = restTemplate.getForObject(googleTokenVerifyUrl,GoogleVerifier.class);
                if(googleVerifier.getEmailVerified().equalsIgnoreCase("false")&& !googleVerifier.getEmail().equalsIgnoreCase(email)){
                    return new ResponseEntity<>(user, new HttpHeaders(), HttpStatus.UNAUTHORIZED);

                }else{
                    user.setUsername(username);
                    user.setEmail(email);
                    user.setName(name);
                    user.setAccessToken(userToken);
                    user.setKun(from);
                    user.setUserSocialId(userId);
                    user.setBalance(Constants.initialBalance);
                    user.setVerified(true);
                    applicationUserRepository.save(user);
                }
            } catch (Exception e) {
                return new ResponseEntity<>(user, new HttpHeaders(), HttpStatus.UNAUTHORIZED);
            }


        } else {
            String getAppToken = Constants.FACEBOOK_APP_TOKEN_URL;
            RestTemplate restTemplate = new RestTemplate();
            FbTokenApi fbTokenApi = restTemplate.getForObject(getAppToken, FbTokenApi.class);
            String verifyingToken = "https://graph.facebook.com/debug_token?input_token=" + userToken + "&access_token=" + fbTokenApi.getAccessToken();
            FbTokenResponse fbTokenResponse = restTemplate.getForObject(verifyingToken, FbTokenResponse.class);
            if (fbTokenResponse.getData().isIsValid()) {
                //verified

                user.setUsername(username);
                user.setEmail(email);
                user.setName(name);
                user.setAccessToken(userToken);
                user.setKun(from);
                user.setUserSocialId(userId);
                user.setBalance(Constants.initialBalance);
                user.setVerified(true);
                applicationUserRepository.save(user);
            }else{
                return new ResponseEntity<>(user, new HttpHeaders(), HttpStatus.UNAUTHORIZED);
            }

        }

        return new ResponseEntity<>(user, new HttpHeaders(), HttpStatus.CREATED);
    }

Теперь я не совсем уверен, как отправить токен JWT в заголовке после социальной регистрации.Нужно ли мне полностью повторить процесс аутентификации и авторизации или это можно сделать, внеся некоторые изменения в эти коды.Любая помощь будет оценена.Спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...