访问被拒绝,在使用Spring Boot安全性JWT更改密码后。

huangapple go评论59阅读模式
英文:

Access denied after changed password with spring boot security JWT

问题

以下是要翻译的内容:

我正在为我的应用程序实现Spring Boot安全性。登录功能正常工作,但是不知何故,每当我测试更改密码功能时,它总是失败。我在数据库中检查了密码已经更新为新的HashString,但我无法使用旧密码和新密码登录。请帮忙!

这是更改密码的API:

@PutMapping("/reset-password")
public ResponseEntity resetPassword(@RequestBody String password) {
    // 提取用户名
    String username = SecurityContextHolder.getContext().getAuthentication()
            .getPrincipal().toString();
    ApplicationUser applicationUser = applicationUserRepo.findByUsername(username);
    if (applicationUser == null) {
        return ResponseEntity.badRequest().body("找不到用户名");
    }

    applicationUser.setPassword(bCryptPasswordEncoder.encode(password));

    applicationUserRepo.save(applicationUser);
    Logs log = new Logs(TimeConverter.getVietnamCurrentTime(), "PASSWORD", "User", applicationUser.getUsername(), applicationUser.getUsername());
    logsRepo.save(log);
    return ResponseEntity.ok().body("密码已成功更改!");
}

这是我的WebSecurityConfigurerAdapter的实现:

@EnableWebSecurity
@Configuration
public class WebSecurity extends WebSecurityConfigurerAdapter {
    private UserDetailsServiceImpl userDetailsService;
    @Autowired
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    public WebSecurity(UserDetailsServiceImpl userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) {
        this.userDetailsService = userDetailsService;
        this.bCryptPasswordEncoder = bCryptPasswordEncoder;
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable().authorizeRequests()
                .antMatchers(HttpMethod.POST, LOGIN_URL).permitAll()
                //.antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
                .addFilter(new JWTAuthenticationFilter(authenticationManager()))
                .addFilter(new JWTAuthorizationFilter(authenticationManager()))
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

    }

    @Bean
    public AuthenticationFailureHandler authenticationFailureHandler() {
        return new CustomAuthenticationFailureHandler();
    }

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


    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        final CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOrigins(ImmutableList.of("*"));
        configuration.setAllowedMethods(ImmutableList.of("HEAD",
                "GET", "POST", "PUT", "DELETE", "PATCH"));
        configuration.setAllowCredentials(true);
        configuration.setAllowedHeaders(ImmutableList.of("Authorization", "Cache-Control", "Content-Type"));
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

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

AuthenticationFilter:

public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private AuthenticationManager authenticationManager;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        this.authenticationManager = authenticationManager;
    }
    @Override
    public Authentication attemptAuthentication(HttpServletRequest req,
                                                HttpServletResponse res) throws AuthenticationException {
        try {
            ApplicationUser creds = new ObjectMapper()
                    .readValue(req.getInputStream(), ApplicationUser.class);
            return authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            creds.getUsername(),
                            creds.getPassword(),
                            new ArrayList<>())
            );
        } catch (IOException e) {
            System.out.println("出错了");
            throw new RuntimeException(e);
        }
    }

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

        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.addHeader("Access-Control-Expose-Headers","*");

    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed)
            throws IOException, ServletException {
        response.getWriter().write("出错了");
        super.unsuccessfulAuthentication(request, response, failed);
    }
}
英文:

I'm implementing spring boot security for my application. The login function works fine, but somehow whenever I test the change-password function, it's always failed, I checked in the database the password has been updated with the new HashString, but I cannot login with both old-password and new-password. Please help !

Here is the change-password API

@PutMapping(&quot;/reset-password&quot;)
public  ResponseEntity resetPassword(@RequestBody String password){
//extract user name
String username =  SecurityContextHolder.getContext().getAuthentication()
.getPrincipal().toString();
ApplicationUser applicationUser = applicationUserRepo.findByUsername(username);
if(applicationUser == null ){
return ResponseEntity.badRequest().body(&quot;Could not find UserName&quot;);
}
applicationUser.setPassword(bCryptPasswordEncoder.encode(password));
applicationUserRepo.save(applicationUser);
Logs log = new Logs (TimeConverter.getVietnamCurrentTime(),&quot;PASSWORD&quot;, &quot;User&quot;, applicationUser.getUsername(), applicationUser.getUsername() );
logsRepo.save(log);
return ResponseEntity.ok().body(&quot;Password changed successfully!&quot;);
}

Here is my implementation of WebSecurityConfigurerAdapter

@EnableWebSecurity
@Configuration
public class WebSecurity extends WebSecurityConfigurerAdapter {
private UserDetailsServiceImpl userDetailsService;
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
public WebSecurity(UserDetailsServiceImpl userDetailsService, BCryptPasswordEncoder bCryptPasswordEncoder) {
this.userDetailsService = userDetailsService;
this.bCryptPasswordEncoder = bCryptPasswordEncoder;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable().authorizeRequests()
.antMatchers(HttpMethod.POST, LOGIN_URL).permitAll()
//.antMatchers(&quot;/login&quot;).permitAll()
.anyRequest().authenticated()
.and()
.addFilter(new JWTAuthenticationFilter(authenticationManager()))
.addFilter(new JWTAuthorizationFilter(authenticationManager()))
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
@Bean
public AuthenticationFailureHandler authenticationFailureHandler() {
return new CustomAuthenticationFailureHandler();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder);
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
final CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(ImmutableList.of(&quot;*&quot;));
configuration.setAllowedMethods(ImmutableList.of(&quot;HEAD&quot;,
&quot;GET&quot;, &quot;POST&quot;, &quot;PUT&quot;, &quot;DELETE&quot;, &quot;PATCH&quot;));
configuration.setAllowCredentials(true);
configuration.setAllowedHeaders(ImmutableList.of(&quot;Authorization&quot;, &quot;Cache-Control&quot;, &quot;Content-Type&quot;));
final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration(&quot;/**&quot;, configuration);
return source;
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}

AuthenticationFilter

public class JWTAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private AuthenticationManager authenticationManager;
public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
}
@Override
public Authentication attemptAuthentication(HttpServletRequest req,
HttpServletResponse res) throws AuthenticationException {
try {
ApplicationUser creds = new ObjectMapper()
.readValue(req.getInputStream(), ApplicationUser.class);
return authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(
creds.getUsername(),
creds.getPassword(),
new ArrayList&lt;&gt;())
);
} catch (IOException e) {
System.out.println(&quot;fucked&quot;);
throw new RuntimeException(e);
}
}
@Override
protected void successfulAuthentication(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain,
Authentication auth)  {
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.addHeader(&quot;Access-Control-Expose-Headers&quot;,&quot;*&quot;);
}
@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed)
throws IOException, ServletException {
response.getWriter().write(&quot;blalfaf&quot;);
super.unsuccessfulAuthentication(request, response, failed);
}
}

答案1

得分: 1

尝试使用:

addFilterBefore(new JWTAuthenticationFilter(authenticationManager(), UsernamePasswordAuthenticationFilter.class)

而不是仅仅使用:

addFilter(....

在你的 WebSecurity.configure(..... 中。这将会把你自己的过滤器放在原始的 UsernamePasswordAuthenticationFilter 之前。也许你的过滤器是排在最后的,导致登录在它之前失败。

英文:

Try using:

    addFilterBefore(new JWTAuthenticationFilter(authenticationManager(), UsernamePasswordAuthenticationFilter.class)

instead of just

    addFilter(....

in your WebSecurity.configure(.....

This will put your own filter before the original UsernamePasswordAuthenticationFilter. Maybe your filter is last in line and the login is failing before.

huangapple
  • 本文由 发表于 2020年10月6日 19:12:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/64224625.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定