繁体   English   中英

JWT authentication with spring and angular with null header

[英]JWT authentication with spring and angular with null header

我正在尝试使用 spring 引导和 angular 进行 JWT 令牌身份验证。 创建登录不记名令牌后,但在JWTAuthorizationFilter中创建后,我得到 null header 并因此返回匿名用户。 请告诉我为什么我得到 null header。

安全配置.java

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;
    
    @Autowired
    private CustomUserDetailService customUserDetailService;
     
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception { 
         http.
         cors().configurationSource(request -> new CorsConfiguration().applyPermitDefaultValues())
        .and().csrf().disable()
                .authorizeRequests()                                                                
                .antMatchers("/**").permitAll()                  
                .antMatchers("/manage/**").hasRole("ADMIN")                                      
                .antMatchers("/").hasRole("USER")
                .and()
                .exceptionHandling()
                .accessDeniedPage("/access-denied")
                .and()
                .addFilter(new JWTAuthenticationFilter(authenticationManager()))
                .addFilter(new JWTAuthorizationFilter(authenticationManager(), customUserDetailService));
    }
     
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(customUserDetailService).passwordEncoder(new 
   
        BCryptPasswordEncoder());
    }
}

JWTAuthenticationFilter.java

    public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private AuthenticationManager authenticationManager;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            UserDetail user = new ObjectMapper().readValue(request.getInputStream(), UserDetail.class);
            return this.authenticationManager
                    .authenticate(new UsernamePasswordAuthenticationToken(user.getEmail(), user.getPassword()));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request,
                                            HttpServletResponse response,
                                            FilterChain chain,
                                            Authentication authResult) throws IOException, ServletException {
        String username = ((org.springframework.security.core.userdetails.User) authResult.getPrincipal()).getUsername();
        String token = Jwts
                .builder()
                .setSubject(username)
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .compact();
        String bearerToken = TOKEN_PREFIX + token;
        System.out.println(bearerToken);
        response.getWriter().write(bearerToken);
        response.addHeader(HEADER_STRING, bearerToken);
       }
    }

JWTAuthorizationFilter.java

    public class JWTAuthorizationFilter extends BasicAuthenticationFilter {
    private final CustomUserDetailService customUserDetailService;

    public JWTAuthorizationFilter(AuthenticationManager authenticationManager, CustomUserDetailService customUserDetailService) {
        super(authenticationManager);
        this.customUserDetailService = customUserDetailService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws IOException, ServletException {
        String header = request.getHeader(HEADER_STRING);
        if (header == null || !header.startsWith(TOKEN_PREFIX)) {
            chain.doFilter(request, response);
            return;
        }
        UsernamePasswordAuthenticationToken authenticationToken = getAuthenticationToken(request);
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        chain.doFilter(request, response);
    }

    private UsernamePasswordAuthenticationToken getAuthenticationToken(HttpServletRequest request) {
        String token = request.getHeader(HEADER_STRING);
        if (token == null) return null;
        String username = Jwts.parser().setSigningKey(SECRET)
                .parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
                .getBody()
                .getSubject();
        UserDetails userDetails = customUserDetailService.loadUserByUsername(username);
        return username != null ?
                new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()) 
      : null;
      }
      }

CustomUserDetailService.java

@Component
public class CustomUserDetailService implements UserDetailsService {

    private List<GrantedAuthority> role;

    @Autowired
    private UserDAO userDAO;

    /*
     * @Autowired public CustomUserDetailService(UserRepository userRepository) {
     * this.userRepository = userRepository; }
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        User user = Optional.ofNullable(userDAO.getByEmail(username))
                .orElseThrow(() -> new UsernameNotFoundException("User not found"));
        List<GrantedAuthority> authorityListAdmin = AuthorityUtils.createAuthorityList("ROLE_ADMIN");
        List<GrantedAuthority> authorityListUser = AuthorityUtils.createAuthorityList("ROLE_USER");
        if (user.getRole() == "admin") {
            role = authorityListAdmin;
        } else {
            role = authorityListUser;
        }
        return new org.springframework.security.core.userdetails.User(user.getEmail(), user.getPassword(), role);
    }
}

用户信息.java

private String email;
private String role;
private String password;

Controller

@RequestMapping(value = "/login")
public ModelAndView login(
        @RequestParam(name = "error", required = false) String error,
        @RequestParam(name = "logout", required = false) String logout,
        HttpServletRequest request,
        HttpServletResponse response) {

    ModelAndView mv = new ModelAndView("login");
    HttpSession session= request.getSession(false);
    Authentication auth = SecurityContextHolder.getContext()
        .getAuthentication();
      
    System.out.println("auth ===" + auth);
    System.out.println("logout ===" + logout);
 
    return mv; 
}

这是控制台上的 output:

 

 Bearer eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJidW50QGdtYWlsLmNvbSIsImV4cCI6MTU5NjExMjcwM30.fBFMDO--8Q_56LT_qbioiT6p3BOxk3L9OrPVTw5EGbf7oJ0ky7W7PuahIYcdjYSL6-OsHY6qq8tPEetlJO7nEg

auth ===org.springframework.security.authentication.AnonymousAuthenticationToken@823df96a: Principal: anonymousUser; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@b364: RemoteIpAddress: 0:0:0:0:0:0:0:1; SessionId: null; Granted Authorities: ROLE_ANONYMOUS

请告诉我我在这里缺少什么。

您的JWTAuthenticationFilter扩展UsernamePasswordAuthenticationFilter覆盖successfulAuthentication方法,默认情况下调用此行:

SecurityContextHolder.getContext().setAuthentication(authResult);

您的实现没有此行,因此在处理此过滤器后,您在 Spring 上下文中仍然没有Authentication 调用的下一个过滤器是您的JWTAuthorizationFilter ,它尝试从与前一个过滤器相同的request object 中读取 header。 JWTAuthenticationFilter设置此 header 以response object 不在request object 中。 因此,基本上您最终没有进行身份验证,因为if (header == null ||.header.startsWith(TOKEN_PREFIX))在登录流程后始终为真。

首先,在 HttpServletResponse header 上生成和设置的身份验证过滤器令牌中,而不是在请求对象的 header 上。 然后授权过滤器检查请求 header 以获得令牌,因此可能发生了null的问题。

通常身份验证和授权不会像这样链接,但不知道您尝试实现的实际用例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM