Spring boot + oauth2:访问此资源需要完全身份验证

Posted

技术标签:

【中文标题】Spring boot + oauth2:访问此资源需要完全身份验证【英文标题】:Spring boot + oauth2 : Full authentication is required to access this resource 【发布时间】:2018-09-11 02:03:20 【问题描述】:

我正在尝试使用 spring boot、spring cloud security 和 spring cloud oauth2 实现身份验证服务器。

当我尝试从邮递员那里点击 http://localhost:8080/auth/oauth/token 时,我遇到了错误

“错误”:“未经授权”, "error_description": "访问此资源需要完全身份验证"

下面是我的 pom.xml

<?xml version="1.0" encoding="UTF-8"?> 
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> . 
<modelVersion>4.0.0</modelVersion>
<groupId>com.teckink.tp</groupId>
<artifactId>tp-auth-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>tp-auth-server</name>
<description>Demo project for Spring Boot</description>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.0.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
    <spring-cloud.version>Finchley.M9</spring-cloud.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-oauth2</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-security</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>$spring-cloud.version</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>
</project>

Starter(Main) 类:

package com.teckink.tp.authserver;

import java.util.HashMap;
import java.util.Map;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@RestController
@EnableResourceServer
@EnableAuthorizationServer
public class App 
    @RequestMapping(value =  "/user" , produces = "application/json")
    public Map<String, Object> user(OAuth2Authentication user) 
        Map<String, Object> userInfo = new HashMap<>();
        userInfo.put("user", user.getUserAuthentication().getPrincipal());
        userInfo.put("authorities", AuthorityUtils.authorityListToSet(user.getUserAuthentication().getAuthorities()));
        return userInfo;
    


    public static void main(String[] args) 
        SpringApplication.run(App.class, args);
    


OAuth2Config 类,它定义了客户端和它的秘密:

package com.teckink.tp.authserver.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;

@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter 

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception 
        clients.inMemory()
                .withClient("eagleeye")
                .secret("thisissecret")
                .authorizedGrantTypes("refresh_token", "password", "client_credentials")
                .scopes("webclient", "mobileclient");
    

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception 
      endpoints
        .authenticationManager(authenticationManager)
        .userDetailsService(userDetailsService);
    

WebSecurityConfigurer 类,它定义了内存中的用户、密码和角色:

package com.teckink.tp.authserver.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;

@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter 
        @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception 
        return super.authenticationManagerBean();
    

   @Override
    @Bean
    public UserDetailsService userDetailsServiceBean() throws Exception 
        return super.userDetailsServiceBean();
    


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception 
        auth
                .inMemoryAuthentication()
                .withUser("john.carnell").password("password1").roles("USER")
                .and()
                .withUser("william.woodward").password("password2").roles("USER", "ADMIN");
    

我正在从 POSTMAN 调用 Rest API,如下所示- 请求身份验证屏幕显示如下:

请求表单数据如下

【问题讨论】:

如果可能,请将可重现的示例项目上传到 GitHub。 @Prithvi - 你认为你可以帮助我吗 - ***.com/questions/53090739/… @KyleAnderson - 你能帮我吗 - ***.com/questions/53090739/… 【参考方案1】:

我注意到您的授权类型在您的帖子中列为“密码”而不是“密码” 您能否更正一下并再试一次?

【讨论】:

我把它改成了“密码”。仍然出现同样的错误【参考方案2】:

在您运行的示例应用程序中,您会遇到以下异常

java.lang.IllegalArgumentException: 没有映射 PasswordEncoder 对于 id "null"

在 spring-security-core:5.0 中,默认 PasswordEncoder 构建为 DelegatingPasswordEncoder。因此,当您将用户存储在内存中时,您是以纯文本形式提供密码,然后当您尝试从 DelegatingPasswordEncoder 检索编码器以验证它找不到的密码时。

更多详情见此链接Password Encoding

为了解决这个问题,对于生产实现,您应该激活BCryptPasswordEncoder 的实例

对于开发,您可以尝试以下更改,以便通过将noop 添加到密码值来覆盖密码编码。这将通过激活NoOpPasswordEncoder 而不是默认的DelegatingPasswordEncoder 来处理密码,并将您的密码视为纯文本。

OAuth2Config 类

clients.inMemory()
            .withClient("eagleeye")
            .secret("noopthisissecret")
            .authorizedGrantTypes("refresh_token", "password", "client_credentials")
            .scopes("webclient", "mobileclient");

WebSecurityConfigurer 类

 auth
                .inMemoryAuthentication()
                .withUser("john.carnell"). password("nooppassword1").roles("USER")
                .and()
                .withUser("william.woodward").password("nooppassword2").roles("USER", "ADMIN");

现在,当您从 Postman 尝试时,您将能够生成令牌

编辑

带有工作演示的 Github 项目 here

【讨论】:

我在控制台中没有收到任何错误。此外,我在密码和密码中添加了 noop,但仍然得到相同的响应错误:“访问此资源需要完全身份验证”。 已经上传了一个 github 项目的链接。查看与您使用的代码库有什么不同。 我打错了端点:localhost:8080/auth/oauth/token。将其更改为localhost:8080/oauth/token,然后我收到了您上面提到的错误。我通过前缀 noop 解决了这个错误 @Chids - 你能在这方面取悦我吗 - ***.com/questions/53090739/…【参考方案3】:

这里发生了同样的事情很奇怪。我通过使用 curl 命令解决了它。

curl -v -X POST  http://url:8080/api/oauth/token -u "yourclientid:yourclient_secret"   -d "grant_type=password"   -d "username=yourusername" -d "password=yourpassword"

或者 如果您想在邮递员中使用它,请转到 Authorization --> 选择类型 OAUTH2 --> Get Access Token enter image description here

【讨论】:

【参考方案4】:

我有同样的问题。 url错了,改成http://localhost:8080/oauth/token就OK了。 我从书中得到了这个样本,它给出了错误的 url。只需删除“/ auth”

【讨论】:

【参考方案5】:

在阅读 John Carnell 的 Spring Microservices in Action 时,以下更改为我解决了这个问题。

更改了以下属性

application.yml

server:
  contextPath: /auth

server:
  servlet:
    context-path: /auth

我还在每个秘密/密码中添加了 noop,现在它可以工作了!

WebSecurityConfigurer.java

@Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception 
        auth.inMemoryAuthentication()
                .withUser("john.carnell").password("nooppassword1").roles("USER")
                .and()
                .withUser("william.woodward").password("nooppassword2").roles("USER", "ADMIN");
    

OAuth2Config.java

@Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception 
        clients.inMemory()
                .withClient("eagleeye")
                .secret("noopthisissecret")
                .authorizedGrantTypes("refresh_token", "password", "client_credentials")
                .scopes("webclient", "mobileclient");
    

我正在使用 Spring Cloud Hoxton SR11

【讨论】:

以上是关于Spring boot + oauth2:访问此资源需要完全身份验证的主要内容,如果未能解决你的问题,请参考以下文章

带有 Spring Boot REST 应用程序的 OAuth2 - 无法使用令牌访问资源

带有加密 JWT 访问令牌的 Spring Boot OAuth2

无法使用 access_token 访问资源:spring boot Oauth2

Spring Boot 2 OAuth2 资源服务器不访问授权服务器进行访问令牌验证

Spring Boot:Oauth2:访问被拒绝(用户是匿名的);重定向到身份验证入口点

使用 spring-boot-starter-oauth2-client 检索 OAuth2 3-legged 身份验证的访问令牌