jwt身份验证导致与常规身份验证冲突我无法从登录页登录

t40tm48m  于 2021-07-23  发布在  Java
关注(0)|答案(1)|浏览(495)

谈到春安,我是个新手,特别是jwt和cors,所以如果我没有说清楚的话,我会提前道歉。
我们被要求制作一个模拟私人诊所网站的应用程序,病人可以在这个网站上预约医生并从药房购买产品。医生可以在数据库中介绍有关病人的信息。我们的项目也有一个restfulapi,可以通过移动应用程序(或 Postman )访问。api所做的是显示我们存储在数据库中的产品列表。
所有用户都可以通过使用Spring Security 的登录表单登录。另一方面,如果我们想检索api的信息,除了Spring Security 之外,还会使用cors和jwt。
当我设置了一个自定义的授权过滤器时,问题就来了,我们的老师给了我们这样做的机会(我已经注解了这一行)。我们可以使用postman完美地访问我们的api:我们使用admin用户登录并将授权令牌传递给我们的api路由,作为回报,我们得到产品列表。但当过滤器工作时,我们不能再使用我们网站的登录形式进行身份验证。整个过程如下:
应用程序从主页开始(localhost:8080/inicio).
在主页面中有一个“登录”按钮,当用户未通过身份验证时会出现该按钮。单击它将进入登录窗体。
在登录窗体中(localhost:8080/auth/login)我们填写了作为数据库用户登录所需的所有字段(在本例中,用户名:admin,密码:admin)。
我们提交了表格,它将我们带到负责认证过程的请愿书(localhost:8080/login/login-post).
在进程结束时,我们被重定向回主页面。当用户通过身份验证时,“login”按钮应显示为“logout”。但事实并非如此。我们无法导航到其他页面,而经过身份验证的用户应该对这两个页面都没有访问权限。
控制台不提供任何错误消息,它所做的只是将我带回主页面,而无需对用户进行身份验证。
这是我的spring安全配置类:

@Autowired
@Qualifier("userService")
private UserService userService;

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

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

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

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
    .csrf().disable()
    // .addFilterAfter(new JWTAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class)
    .authorizeRequests()
        .antMatchers("/", "/css/**",  "/img/**", "/js/**", "/vendor/**", "/inicio/**", "/pacientes/altaPaciente/**", "/pacientes/addPaciente/**", "/auth/**").permitAll()
        .antMatchers(HttpMethod.GET, "/authRest/**").permitAll()
        .antMatchers(HttpMethod.POST, "/authRest/**").permitAll()
        .anyRequest().authenticated()
        .and()
    .formLogin()
        .loginPage("/auth/login")
        .defaultSuccessUrl("/inicio/", true)
        .loginProcessingUrl("/auth/login-post")
        .permitAll()
        .and()
    .logout()
        .logoutUrl("/logout")
        .logoutSuccessUrl("/auth/login?logout")
        .permitAll();
}

以及我的jwt授权过滤器:

private final String HEADER = "Authorization";
private final String PREFIX = "Bearer ";
private final String SECRET = "mySecretKey";

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
        throws ServletException, IOException {
    try {
        if (checkJWTToken(request, response)) {
            Claims claims = validateToken(request);
            if (claims.get("authorities") != null) {
                setUpSpringAuthentication(claims);
            } else {
                SecurityContextHolder.clearContext();
            }
        } else {
            SecurityContextHolder.clearContext();
        }
        chain.doFilter(request, response);
    } catch(ExpiredJwtException | UnsupportedJwtException | MalformedJwtException e) {
        response.setStatus(HttpServletResponse.SC_FORBIDDEN);
        ((HttpServletResponse) response).sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
        return;
    }
}

private Claims validateToken(HttpServletRequest request) {
    String jwtToken = request.getHeader(HEADER).replace(PREFIX, "");
    return Jwts.parser().setSigningKey(SECRET.getBytes()).parseClaimsJws(jwtToken).getBody();
}

private void setUpSpringAuthentication(Claims claims) {
    @SuppressWarnings("unchecked")
    List<String> authorities = (List<String>) claims.get("authorities");

    UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(
            claims.getSubject(), 
            null, 
            authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList())
    );
    SecurityContextHolder.getContext().setAuthentication(auth);
}

private boolean checkJWTToken(HttpServletRequest request, HttpServletResponse res) {
    String authenticationHeader = request.getHeader(HEADER);
    if (authenticationHeader == null || !authenticationHeader.startsWith(PREFIX)) {
        return false;
    }
    return true;
}

编辑:根据请求,以下是我尝试使用web窗体以现有用户身份登录数据库时获得的日志:https://pastebin.com/7syx2mzf

uajslkp6

uajslkp61#

故障可能是(经过讨论)
在这里的某个地方:

if (checkJWTToken(request, response)) {
    Claims claims = validateToken(request);
    if (claims.get("authorities") != null) {
         setUpSpringAuthentication(claims);
    } else {
        SecurityContextHolder.clearContext();
    }
} else {
        SecurityContextHolder.clearContext();
}

检查是在 checkJWTToken 因为有一个 Authorization 标题,如果没有,则当前 SecurityContext 被清除,意味着它将删除任何主要出席。
这将删除先前登录的用户,这反过来又会删除最初登录时构造的主体。
因此,当您登录时,securitycontext由主体填充,然后在下一个过滤器中突然被删除。

相关问题