有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java如何在身份验证后调用控制器方法

我在控制器中有以下方法:

@PostMapping(path = "/api/users/login", consumes = APPLICATION_JSON_VALUE, produces = APPLICATION_JSON_VALUE)
@ResponseStatus(OK)
public TokenResponse login(@RequestBody LoginUserRequest loginUserRequest, Principal principal) {
    return new TokenResponse().setAccessToken("token");
}

这里是一个WebSecurityConfigurerAdapter

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
            .formLogin().disable()
            .authorizeRequests().antMatchers("/api/users/login").permitAll()
            .and()
            .authorizeRequests().antMatchers("/api/**").authenticated()
            .and()
            .addFilterBefore(mobileAuthenticationFilter(objectMapper), UsernamePasswordAuthenticationFilter.class)
            .addFilter(new JwtAuthorizationFilter(authenticationManager(), super.userDetailsService()));
}

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

    auth.jdbcAuthentication().dataSource(dataSource)
            .usersByUsernameQuery("SELECT login, pass, active FROM users WHERE login = ?")
            .authoritiesByUsernameQuery("SELECT login, 'ROLE_USER' FROM users WHERE login = ?")
            .passwordEncoder(new CustomPasswordEncoder());
}

@Bean
public MobileAuthenticationFilter mobileAuthenticationFilter(ObjectMapper objectMapper) throws Exception {
    MobileAuthenticationFilter mobileAuthenticationFilter = new MobileAuthenticationFilter(objectMapper);
    mobileAuthenticationFilter.setAuthenticationManager(authenticationManager());
    mobileAuthenticationFilter.setAuthenticationSuccessHandler((request, response, authentication) -> {
        System.out.println(request);
    });
    return mobileAuthenticationFilter;
}

MobileAuthenticationFilter正在读取json正文并准备UsernamePasswordAuthenticationToken

public class MobileAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
    private final ObjectMapper objectMapper;

    public MobileAuthenticationFilter(ObjectMapper objectMapper) {
        super(new AntPathRequestMatcher("/api/users/login"));
        this.objectMapper = objectMapper;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            BufferedReader reader = request.getReader();
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
            reader.mark(0);
            LoginUserRequest loginUserRequest = objectMapper.readValue(sb.toString(), LoginUserRequest.class);
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(loginUserRequest.getLogin(), loginUserRequest.getPassword());
            return getAuthenticationManager().authenticate(token);
        } catch (IOException e) {
            throw new IllegalArgumentException(e.getMessage());
        }
    }
}

这段代码很好用,但这是我想归档的一件事

成功身份验证后,响应将立即由:

mobileAuthenticationFilter.setAuthenticationSuccessHandler((request, response, authentication) -> {
    System.out.println(request);
});

当然,在这里我可以向客户机(在主体中)返回一些东西,但是否有可能调用控制器方法public TokenResponse login,并且该方法应该返回一个响应(基于http代码的方法契约和注释)

在那个场景中,控制器中的这个方法永远不会被调用


共 (1) 个答案

  1. # 1 楼答案

    如果有formLogin,你可以使用successHandler(...)重定向到你想要的页面。请注意,您还必须考虑错误响应

    由于您已明确禁用了formLogin,我建议用户调用/api/users/login,而不是在attemptAuthentication(...)中对其进行身份验证

    因此,正如您所说..addFilterBefore(mobileAuthenticationFilter(objectMapper), UsernamePasswordAuthenticationFilter.class),您的过滤器将被触发以填充结果响应

    您的控制器将如下所示:

    public TokenResponse login(@Valid @RequestBody LoginUserRequest loginUserRequest) {
       //may be check for AuthenticationException
       try{
           ...
           generateToken(loginUserRequest.getUserName(), loginUserRequest.getPassword());
           ...
       } catch(AuthenticationException ex){
            // status = HttpStatus.UNAUTHORIZED;
       } catch (Exception ex) {
            //status = HttpStatus.INTERNAL_SERVER_ERROR;
       }
    }
    
    public String generateToken(String name, String password) {
            try {
                // check for null or empty
                
                UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(name, password, new ArrayList<>());
                Authentication authentication = authenticationManager.authenticate(upToken);
                
                // do whatever operations you need and return token 
            } catch (Exception ex) {
                throw ex;
            }
        }