“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。

每个开发人员都希望能够更快,更有效地进行构建以支持规模。 使用Spring构建微服务架构可以为您的架构增加弹性和弹性,这将使其优雅地失效并无限扩展。

借助Spring Security及其OAuth 2.0支持,您还可以获得锁定API网关以及后端服务器所需的一切。 您可以将其设置为自动将访问令牌从一个应用程序传播到另一个应用程序,以确保在此过程中所有内容保持安全和加密。

本教程向您展示如何将Spring Security与OAuth 2.0和Okta结合使用来锁定您的微服务架构。

带有Spring Boot + Spring Cloud的微服务架构

本教程将向您展示如何为我之前写的教程“ 使用Spring Boot为Microbrews构建微服务体系结构”增加安全性。 带有Spring Boot和Spring Cloud的基本微服务架构如下图所示。

完成本教程后,您将获得Spring Security锁定的一切,Okta将为OAuth提供授权。 您的边缘服务(也称为API网关)将具有一个Feign客户端和一个处理正常故障转移的Hystrix,该客户端将随您的访问令牌一起传递。

首先,您需要克隆上述文章的已完成项目。

git clone https://github.com/oktadeveloper/spring-boot-microservices-example.git

在Okta中创建Web应用程序

如果您还没有,请创建一个永久免费的Okta Developer帐户 。 完成设置过程后,登录到您的帐户并导航至Applications > Add Application 。 单击Web然后单击下一步 。 在下一页上,输入以下值,然后单击完成

  • 应用名称: Spring OAuth
  • 基本URI: http://localhost:8081
  • 登录重定向URI: http://localhost:8081/login

记下clientId和client机密值,因为它们将用于配置Spring Boot应用程序。

您需要在ID令牌中添加一个roles声明,以便将Okta中的组转换为Spring Security机构。 在Okta开发人员控制台中,导航到API > 授权服务器 ,单击授权服务器选项卡并编辑默认选项卡。 点击索赔标签,然后添加索赔 。 将其命名为“角色”,并将其包含在ID令牌中。 将值类型设置为“ Groups”,并将过滤器设置为.*的正则表达式。

将Spring Security OAuth添加到边缘服务应用程序

边缘服务应用程序处理与beer-catalog-service的通信,因此它是开始集成OAuth的最佳位置。 在edge-service/pom.xml ,添加Spring Security的依赖关系,其OAuth支持和JWT支持。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency><groupId>org.springframework.security.oauth.boot</groupId><artifactId>spring-security-oauth2-autoconfigure</artifactId><version>2.0.1.RELEASE</version>
</dependency>

将以下Zuul路由添加到edge-service/src/main/resources/application.properties

zuul.routes.beer-catalog-service.path=/beers
zuul.routes.beer-catalog-service.url=http://localhost:8080zuul.routes.home.path=/home
zuul.routes.home.url=http://localhost:8080

打开edge-service/src/main/java/com/example/edgeservice/EdgeServiceApplication.java并添加@EnableOAuth2Sso以启用OAuth身份验证。

import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
...
@EnableOAuth2Sso
@SpringBootApplication
public class EdgeServiceApplication {

添加@EnableOAuth2Sso导致Spring Security查找大量属性。 将以下属性添加到edge-service/src/main/resources/application.properties

security.oauth2.client.client-id={yourClientId}
security.oauth2.client.client-secret={yourClientSecret}
security.oauth2.client.access-token-uri=https://{yourOktaDomain}.com/oauth2/default/v1/token
security.oauth2.client.user-authorization-uri=https://{yourOktaDomain}.com/oauth2/default/v1/authorize
security.oauth2.client.scope=openid profile email
security.oauth2.resource.user-info-uri=https://{yourOktaDomain}.com/oauth2/default/v1/userinfo
security.oauth2.resource.token-info-uri=https://{yourOktaDomain}.com/oauth2/default/v1/introspect
security.oauth2.resource.prefer-token-info=false

提示:如果在上面的代码片段中看到{yourOktaDomain} ,请登录到Okta帐户并刷新此页面。 它将用您的域替换该值。

ResourceServerConfig.java类添加到与EdgeServiceApplication相同的包中。

package com.example.edgeservice;import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {@Overridepublic void configure(HttpSecurity http) throws Exception {http.requestMatcher(new RequestHeaderRequestMatcher("Authorization")).authorizeRequests().antMatchers("/**").authenticated();}
}

至此,您已经完成了足以登录到Edge Service应用程序的配置,但是它无法与下游beer-catalog-service进行通信。

将Spring Security OAuth添加到Beer Catalog Service

beer-catalog-service/pom.xml ,添加与添加到Edge Service相同的依赖项,以及Thymeleaf的依赖项。

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency><groupId>org.springframework.security.oauth.boot</groupId><artifactId>spring-security-oauth2-autoconfigure</artifactId><version>2.0.1.RELEASE</version>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

将相同的属性添加到beer-catalog-service/src/main/resources/application.properties

security.oauth2.client.client-id={yourClientId}
security.oauth2.client.client-secret={yourClientSecret}
security.oauth2.client.access-token-uri=https://{yourOktaDomain}.com/oauth2/default/v1/token
security.oauth2.client.user-authorization-uri=https://{yourOktaDomain}.com/oauth2/default/v1/authorize
security.oauth2.client.scope=openid profile email
security.oauth2.resource.user-info-uri=https://{yourOktaDomain}.com/oauth2/default/v1/userinfo
security.oauth2.resource.token-info-uri=https://{yourOktaDomain}.com/oauth2/default/v1/introspect
security.oauth2.resource.prefer-token-info=false

提示:添加这些属性的替代方法是使用环境变量。 例如, SECURITY_OAUTH2_CLIENT_CLIENT_ID将是用于指定security.oauth2.client.client-id的环境变量。 使用环境变量将允许您从一个位置更改两个应用程序的设置。

beer-catalog-service/src/main/java/com/example/beercatalogservice/HomeController.java创建一个HomeController来呈现用户信息,以便您可以验证身份验证是否正常。

package com.example.beercatalogservice;import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;import java.security.Principal;
import java.util.Map;@Controller
public class HomeController {@GetMapping("/home")@SuppressWarnings("unchecked")public String howdy(Model model, Principal principal) {OAuth2Authentication authentication = (OAuth2Authentication) principal;Map<String, Object> user = (Map<String, Object>) authentication.getUserAuthentication().getDetails();model.addAttribute("user", user);return "home";}
}

beer-catalog-service/src/main/resources/templates/home.html创建一个home.html模板,并使用以下代码填充它。

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head><style>th {text-align: left;}td {white-space: nowrap;}td:first-child {font-family: "Courier", monospace;font-size: 0.9em;color: #343434;}</style>
</head>
<body>
<h1>Hello<span th:if="${user}" th:text="' ' + ${user.name}"> Joe</span>!</h1>
<div th:unless="${user}"><a th:href="@{/login}">Login</a>
</div>
<div th:if="${user}"><form id="logoutForm" th:action="@{/logout}" method="post"><input type="submit" value="Logout"/></form>
</div><h2>User Properties</h2>
<table><thead><tr><th>Name</th><th>Value</th></tr></thead><tbody><tr><td>sub</td><td th:text="${user.sub}"></td></tr><tr><td>name</td><td th:text="${user.name}"></td></tr><tr><td>given_name</td><td th:text="${user.given_name}"></td></tr><tr><td>family_name</td><td th:text="${user.family_name}"></td></tr><tr><td>preferred_username</td><td th:text="${user.preferred_username}"></td></tr><tr><td>email</td><td th:text="${user.email}"></td></tr><tr><td>roles</td><td th:text="${user.roles}"></td></tr></tbody>
</table>
</body>
</html>

在与HomeController相同的包中创建ResourceServerConfig.java类。 此类配置Spring Security,因此可以保护所有端点,但那些通过Authorization标头访问的端点除外。

package com.example.beercatalogservice;import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.web.util.matcher.RequestHeaderRequestMatcher;@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {@Overridepublic void configure(HttpSecurity http) throws Exception {http.requestMatcher(new RequestHeaderRequestMatcher("Authorization")).authorizeRequests().anyRequest().fullyAuthenticated();}
}

添加伪装的RequestInterceptor

用于与beer-catalog-service对话的@FeignClient Authorization标头。 为了使其UserFeignClientInterceptor ,请在与EdgeServiceApplication相同的目录中创建UserFeignClientInterceptor类。

package com.example.edgeservice;import feign.RequestInterceptor;
import feign.RequestTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.stereotype.Component;@Component
public class UserFeignClientInterceptor implements RequestInterceptor {private static final String AUTHORIZATION_HEADER = "Authorization";private static final String BEARER_TOKEN_TYPE = "Bearer";@Overridepublic void apply(RequestTemplate template) {SecurityContext securityContext = SecurityContextHolder.getContext();Authentication authentication = securityContext.getAuthentication();if (authentication != null && authentication.getDetails() instanceof OAuth2AuthenticationDetails) {OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();template.header(AUTHORIZATION_HEADER, String.format("%s %s", BEARER_TOKEN_TYPE, details.getTokenValue()));}}
}

注册为@Bean里面EdgeServiceApplication类。

import feign.RequestInterceptor;
...
public class EdgeServiceApplication {public static void main(String[] args) {SpringApplication.run(EdgeServiceApplication.class, args);}@Beanpublic RequestInterceptor getUserFeignClientInterceptor() {return new UserFeignClientInterceptor();}
}

为了使Hystrix了解安全上下文,您需要在edge-service/src/main/resources/application.properties 添加两个属性 :

feign.hystrix.enabled=true
hystrix.shareSecurityContext=true

验证安全通信

您可以通过启动所有Spring Boot应用程序来验证edge-servicebeer-catalog-service之间的通信。 首先,启动eureka-service

cd eureka-service
./mvnw spring-boot:run

在新的终端窗口中,启动beer-catalog-service

cd beer-catalog-service
./mvnw spring-boot:run

在另一个终端窗口中,启动edge-service

cd edge-service
./mvnw spring-boot:run

打开浏览器并导航到http://localhost:8081/good-beers 。 您应该被重定向到Okta域,并看到一个登录页面,提示您输入凭据。

输入您用来创建帐户的凭据,结果将看到一列优质啤酒。

如果您尝试导航到http://localhost:8081/home ,它将无法正常工作。 这是因为您需要将Spring Cloud Security添加到edge-service/pom.xml以中继Zuul代理的访问令牌。

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

没有这种依赖性,对/good-beers请求将可以工作(因为已配置Feign),但对/home请求将不会(因为Zuul需要Spring Cloud Security)。

重新启动边缘服务器应用程序,导航到http://localhost:8081/home ,您将在下一页看到您的用户详细信息。

在Spring Boot 2.0中保护下游服务

使用Spring Boot 1.5.x,将Actuator作为依赖项包括在内将触发Actuator Security并使其受到保护,从而保护了http://localhost:8080 。 在Spring Boot 2.x中,拥有WebSecurityConfigurerAdapter会导致执行器安全性降低。 在Beer Catalog Service应用程序中, ResourceServerConfig导致此行为。

要确保执行器端点安全并使其无法直接访问http://localhost:8080 ,请在beer-catalog-service/src/main/resources/application.properties添加要公开的端点:

management.endpoints.web.exposure.include=beans,mappings

然后创建一个SecurityConfig类(与ResourceServerConfig放在同一包中)。

package com.example.beercatalogservice;import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ADMIN").anyRequest().authenticated().and().httpBasic();}
}

进行这些更改后,重新启动beer-catalog-service并见证其保护。

注意:由于出现403错误,我无法使注销按钮正常工作。 我尝试在边缘服务应用程序csrf().requireCsrfProtectionMatcher(r -> false)ResourceServerConfig ,但这没有帮助。 我给Spring Security团队发送了一封电子邮件,询问他们是否有任何建议。

将Okta的登录小部件添加到Angular客户端

要使用Okta的登录小部件,您需要在Okta中修改您的应用以启用“ 隐式”授予类型。 登录到您的帐户,导航至“ 应用程序” >“ Spring OAuth” >“ 常规”选项卡,然后单击“ 编辑” 。 在“ 允许的授予类型”下启用“ 隐式(混合)” ,并选中其下方的两个复选框。 在登录重定向URI下添加http://localhost:4200 ,然后点击保存

为了使“登录小部件”向该应用程序发出请求,您还需要将客户端URL配置为可信来源。 单击API > 可信 来源 > 添加来源 。 输入http://localhost:4200作为原始URL,并选中其下方的两个复选框。

打开一个终端,导航到spring-boot-microservices-example/client ,然后使用npm安装客户端的依赖项。

cd client
npm install

安装Okta的登录小部件 ,使其可以与受保护的服务器进行通信。

npm install @okta/okta-signin-widget --save

将小部件CSS添加到client/src/styles.css

@import '~@okta/okta-signin-widget/dist/css/okta-sign-in.min.css';
@import '~@okta/okta-signin-widget/dist/css/okta-theme.css';

创建client/src/app/shared/okta/okta.service.ts并使用它来配置小部件以与您的Okta租户对话。 请确保在下面的代码中替换{yourOktaDomain}{clientId}

import { Injectable } from '@angular/core';
import * as OktaSignIn from '@okta/okta-signin-widget';@Injectable()
export class OktaService {widget;constructor() {this.widget = new OktaSignIn({baseUrl: 'https://{yourOktaDomain}.com',clientId: '{yourClientId}',authParams: {issuer: 'default',responseType: ['id_token', 'token'],scopes: ['openid', 'email', 'profile']}});}getWidget() {return this.widget;}getIdToken() {return this.widget.tokenManager.get('idToken');}getAccessToken() {return this.widget.tokenManager.get('accessToken');}
}

OktaService作为提供程序添加到client/src/app/app.module.ts

import { OktaService } from './shared/okta/okta.service';@NgModule({...providers: [OktaService],bootstrap: [AppComponent]
})
export class AppModule { }

修改client/src/app/shared/beer/beer.service.ts以读取访问令牌,并将其设置在Authorization标头中(如果存在)。

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { OktaService } from '../okta/okta.service';@Injectable()
export class BeerService {constructor(private http: HttpClient, private oktaService: OktaService) {}getAll(): Observable {let headers: HttpHeaders = new HttpHeaders();if (this.oktaService.getAccessToken()) {const accessToken = this.oktaService.getAccessToken();// headers is immutable, so re-assignheaders = headers.append('Authorization', accessToken.tokenType + ' ' + accessToken.accessToken);}return this.http.get('http://localhost:8081/good-beers', {headers: headers});}
}

修改app.component.html ,为小部件添加一个占位符,并显示一个部分,以显示用户名和注销按钮。

<mat-toolbar color="primary"><span>Welcome to {{title}}!</span>
</mat-toolbar><!-- Container to inject the Sign-In Widget -->
<div id="okta-signin-container"></div><div *ngIf="user"><h2>Welcome {{user?.name}}!</h2><button mat-raised-button (click)="logout()">Logout</button><app-beer-list></app-beer-list>
</div>

您会注意到HTML中的user变量。 要解决此问题,您需要更改client/src/app/app.component.ts以使其呈现登录小部件。 Angular的ChangeDetectorRef用于在事物发生更改并且渲染需要处理更新的变量时通知Angular。

import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
import { OktaService } from './shared/okta/okta.service';@Component({selector: 'app-root',templateUrl: './app.component.html',styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {title = 'app';user;signIn;constructor(private oktaService: OktaService, private changeDetectorRef: ChangeDetectorRef) {this.signIn = oktaService.getWidget();}showLogin() {this.signIn.renderEl({el: '#okta-signin-container'}, (response) => {if (response.status === 'SUCCESS') {response.forEach(token => {if (token.idToken) {this.signIn.tokenManager.add('idToken', token);this.user = this.getUser(token);}if (token.accessToken) {this.signIn.tokenManager.add('accessToken', token);}});this.signIn.remove();this.changeDetectorRef.detectChanges();}});}getUser(token) {return {name: token.claims.name,email: token.claims.email,username: token.claims.preferred_username};}ngOnInit() {this.signIn.session.get((response) => {if (response.status !== 'INACTIVE') {const token = this.oktaService.getIdToken();this.user = this.getUser(token);this.changeDetectorRef.detectChanges();} else {this.showLogin();}});}logout() {this.signIn.signOut(() => {this.user = undefined;this.changeDetectorRef.detectChanges();this.showLogin();});}
}

为了使BeerListComponent (在src/app/beer-list/beer-list.component.ts )来检测你已经登录,您需要使用添加在构造函数依赖ChangeDetectorRef并调用它的detectChanges()方法时您可以在每种beer上设置giphyUrl属性。

import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
import { BeerService, GiphyService } from '../shared';@Component({selector: 'app-beer-list',templateUrl: './beer-list.component.html',styleUrls: ['./beer-list.component.css'],providers: [BeerService, GiphyService]
})
export class BeerListComponent implements OnInit {beers: Array<any>;constructor(private beerService: BeerService, private giphyService: GiphyService,private changeDetectorRef: ChangeDetectorRef) { }ngOnInit() {this.beerService.getAll().subscribe(data => {this.beers = data;for (const beer of this.beers) {this.giphyService.get(beer.name).subscribe(url => {beer.giphyUrl = url;this.changeDetectorRef.detectChanges();});}},error => console.log(error))}
}

验证身份验证作品

通过打开终端,导航到client目录,然后运行npm start client 。 将浏览器打开到http://localhost:4200 ,您应该看到类似以下的登录表单。

如果要调整表单的样式,以免它与顶部工具栏不对,请在styles.css添加以下内容。

#okta-signin-container {margin-top: 25px;

}
您应该能够登录,看到欢迎消息以及注销按钮。 但是,由于控制台中出现以下错误,您不会看到啤酒清单。

Failed to load http://localhost:8081/good-beers: Response for preflight is invalid (redirect)

发生这种情况是因为Spring Security无法识别/good-beers端点上的@CrossOrigin批注。 要解决此问题,请向EdgeServiceApplication添加一个simpleCorsFilter

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.core.Ordered;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;import java.util.Collections;
...
public class EdgeServiceApplication {public static void main(String[] args) {SpringApplication.run(EdgeServiceApplication.class, args);}@Beanpublic RequestInterceptor getUserFeignClientInterceptor() {return new UserFeignClientInterceptor();}@Beanpublic FilterRegistrationBean simpleCorsFilter() {UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();CorsConfiguration config = new CorsConfiguration();config.setAllowCredentials(true);config.setAllowedOrigins(Collections.singletonList("*"));config.setAllowedMethods(Collections.singletonList("*"));config.setAllowedHeaders(Collections.singletonList("*"));source.registerCorsConfiguration("/**", config);FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source));bean.setOrder(Ordered.HIGHEST_PRECEDENCE);return bean;}
}

重新启动边缘服务应用程序,然后重试。 这次您应该取得巨大的成功!

注意:如果在生产中使用此配置,则应将允许的来源从*更改为客户的URL。

部署到Cloud Foundry

要使用Pivotal Web Services在Cloud Foundry上部署所有内容,您需要创建一个帐户,下载/安装Cloud Foundry CLI并登录(使用cf login -a api.run.pivotal.io )。

部署所有服务和Angular客户端要进行生产涉及很多步骤。 因此,我编写了一个deploy.sh脚本来自动执行所有操作。

注意:该脚本完成后,您必须将客户端的URL作为登录重定向URI添加到Okta应用中。 您还需要在API > Trusted Origins下将其添加为

提示:如果收到错误消息,说明您使用的内存过多,则可能必须升级Cloud Foundry订阅。

进一步了解Spring Boot,OAuth 2.0和微服务

本文向您展示了如何使用Spring Security,OAuth和Okta保护微服务架构。 借助Zuul,Feign和Spring Cloud Security,您可以确保后端服务安全地通信。

本教程的源代码位于GitHub的“ oauth”分支中 。

git clone https://github.com/oktadeveloper/spring-boot-microservices-example.git
git checkout oauth

本教程向您展示了如何在上一教程“ 使用Spring Boot为Microbrews构建微服务架构 ”中增加安全性。

如果您有兴趣了解Spring Security和OAuth 2.0的未来,请参阅我们的Spring Security团队的好朋友Joe Grandja提供的有关Spring Security的下一代OAuth 2.0支持 。

此外,JHipster对其OAuth支持使用相同的设置。 如果您对将Okta与JHipster结合使用感兴趣,建议您阅读以下博客文章:

  • 使用OAuth 2.0和JHipster开发微服务架构
  • 使用Ionic for JHipster创建具有OIDC身份验证的移动应用程序

在developer.okta.com/product上了解有关Okta及其API的更多信息。 如果您对本教程有疑问,请在下面发表评论或在Twitter @mraible上打我。

变更日志:

  • 2018年5月11日:更新为使用Spring Boot 2.0和Okta登录小部件2.0.8。 请参阅spring-boot-microservices-example#17中的示例应用程序更改; 可以在okta.github.io#2049中查看对此帖子的更改。

“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证。

使用Spring Security和OAuth 2.0保护Spring微服务体系结构最初于2018年2月13日发布在Okta开发者博客上。

翻译自: https://www.javacodegeeks.com/2018/05/secure-a-spring-microservices-architecture-with-spring-security-and-oauth-2-0.html

使用Spring Security和OAuth 2.0保护Spring微服务架构相关推荐

  1. oauth2_带有Spring Security的OAuth 2.0快速指南

    oauth2 "我喜欢编写身份验证和授权代码." 〜从来没有Java开发人员. 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验 ...

  2. 带有Spring Security的OAuth 2.0快速指南

    "我喜欢编写身份验证和授权代码." 〜从来没有Java开发人员. 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多因素身份验证. 在构建W ...

  3. Re:从0开始的微服务架构--(二)快速快速体验微服务架构?--转

    原文地址:https://mp.weixin.qq.com/s/QO1QDQWnjHZp8EvGDrxZvw 这是专题的第二篇文章,看看如何搭建一个简单模式的微服务架构. 记得好久之前看到一个大牛说过 ...

  4. Re:从0开始的微服务架构:(二)如何快速体验微服务架构?

    记得好久之前看到一个大牛说过:如果单体架构都搞不好,就别搞微服务架构.乍一看,这句很有道理,后来发现这句话是不太对的,因为微服务架构的目的就是为了降低系统的复杂性,所以 微服务架构应该比单体架构更简单 ...

  5. 从0开始的微服务架构:(一)重识微服务架构

    2019独角兽企业重金招聘Python工程师标准>>> 导语 虽然已经红了很久,但是"微服务架构"正变得越来越重要,也将继续火下去. 各个公司与技术人员都在分享微 ...

  6. Re:从0开始的微服务架构:(一)重识微服务架构--转

    原文地址:http://www.infoq.com/cn/articles/micro-service-architecture-from-zero?utm_source=infoq&utm_ ...

  7. Re:从0开始的微服务架构:(一)重识微服务架构

    导语 虽然已经红了很久,但是"微服务架构"正变得越来越重要,也将继续火下去. 各个公司与技术人员都在分享微服务架构的相关知识与实践经验,但我们发现,目前网上的这些相关文章中,要么上 ...

  8. Spring Boot与Docker(一):微服务架构和容器化概述

    本文讲的是Spring Boot与Docker(一):微服务架构和容器化概述,[编者的话]本篇是<使用Spring Boot和Docker构建微服务架构>系列四部曲的第一篇,本篇将会对我们 ...

  9. Re:从 0 开始的微服务架构--(三)微服务架构 API 的开发与治理--转

    原文来自:聊聊架构公众号 前面的文章中有说到微服务的通信方式,Martin Folwer 先生在他对微服务的定义中也提到"每个服务运行在其独立的进程中,服务与服务间采用 轻量级的通信机制 互 ...

最新文章

  1. 从换脸到换姿势,AI 在图像处理的道路上越走越魔幻
  2. 干货|2018物流机器人行业报告发布!不容错过
  3. 模型与logit_基础方法 | 如何用Logit回归模型写论文?
  4. 在xml文件中使用typeAliases标签报错The content of element type “configuration“ must match “(properties?,setting
  5. dataframe转化为array_【Python专栏】12 种高效 Numpy 和 Pandas 函数为你加速分析
  6. 项目添加universal link跳转,升级微信SDK
  7. SpringMVC:400 Bad Request
  8. javascript学习之利用方向键控制div模块的移动
  9. Mysql报错(必解决):The user specified as a definer (‘mysql.infoschema‘@‘localhost‘) does not exist
  10. Reeder Web版
  11. html内容转换中文乱码怎么办,HTML中文乱码怎么解决?
  12. 高级语言程序设计(C语言)----第三章(上) 数据类型、运算符和表达式
  13. 谷粒学院day08——课程章节与小节的实现
  14. linux who命令详解,Linux who命令实例详解
  15. B站 x《男人装》首次破圈合作,有趣的灵魂遇见了艺术
  16. jadx 反编译apk
  17. linux可以挂载nas盘吗_linux可以挂载nas盘吗
  18. 微信QQ域名防封防红防屏蔽系统源码
  19. java输出希腊字母_java 命令行窗口输出希腊字母表
  20. 基于GC - MS的代谢组学研究揭示:SD大鼠和Wistar大鼠之间存在系统的代谢差异及乙醇灌胃反应差异

热门文章

  1. 【模拟】【递归】电子表格(jzoj 2127)
  2. Hadoop的FileSystem.copyToLocalFile两个参数 空指针异常
  3. 微服务为什么选Spring Cloud
  4. 分布式作业 Elastic-Job 快速上手指南
  5. java中,如何实现输入一个正整数,并将这个数字反转输出,比如输入123,输出321
  6. SpringBoot整合Shiro实现登录认证和授权CHCache
  7. SpringMVC(笔记)
  8. Android使用MPAndroidChat
  9. mybatis-plus 错误java.lang.NoClassDefFoundError: org/apache/velocity/context/Context
  10. servlet设置cookie实验