Java 保护微服务spring云安全Oauth2

Java 保护微服务spring云安全Oauth2,java,spring,security,spring-boot,microservices,Java,Spring,Security,Spring Boot,Microservices,我正在使用SpringCloudSecurity和Oauth2来保护我的微服务。现在Pom如下所示: package com.oreilly.cloud; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.authenticat

我正在使用SpringCloudSecurity和Oauth2来保护我的微服务。现在Pom如下所示:

package com.oreilly.cloud;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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 AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authManager;

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

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory().withClient("webapp").secret("websecret").authorizedGrantTypes("password")
                .scopes("read,write,trust");
    }

}
{
    "access_token": "2d632e54-17c3-41f7-af3b-935ca3022d78",
    "token_type": "bearer",
    "expires_in": 43199,
    "scope": "read,write,trust"
}
http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0

<groupId>com.oreilly.cloud</groupId>
<artifactId>spring-microservices-oauth-server</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>spring-microservices-oauth-server</name>
<description>Demo project for Spring Boot</description>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.5.7.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>Dalston.SR3</spring-cloud.version>
</properties>

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

    <dependency>
        <groupId>org.hsqldb</groupId>
        <artifactId>hsqldb</artifactId>
        <scope>runtime</scope>
    </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-snapshots</id>
        <name>Spring Snapshots</name>
        <url>https://repo.spring.io/snapshot</url>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>
授权服务器配置如下:

package com.oreilly.cloud;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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 AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authManager;

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

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory().withClient("webapp").secret("websecret").authorizedGrantTypes("password")
                .scopes("read,write,trust");
    }

}
{
    "access_token": "2d632e54-17c3-41f7-af3b-935ca3022d78",
    "token_type": "bearer",
    "expires_in": 43199,
    "scope": "read,write,trust"
}
注意,身份验证管理器自动连接到授权配置中

在下面的类中,身份验证管理器配置为abean并返回,以便可以自动连接到上面的类:

package com.oreilly.cloud;

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;

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

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

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("user1").password("password1").roles("USER").and().withUser("admin")
                .password("password2").roles("ADMIN");
    }

}
现在application.properties如下所示:

package com.oreilly.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@EnableAuthorizationServer
@EnableResourceServer
@RestController
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SpringMicroservicesOauthServerApplication {

    @RequestMapping("/resource/endpoint")
    @PreAuthorize("hasRole('ADMIN')")
    public String endpoint(){
        return "This message is protected by the resource server.";
    }

    public static void main(String[] args) {
        SpringApplication.run(SpringMicroservicesOauthServerApplication.class, args);
    }
}
server.port=9090
<html>
    <head>
        <title>Login Page</title>
    </head>
    <body onload='document.f.username.focus();'>
        <h3>Login with Username and Password</h3>
        <form name='f' action='/login' method='POST'>
            <table>
                <tr>
                    <td>User:</td>
                    <td>
                        <input type='text' name='username' value=''>
                    </td>
                </tr>
                <tr>
                    <td>Password:</td>
                    <td>
                        <input type='password' name='password'/>
                    </td>
                </tr>
                <tr>
                    <td colspan='2'>
                        <input name="submit" type="submit" value="Login"/>
                    </td>
                </tr>
                <input name="_csrf" type="hidden" value="8dbc1c38-6f89-43c5-a8f8-797c920722a1" />
            </table>
        </form>
    </body>
</html>
现在,我运行Spring boot应用程序,如下所示:

package com.oreilly.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@EnableAuthorizationServer
@EnableResourceServer
@RestController
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SpringMicroservicesOauthServerApplication {

    @RequestMapping("/resource/endpoint")
    @PreAuthorize("hasRole('ADMIN')")
    public String endpoint(){
        return "This message is protected by the resource server.";
    }

    public static void main(String[] args) {
        SpringApplication.run(SpringMicroservicesOauthServerApplication.class, args);
    }
}
server.port=9090
<html>
    <head>
        <title>Login Page</title>
    </head>
    <body onload='document.f.username.focus();'>
        <h3>Login with Username and Password</h3>
        <form name='f' action='/login' method='POST'>
            <table>
                <tr>
                    <td>User:</td>
                    <td>
                        <input type='text' name='username' value=''>
                    </td>
                </tr>
                <tr>
                    <td>Password:</td>
                    <td>
                        <input type='password' name='password'/>
                    </td>
                </tr>
                <tr>
                    <td colspan='2'>
                        <input name="submit" type="submit" value="Login"/>
                    </td>
                </tr>
                <input name="_csrf" type="hidden" value="8dbc1c38-6f89-43c5-a8f8-797c920722a1" />
            </table>
        </form>
    </body>
</html>
mvn spring启动:运行

应用程序成功启动,并准备接受本地主机上端口9090上的请求

现在,我使用postman发送一个post请求来获取access_令牌。一个小背景是,这里使用的Aoauth2流是密码授予。因此,在上面的AuthorizationServerConfig类中,我定义了一个密码授予流,并注册了一个简单的web应用程序,其中包含客户端名称和密码。可以看到,客户端配置在记忆

从授权服务器获取访问令牌的post man请求如下:它的post请求,基本auth头具有 用户名为webapp,密码为websecret

此请求成功返回,带有访问令牌json,如下所示:

package com.oreilly.cloud;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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 AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authManager;

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

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory().withClient("webapp").secret("websecret").authorizedGrantTypes("password")
                .scopes("read,write,trust");
    }

}
{
    "access_token": "2d632e54-17c3-41f7-af3b-935ca3022d78",
    "token_type": "bearer",
    "expires_in": 43199,
    "scope": "read,write,trust"
}
现在,当我尝试使用上述访问令牌访问/resource/endpoint时,如下所示:

package com.oreilly.cloud;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
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 AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authManager;

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

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory().withClient("webapp").secret("websecret").authorizedGrantTypes("password")
                .scopes("read,write,trust");
    }

}
{
    "access_token": "2d632e54-17c3-41f7-af3b-935ca3022d78",
    "token_type": "bearer",
    "expires_in": 43199,
    "scope": "read,write,trust"
}

它不会返回从服务/资源/端点返回的文本,而是返回登录页面,如下所示:

package com.oreilly.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@EnableAuthorizationServer
@EnableResourceServer
@RestController
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SpringMicroservicesOauthServerApplication {

    @RequestMapping("/resource/endpoint")
    @PreAuthorize("hasRole('ADMIN')")
    public String endpoint(){
        return "This message is protected by the resource server.";
    }

    public static void main(String[] args) {
        SpringApplication.run(SpringMicroservicesOauthServerApplication.class, args);
    }
}
server.port=9090
<html>
    <head>
        <title>Login Page</title>
    </head>
    <body onload='document.f.username.focus();'>
        <h3>Login with Username and Password</h3>
        <form name='f' action='/login' method='POST'>
            <table>
                <tr>
                    <td>User:</td>
                    <td>
                        <input type='text' name='username' value=''>
                    </td>
                </tr>
                <tr>
                    <td>Password:</td>
                    <td>
                        <input type='password' name='password'/>
                    </td>
                </tr>
                <tr>
                    <td colspan='2'>
                        <input name="submit" type="submit" value="Login"/>
                    </td>
                </tr>
                <input name="_csrf" type="hidden" value="8dbc1c38-6f89-43c5-a8f8-797c920722a1" />
            </table>
        </form>
    </body>
</html>

登录页面
使用用户名和密码登录
用户:
密码:
谁能帮我解决我在这里所缺少的问题


注意我在同一个应用程序中配置了授权服务器和资源服务器。这是一个POC,所以我正在尝试Spring云安全,稍后我会将两者分开…但这是以后的事。

我通过查看Spring Boot的根调试日志来解决问题

如果您使用的是
yml

src/main/resources/application.yml
----------------------------------
logging:
  level:
    root: DEBUG
或者如果
属性

src/main/resources/application.properties
----------------------------------
logging.level.root=DEBUG
我意识到我没有用
GET
传递任何用户身份验证信息:

o.s.s.w.a.ExceptionTranslationFilter: Access is denied (user is anonymous); ...
因此,您可以做以下两件事中的一件:

1.通过url参数添加creds,例如。 或

2.通过基本认证添加信用,例如。 您是否也从safaribooksonline上的“使用Spring构建微服务”课程中获得了此信息?:)


我发现了老师没有这个问题的原因。他以前一定授权过用户名/密码——它似乎被缓存在某个地方,因为在您
获取
一次资源后,如果您仅使用
身份验证令牌
再次调用它,它就会工作。

您的问题到底是什么?在您的令牌中,expires\u的值在外观中it’很有趣..它映射到什么,当然不是滴答声,你能检查一下吗?@WilliamHampshire我的问题是我通过点击以下URL成功地获得访问令牌:使用基本身份验证头指定客户端用户名和密码,但是,如果我尝试访问受保护的资源(/resource/endpoint/)将access_token参数设置为上述访问令牌后,我将获得一个登录页面,而不是端点应该返回的文本响应