Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/379.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用Spring Security(非OAuth)的登录、密码和Facebook访问令牌的身份验证方法_Java_Spring_Facebook_Spring Security - Fatal编程技术网

Java 使用Spring Security(非OAuth)的登录、密码和Facebook访问令牌的身份验证方法

Java 使用Spring Security(非OAuth)的登录、密码和Facebook访问令牌的身份验证方法,java,spring,facebook,spring-security,Java,Spring,Facebook,Spring Security,我已经使用SpringSecurity实现了登录和密码的注册和身份验证。我是用电脑做的。但是现在我想使用Facebook Id提供注册和身份验证。我将在移动应用程序上获取Facebook用户的访问令牌,然后我将此访问令牌发送到my Spring服务器(因此OAuth不适用),使用Facebook API验证它,并获取Facebook用户Id。 请注意,我的数据库中已经有表用户,登录,密码,fb\u id列,所以注册有两种变体:要么用户有登录名和密码,要么用户只有Facebook帐户,我使用他的F

我已经使用SpringSecurity实现了登录和密码的注册和身份验证。我是用电脑做的。但是现在我想使用Facebook Id提供注册和身份验证。我将在移动应用程序上获取Facebook用户的访问令牌,然后我将此访问令牌发送到my Spring服务器(因此OAuth不适用),使用Facebook API验证它,并获取Facebook用户Id。 请注意,我的数据库中已经有表
用户
登录
密码
fb\u id
列,所以注册有两种变体:要么用户有登录名和密码,要么用户只有Facebook帐户,我使用他的Facebook id

最后,我只需要对这个用户进行身份验证并将JWT令牌返回给他

已经存在的代码

SecurityConfig:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(
        securedEnabled = true,
        jsr250Enabled = true,
        prePostEnabled = true
)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private CustomUserDetailsService customUserDetailsService;

    @Autowired
    private JwtAuthenticationEntryPoint unauthorizedHandler;

    @Bean
    public JwtAuthenticationFilter jwtAuthenticationFilter() {
        return new JwtAuthenticationFilter();
    }

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

    @Bean(BeanIds.AUTHENTICATION_MANAGER)
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .cors()
                .and()
                .csrf()
                .disable()
                .exceptionHandling()
                .authenticationEntryPoint(unauthorizedHandler)
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .authorizeRequests()
                .antMatchers("/",
                        "/favicon.ico",
                        "/**/*.png",
                        "/**/*.gif",
                        "/**/*.svg",
                        "/**/*.jpg",
                        "/**/*.html",
                        "/**/*.css",
                        "/**/*.js")
                .permitAll()
                .antMatchers("/api/auth/**")
                .permitAll()
                .antMatchers("/api/user/checkUsernameAvailability", "/api/user/checkEmailAvailability")
                .permitAll()
                .antMatchers(HttpMethod.GET, "/api/polls/**", "/api/users/**")
                .permitAll()
                .anyRequest()
                .authenticated();

        // Add our custom JWT security filter
        http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

    }
}
当前用户:

@Target({ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@AuthenticationPrincipal
public @interface CurrentUser {

}
CustomUserDetails服务:

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Autowired
    UserRepository userRepository;

    @Override
    @Transactional
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {
        // Let people login with either username or email
        User user = userRepository.findByPhone(username)
                .orElseThrow(() ->
                        new UsernameNotFoundException("User not found with username or email : " + username)
                );

        return user;
    }

    // This method is used by JWTAuthenticationFilter
    @Transactional
    public UserDetails loadUserById(Long id) {
        User user = userRepository.findById(id).orElseThrow(
                () -> new UsernameNotFoundException("User not found with id : " + id)
        );

        return user;
    }
}
JwtAuthenticationEntryPoint:

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {

    private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationEntryPoint.class);
    @Override
    public void commence(HttpServletRequest httpServletRequest,
                         HttpServletResponse httpServletResponse,
                         AuthenticationException e) throws IOException, ServletException {
        logger.error("Responding with unauthorized error. Message - {}", e.getMessage());
        httpServletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED,
                "Sorry, You're not authorized to access this resource.");
    }
}
JwtAuthenticationFilter:

public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Autowired
    private JwtTokenProvider tokenProvider;

    @Autowired
    private CustomUserDetailsService customUserDetailsService;

    private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationFilter.class);

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        try {
            String jwt = getJwtFromRequest(request);

            if (StringUtils.hasText(jwt) && tokenProvider.validateToken(jwt)) {
                Long userId = tokenProvider.getUserIdFromJWT(jwt);

                UserDetails userDetails = customUserDetailsService.loadUserById(userId);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, userDetails.getPassword(), userDetails.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        } catch (Exception ex) {
            logger.error("Could not set user authentication in security context", ex);
        }

        filterChain.doFilter(request, response);
    }

    private String getJwtFromRequest(HttpServletRequest request) {
        String bearerToken = request.getHeader("Authorization");
        if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7, bearerToken.length());
        }
        return null;
    }
}
JwtTokenProvider:

@Component
public class JwtTokenProvider {

    private static final Logger logger = LoggerFactory.getLogger(JwtTokenProvider.class);

    @Value("${app.jwtSecret}")
    private String jwtSecret;

    @Value("${app.jwtExpirationInMs}")
    private int jwtExpirationInMs;

    public String generateToken(Authentication authentication) {

        User user = (User) authentication.getPrincipal();

        Date now = new Date();
        Date expiryDate = new Date(now.getTime() + jwtExpirationInMs);

        return Jwts.builder()
                .setSubject(Long.toString(user.getId()))
                .setIssuedAt(new Date())
                .setExpiration(expiryDate)
                .signWith(SignatureAlgorithm.HS512, jwtSecret)
                .compact();
    }

    public Long getUserIdFromJWT(String token) {
        Claims claims = Jwts.parser()
                .setSigningKey(jwtSecret)
                .parseClaimsJws(token)
                .getBody();

        return Long.parseLong(claims.getSubject());
    }

    public boolean validateToken(String authToken) {
        try {
            Jwts.parser().setSigningKey(jwtSecret).parseClaimsJws(authToken);
            return true;
        } catch (SignatureException ex) {
            logger.error("Invalid JWT signature");
        } catch (MalformedJwtException ex) {
            logger.error("Invalid JWT token");
        } catch (ExpiredJwtException ex) {
            logger.error("Expired JWT token");
        } catch (UnsupportedJwtException ex) {
            logger.error("Unsupported JWT token");
        } catch (IllegalArgumentException ex) {
            logger.error("JWT claims string is empty.");
        }
        return false;
    }
}
授权控制器:

//...
 @PostMapping("/authorization")
    public AuthorizationResponse AuthauthenticateUser(@Valid @RequestBody LoginRequest loginRequest) {

        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        loginRequest.getPhone(),
                        loginRequest.getPassword()
                )
        );

        SecurityContextHolder.getContext().setAuthentication(authentication);

        String jwt = tokenProvider.generateToken(authentication);

        User user = (User)authentication.getPrincipal();

        AuthorizationResponse authorizationResponse = new AuthorizationResponse(user.getId(), jwt);

        return authorizationResponse;
    }
//...

那么,如何使用Spring Security实现这一目标呢?

您可以创建一个

  • 从请求正文中的客户端获取
    id\u令牌
  • 调用facebook的API来验证
    id\u令牌
    ,并获取用户的详细信息
  • 在数据库中保存或更新用户
  • 对用户进行身份验证
  • 创建并返回JWT
下面是一个示例代码-

@PostMapping("/signin/facebook")
public ResponseEntity<?> signInWithFacebook(@Valid @RequestBody FBLoginRequest loginRequest) {

    // Call facebook's API to validate id_token and get user's details

    // Register new user (Note: Also add code to check if a user already exists with the given facebookId )
    User user = new User(fbName, fbID,
            emailId, null);
    Role userRole = roleRepository.findByName(RoleName.ROLE_USER)
            .orElseThrow(() -> new AppException("User Role not set."));
    user.setRoles(Collections.singleton(userRole));

    User result = userRepository.save(user);

    // Authenticate User
    UserPrincipal userPrincipal = UserPrincipal.create(result);
    PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(userPrincipal, null, userPrincipal.getAuthorities());
    SecurityContextHolder.getContext().setAuthentication(authentication);

    // Generate and return token
    String jwt = tokenProvider.generateToken(authentication);
    return ResponseEntity.ok(new JwtAuthenticationResponse(jwt));
}
@PostMapping(“/sign/facebook”)
公共响应登录Facebook(@Valid@RequestBody FBLoginRequest loginRequest){
//调用facebook的API验证id_令牌并获取用户详细信息
//注册新用户(注意:还要添加代码以检查是否已存在具有给定facebookId的用户)
用户=新用户(fbName、fbID、,
emailId,空);
Role userRole=roleRepository.findByName(RoleName.Role\u USER)
.orelsetrow(()->newappexception(“未设置用户角色”);
user.setRoles(Collections.singleton(userRole));
用户结果=userRepository.save(用户);
//验证用户

UserPrincipal UserPrincipal=UserPrincipal.create(结果); PreAuthenticateAuthenticationToken authentication=新的PreAuthenticateAuthenticationToken(userPrincipal,null,userPrincipal.getAuthories()); SecurityContextHolder.getContext().setAuthentication(身份验证); //生成并返回令牌 字符串jwt=tokenProvider.generateToken(身份验证); 返回ResponseEntity.ok(新的JwtAuthenticationResponse(jwt)); }

我还没有添加调用facebook API的代码。但是实现起来应该很简单。

您可以创建一个

  • 从请求正文中的客户端获取
    id\u令牌
  • 调用facebook的API来验证
    id\u令牌
    ,并获取用户的详细信息
  • 在数据库中保存或更新用户
  • 对用户进行身份验证
  • 创建并返回JWT
下面是一个示例代码-

@PostMapping("/signin/facebook")
public ResponseEntity<?> signInWithFacebook(@Valid @RequestBody FBLoginRequest loginRequest) {

    // Call facebook's API to validate id_token and get user's details

    // Register new user (Note: Also add code to check if a user already exists with the given facebookId )
    User user = new User(fbName, fbID,
            emailId, null);
    Role userRole = roleRepository.findByName(RoleName.ROLE_USER)
            .orElseThrow(() -> new AppException("User Role not set."));
    user.setRoles(Collections.singleton(userRole));

    User result = userRepository.save(user);

    // Authenticate User
    UserPrincipal userPrincipal = UserPrincipal.create(result);
    PreAuthenticatedAuthenticationToken authentication = new PreAuthenticatedAuthenticationToken(userPrincipal, null, userPrincipal.getAuthorities());
    SecurityContextHolder.getContext().setAuthentication(authentication);

    // Generate and return token
    String jwt = tokenProvider.generateToken(authentication);
    return ResponseEntity.ok(new JwtAuthenticationResponse(jwt));
}
@PostMapping(“/sign/facebook”)
公共响应登录Facebook(@Valid@RequestBody FBLoginRequest loginRequest){
//调用facebook的API验证id_令牌并获取用户详细信息
//注册新用户(注意:还要添加代码以检查是否已存在具有给定facebookId的用户)
用户=新用户(fbName、fbID、,
emailId,空);
Role userRole=roleRepository.findByName(RoleName.Role\u USER)
.orelsetrow(()->newappexception(“未设置用户角色”);
user.setRoles(Collections.singleton(userRole));
用户结果=userRepository.save(用户);
//验证用户

UserPrincipal UserPrincipal=UserPrincipal.create(结果); PreAuthenticateAuthenticationToken authentication=新的PreAuthenticateAuthenticationToken(userPrincipal,null,userPrincipal.getAuthories()); SecurityContextHolder.getContext().setAuthentication(身份验证); //生成并返回令牌 字符串jwt=tokenProvider.generateToken(身份验证); 返回ResponseEntity.ok(新的JwtAuthenticationResponse(jwt)); }

我还没有添加调用facebook API的代码。但是实现起来应该很简单。

Pls@don prog您有facebook API请求的示例吗?你用过这个春季社交网站吗?您是否也创建了对Google API的请求?@user1089362 1。我不使用FacebookAPI来获取用户登录和访问\u令牌,我在Android上这样做,所以我使用FacebookAndroid SDK。在服务器端,我只检查访问令牌是否有效,这是您可以在web上找到的默认请求,但如果您愿意,我可以共享它。2.不,我不使用spring社交网站。3.No.UserPrincipal UserPrincipal=新的UserPrincipal(用户名);谢谢你broPls@don prog你有facebook API的请求样本吗?你用过这个春季社交网站吗?您是否也创建了对Google API的请求?@user1089362 1。我不使用FacebookAPI来获取用户登录和访问\u令牌,我在Android上这样做,所以我使用FacebookAndroid SDK。在服务器端,我只检查访问令牌是否有效,这是您可以在web上找到的默认请求,但如果您愿意,我可以共享它。2.不,我不使用spring社交网站。3.No.UserPrincipal UserPrincipal=新的UserPrincipal(用户名);谢谢你,兄弟