Spring Boot 2.0.3 Oauth2 安全性:即使在标头中使用访问令牌时也会出现 401 错误 [英] Spring Boot 2.0.3 Oauth2 Security: Getting 401 error even when using access token in header

查看:61
本文介绍了Spring Boot 2.0.3 Oauth2 安全性:即使在标头中使用访问令牌时也会出现 401 错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在创建一个 spring boot 2.0 应用程序并尝试启用 oauth2 安全性.到目前为止,我在同一个应用程序中拥有身份验证服务器和资源服务器.我的客户端和用户详细信息以及生成的令牌保存在数据库 (mysql) 中,并且数据库架构与 spring 文档提供的相同.当我点击/oauth/token/"端点并使用 Postman 在标头中提供 clientId 和 clientSecret 并在正文中提供用户凭据时,我成功获取了访问令牌.

I'm creating a spring boot 2.0 application and trying to enable oauth2 security. I have Auth server and Resource server in the same application as of now. My client and user details as well as token generated are persisted in databases (mysql) and database schema is the same as provided by spring documentation. When I hit the '/oauth/token/' endpoint providing clientId and clientSecret in header and user's credentials in body using Postman, I'm getting access token successfully.

{
"access_token": "bef2d974-2e7d-4bf0-849d-d80e8021dc50",
"token_type": "bearer",
"refresh_token": "32ed6252-e7ee-442c-b6f9-d83b0511fcff",
"expires_in": 6345,
"scope": "read write trust"
}

但是当我尝试使用此访问令牌访问我的 rest api 时,我收到 401 Unauthorized 错误:

But when I try to hit my rest api using this access token, I'm getting 401 Unauthorized error:

{
"timestamp": "2018-08-13T11:17:19.813+0000",
"status": 401,
"error": "Unauthorized",
"message": "Unauthorized",
"path": "/myapp/api/unsecure"
}

我正在使用的其他 API 如下:

The rest APIs I'm hitting are as follows:

http://localhost:8080/myapp/api/unsecure

http://localhost:8080/myapp/api/secure

myapp 是我的应用程序的上下文路径.

myapp is the context path of my application.

对于安全"api,我在请求标头中提供了访问令牌,如 Spring 文档中所述:

For 'secure' api, I have provided access token in request header as described in Spring documentation:

Authorization: Bearer bef2d974-2e7d-4bf0-849d-d80e8021dc50

对于不安全的 api,我尝试过使用和不使用 Authentication 标头.在所有情况下,我都收到了两个 api 的相同错误.

Whereas for unsecure api, I have tried with and without Authentication header. In all cases I'm getting same error for both apis.

此外,当我尝试打印当前经过身份验证的用户时,它会被打印为匿名用户.

Also when I try to print currently authenticated user, its getting printed as anonymousUser.

我想要的如下:

1) 我希望只有在请求标头中提供访问令牌时才能访问我的安全 API.

1) I want my secure api to be accessible only when access token is provided in request header.

2) 我希望未经授权的用户可以访问我的不安全 API.

2) I want my unsecure api to be accessible by unauthorised user.

3) 我应该在访问安全 url 时使用 SecurityContextHolder 获取当前经过身份验证的用户.

3) I should get currently authenticated user using SecurityContextHolder when accessing secure url.

我的 WebSecurityConfigurerAdapter 如下:

@Configuration
@EnableWebSecurity(debug=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
private DataSource dataSource;

@Autowired
UserDetailsService userDetailsService;

@Autowired
private ClientDetailsService clientDetailsService;

@Bean
public PasswordEncoder userPasswordEncoder() {
    return new BCryptPasswordEncoder(8);
}

@Bean
public TokenStore tokenStore() {
    return new JdbcTokenStore(dataSource);
}

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

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

@Bean
@Autowired
public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore 
tokenStore){
    TokenStoreUserApprovalHandler handler = new 
    TokenStoreUserApprovalHandler();
    handler.setTokenStore(tokenStore);
    handler.setRequestFactory(new 
    DefaultOAuth2RequestFactory(clientDetailsService));
    handler.setClientDetailsService(clientDetailsService);
    return handler;
}

@Bean
@Autowired
public ApprovalStore approvalStore(TokenStore tokenStore) throws 
Exception {
    TokenApprovalStore store = new TokenApprovalStore();
    store.setTokenStore(tokenStore);
    return store;
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
    .csrf().disable()
    .cors().disable()
    .anonymous().disable()
    .authorizeRequests()
    .antMatchers("/index.html", "/**.js", "/**.css", "/").permitAll()
    .anyRequest().authenticated()
    .and()
    .httpBasic();
}

这里使用 antMatchers,我允许使用 Angular 6 应用程序的静态页面,因为我打算在我的真实应用程序中使用这些页面.不,以下行不适用于允许 angular 应用程序的静态页面:

Here using antMatchers I have permitted static pages of Angular 6 application, as I'm planning to use those in my real app. And no, the following line does not work to allow static pages of angular application:

.requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()

我的 AuthorizationServerConfigurerAdapter 如下:

@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends 
AuthorizationServerConfigurerAdapter {

@Autowired
private DataSource dataSource;

@Autowired
UserDetailsService userDetailsService;

@Autowired
PasswordEncoder passwordEncoder;

@Autowired
TokenStore tokenStore;

@Autowired
private UserApprovalHandler userApprovalHandler;

@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;


@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
    oauthServer
    .tokenKeyAccess("permitAll()")
    .checkTokenAccess("isAuthenticated()")
    .passwordEncoder(passwordEncoder);
}

@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.jdbc(dataSource);
}

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    endpoints
    .tokenStore(tokenStore)
    .userApprovalHandler(userApprovalHandler)
    .authenticationManager(authenticationManager)
    .userDetailsService(userDetailsService);
}
}

我的ResourceServerConfigurerAdapter如下:

@Configuration
@EnableResourceServer
public abstract class ResourceServerConfig extends ResourceServerConfigurerAdapter {

private static final String RESOURCE_ID = "resource-server-rest-api";

@Autowired
TokenStore tokenStore;

@Override
public void configure(ResourceServerSecurityConfigurer resources) {
    resources
    .resourceId(RESOURCE_ID)
    .tokenStore(tokenStore);
}

@Override
public void configure(HttpSecurity http) throws Exception {

    http
    .csrf().disable()
    .cors().disable()
    .anonymous().disable()
    .requestMatchers()
    .antMatchers("/api/**").and()
    .authorizeRequests()
    .antMatchers("/api/secure").authenticated()
    .antMatchers("/api/unsecure").permitAll();
}
}

但是当我在 SecurityConfig 中启用匿名访问并将我的不安全 url 声明为 permitAll 时,我就可以访问该 url.

But when I enable anonymous access in SecurityConfig and declare my unsecure url as permitAll, then I'm able to access that url.

.antMatchers("/api/unsecure", "/index.html", "/**.js", "/**.css", "/").permitAll()

我的控制器类如下:

@RestController
@RequestMapping("/api")
public class DemoController {

@GetMapping("/secure")
public void sayHelloFriend() {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    System.out.println("Current User: "+authentication.getName());
    System.out.println("Hello Friend");
}

@GetMapping("/unsecure")
public void sayHelloStranger() {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    System.out.println("Current User: "+authentication.getName());
    System.out.println("Hello Stranger");
}
}

如果需要更多信息,请告诉我.任何帮助将不胜感激.但请记住,根据我的发现,它的 Spring Boot 2.0 而不是 1.5,因为两者都有一些关键差异.

Let me know if any more information is needed. Any help will be appreciated. But please keep in mind that its Spring Boot 2.0 not 1.5 as both have some critical differences as per my findings.

推荐答案

尝试添加

@Order(SecurityProperties.BASIC_AUTH_ORDER)

对于安全配置?所以链会首先检查你的资源服务器的配置.

for the securityConfig? so the chain will check your Resource server's config first.

并且不确定您的类型是否错误,请从资源服务器中删除摘要.

And not sure if that your type error, remove the abstract from the resource server.

这篇关于Spring Boot 2.0.3 Oauth2 安全性:即使在标头中使用访问令牌时也会出现 401 错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆