不同“接受”内容类型标头字段的不同身份验证

Posted

技术标签:

【中文标题】不同“接受”内容类型标头字段的不同身份验证【英文标题】:Different authentication for different "Accept" content type header field 【发布时间】:2017-07-31 22:22:08 【问题描述】:

我有一个简单的 Web 应用程序,它使用默认的 Spring Security 表单身份验证,一旦通过身份验证,用户就可以在 Thymeleaf 视图之间浏览并访问内容。

我能够为 REST 客户端应用程序提供 JSON,而不是 Web 视图,对于同一个端点,只需使用这样的 Spring 映射:

// response for web application, thymeleaf views
@RequestMapping("/fruits", produces = MediaType.TEXT_html_VALUE)
public String index(Model model) 
    model.addAttribute("fruits", fruits);
    return "fruitsView";


// response for REST client applications
@RequestMapping("/fruits", produces = MediaType.APPLICATION_JSON_VALUE)
public Fruits[] index() 
    return fruits;

问题是:当请求接受 JSON(Accept 标头字段)而不是首先接受 HTML 时,是否可以接受基本身份验证而不是使用登录 Web 表单进行响应?

我的安全配置:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter 

    @Override
    protected void configure(HttpSecurity http) throws Exception 
        // works well for web views: 
        http.authorizeRequests().antMatchers("/**").hasRole("USER").and().formLogin();

        // works well for REST clients:
        // http.authorizeRequests().antMatchers("/**").hasRole("USER").and().httpBasic();
    

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception 
        auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
    


是否可以同时配置 httpBasicformLogin 身份验证,以分别响应特定的 Accept 内容类型标头字段?

我了解到对于不同的 URL 模式可以有两种不同的身份验证:Spring REST security - Secure different URLs differently。但是对于同一个 URL 的两种不同的身份验证机制,其中请求由 Accept 内容头字段区分,怎么样?

【问题讨论】:

@dur 尝试过.formLogin().and().httpBasic()。通过浏览器访问时,我得到了预期的登录表单。但是在通过其他客户端访问时,将 application/json 作为 Accept 标头字段,如果未通过身份验证,我可以访问内容。 @dur 虽然您删除了您的评论,但您是对的:客户端工具是一个浏览器插件,因此它会发送浏览器 cookie。当没有发送 cookie 时,.formLogin().and().httpBasic() 在通过浏览器访问端点时使用表单登录身份验证和 http 基本身份验证非常有效,同时像 REST API 一样使用端点。问题解决了!谢谢! 【参考方案1】:

就代码的可扩展性和可维护性而言,这可能不是长期运行的好习惯。

但是,这可能会在一定程度上帮助您。但这指向具有两种登录类型的相同资源并提供相同的响应。在您的情况下,您希望为同一资源提供不同的响应。这就是它不是一个好的做法的原因。 Combining basic authentication and form login for the same REST Api

另一种建议是向您的请求添加可选属性,当您根据可选属性值在服务器端到达请求时,调用适当的方法并根据需要设置响应内容类型。

【讨论】:

感谢您花时间发布此内容。但是我想以两种不同的格式提供 same resource,这就是为什么我想通过同一个端点来执行此操作,这就是根据 HTTP 的 Accept 标头字段的目的RFC(参见“内容类型协商”)。这也是 Ruby on Rails 的方式,Spring 通过 RequestMapping 注释明确支持这一点。而且我不明白为什么对同一个端点启用两种不同形式的身份验证会是一种不好的做法。

以上是关于不同“接受”内容类型标头字段的不同身份验证的主要内容,如果未能解决你的问题,请参考以下文章

如何在同一个 Angular JS 应用程序中使用具有不同身份验证标头的不同 API

Alamofire 5中未设置授权标头?

是否根据身份验证凭据 RESTful 返回不同的输出?

带有标头和身份验证的 npm 请求

自定义身份验证

向具有不同域和基本身份验证的服务器发出 ajax POST 请求是不可能的吗?