【问题标题】:Spring security with @RestController - JSONish CustomAuthenticationProvider response使用 @RestController 的 Spring 安全性 - JSONish CustomAuthenticationProvider 响应
【发布时间】:2016-08-31 23:50:52
【问题描述】:

我对 Spring 还是很陌生,尤其是 Spring Security。本应用为 Restful 应用。

下面是来自@RestController的sn-p:

@RequestMapping(value = "/new", method = RequestMethod.POST)
    @PreRegistration("new")
    @ResponseBody
    public ResponseEntity<Void> newUser(@RequestBody @Valid TempUser user, UriComponentsBuilder ucBuilder) {

        registerService.addUser(user);

        HttpHeaders headers = new HttpHeaders();
        headers.setLocation(ucBuilder.path("/register/{userName}").buildAndExpand(user.getUserName()).toUri());
        return new ResponseEntity<Void>(headers, HttpStatus.CREATED);
    }

以下是来自CustomAuthenticationProvider的sn-p:

@Override
public Authentication authenticate(final Authentication authentication) throws AuthenticationException  {
    final String name = authentication.getName();
    final String password = authentication.getCredentials().toString();
    if (name.equals("admin") && password.equals("system")) {
        final List<GrantedAuthority> grantedAuths = new ArrayList<>();
        grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
        final UserDetails principal = new User(name, password, grantedAuths);
        final Authentication auth = new UsernamePasswordAuthenticationToken(principal, password, grantedAuths);
        return auth;
    } 
    else {
        throw new BadCredentialsException("NOT_AUTHORIZED");
    }
}

安全配置:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .anyRequest().authenticated()
            .and()
        .requestCache()
            .requestCache(new NullRequestCache())
            .and()
        .httpBasic()
            .and()
        .csrf().disable();
}

我尝试实现的是当CustomAuthenticationProvider 抛出异常(例如“错误凭据”或“需要完整身份验证...”时,我想自定义响应并以 JSON 格式返回响应正文。

我所做的是创建一个新异常并使用 AOP 调用它。但这似乎不起作用。我也尝试使用@ControllerAdvice,但它似乎不能正常工作,因为CustomAuthenticationProvider 在控制器之外(我猜)。

【问题讨论】:

    标签: spring spring-mvc authentication spring-security


    【解决方案1】:

    对此有更好的方法。您应该在 spring 安全配置和类中添加authenticationEntryPoint,它实现了AuthenticationEntryPoint 接口。像这样的:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().authenticated()
                .and()
            .requestCache()
                .requestCache(new NullRequestCache())
                .and()
            .httpBasic()
            // --> begin change: new lines added
                .and()
            .exceptionHandling().authenticationEntryPoint(new AuthExceptionEntryPoint())
            // <-- end change
                .and()
            .csrf().disable();
    

    }

    AuthExceptionEntryPoint 类,用于生成 JSON Jackson ObjectMapper

    public class AuthExceptionEntryPoint implements AuthenticationEntryPoint {
        @Override
        public void commence(HttpServletRequest request, HttpServletResponse response, 
                             AuthenticationException authException) 
                             throws IOException, ServletException {
    
            List<String> errors = new ArrayList<>();
            errors.add("Unauthorized");
            response.setContentType("application/json");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            try {
                ObjectMapper mapper = new ObjectMapper();
                mapper.writeValue(response.getOutputStream(), errors);
            } catch (Exception e) {
                throw new ServletException();
            }
        }
    }
    

    您可以在Spring docs上阅读有关 Spring Security 配置的更多信息

    【讨论】:

    • 感谢您的回答。但仍然存在相同的错误。使用有效凭据登录也会触发“AuthExceptionEntryPoint”。有什么提示我可以在哪里检查以进行调试?
    • 打开org.springframework.security 包的日志记录并将其附加到问题(当有效凭据不起作用时)
    • 我试图打印 authException : org.springframework.security.authentication.InsufficientAuthenticationException: 访问此资源需要完全身份验证
    • 尝试在.authorizeRequests() 是安全配置之后添加.antMatchers("/login").permitAll()(必须是登录映射的URL)
    • 我在添加 .antMatchers 后尝试访问 /login 并且它可以工作。 - 这是否意味着仅适用于登录表单而不适用于 httpBasic?
    【解决方案2】:

    您可以创建一个可以捕获AccessDeniedException 的自定义过滤器,并通过以下方式在配置文件中的ExceptionTranslationFilter 之后添加过滤器:

    http.addFilterAfter(customExceptionTranslationFilter, ExceptionTranslationFilter.class)
    

    捕捉到异常后,您可以使用响应对象以您想要的方式响应。

    然后,您还可以添加处理您可能希望在控制器中抛出的其他异常的功能。

    【讨论】:

    • 好像当我添加“addFilterAfter”时,请求将永久无效。即使登录是正确的。有什么想法吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-11
    • 2019-12-06
    • 1970-01-01
    • 2017-07-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多