谈到春安,我是个新手,特别是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
1条答案
按热度按时间uajslkp61#
故障可能是(经过讨论)
在这里的某个地方:
检查是在
checkJWTToken
因为有一个Authorization
标题,如果没有,则当前SecurityContext
被清除,意味着它将删除任何主要出席。这将删除先前登录的用户,这反过来又会删除最初登录时构造的主体。
因此,当您登录时,securitycontext由主体填充,然后在下一个过滤器中突然被删除。