From Zero to OAuth2 in Spring cloud

Today I am presenting hours of research about a (apparently) simple question: “How can I maintain security in my microservices architecture?”. The task is to enable a simple but mighty possibility to secure spring cloud services down to method invocation level, having a central point of where users and authorities can be assigned.

To achieve this as efficient as possible, OAuth2 is the solution.

In this article we are going to implement an authorization server, holding user authorities and client information, and a resource service with protected resources, using Spring OAuth2 and JSON Web Tokens (JWT). I will demonstrate, how the resource server can host a RESTful resource, having different security levels, which is defined in example authorities “FOO_READ” and “FOO_WRITE”.

The implementation can be downloaded and tested on my GitHub Repository.

Since I am really new to Spring and Spring Cloud including all its concepts, this was a quite hard way of research. This might sound weird, but at the beginning I couldn’t get, why they are all talking about Facebook/GitHub authentication in context of how to secure internal data. It was leading to an obvious question:

Why OAuth2?

Despite microservices are a rather new topic in modern software development, OAuth2 is a well known authorization technology. It is widely used, to give web applications developers access to users data at Google/Facebook/GitHub directly from the foreign services in a secure way. But before I explain more details, I will first refocus, what we initially want to achieve: cloud security.

So, what could we do generally, to gain/forbid access to resources inside the cloud to users? Let’s take some dumb stupid ways.

We could secure the edge server, assuming all the access to our data will go through it. This is nearly the same as you would do with classic Spring MVC Security. But there is no way of method security and - what is the most important - your data is insecure from inside attacks.

Other way: We share the user credential database for all services and authenticate the user on each service before access. Sounds somehow really stupid, but it’s actually a working approach with all the spring security features available.

Better way: The user authenticates on a authorization service, which maps the user session to a token. Any further API call to the resource services must provide this token. The services are able to recognize the provided token and ask the authorization service, which authorities this token grants, and who is the owner of this token.

This sounds like a good solution, doesn’t it? But what’s about secure token transmission? How to distinguish between access from a user and access from another service (and this is also something we could need!)

So this leads us to: OAuth2. Accessing sensible data from Facebook/Google is pretty much the same as accessing protected data from the own backend. Since they are working for some years on this solution, we can apply this battleground approved solution for our needs.

How OAuth2 works

Implementation of OAuth2 in Spring is quite easy, when you understand the concept of OAuth2. Let us describe the scenario “AwesomeApp wants Peters profile data from facebook for Peters profile in AwesomeApp”

OAuth2 defines 4 roles in this process:

  • Resource Owner - this is Peter
  • Resource Server - this is Facebook
  • Authorization Server - this is also Facebook, because it knows Peter and its Session and data
  • Client - the AwesomeApp

When Peter tries to sign up with Facebook Login, Awesome App redirects him to FBs authorization server. This knows about Peter, whether he is logged in, and even if Peter already was here before and already approved it’s data. When Peter visits this page for the first time, he has to allow AwesomeApp to access his email and profile data. These two sources are defined as scopes, which AwesomeApp defines in Facebooks AwesomeApp Facebook-app. The developer of AwesomeApp provided to ask exactly for these two permissions.

Peter gives his permission, and is redirected to AwesomeApp with a access token. AwesomeApp then uses the access token to retrieve Peters email and profile data directly from Facebook, with no need to authenticate with Peters credentials. More than that, each time Peter signs in to AwesomeApp, he visit the authorization page again, which already knows his decision and directly responds with a token.

So far…but how to apply this on our brutal real world? In springs OAuth2 implementation as well as in all examples, they are talking about clients and scope.

Are OAuths “clients and scopes” the same as our classical “user and authorities”?

Do I have to map authorities to scopes or users to clients?

Why do I need clients?

You are maybe trying to map the roles from the first scenario to enterprise case. This is tricky!

Second scenario: Any kind of application provides user login. This login results in a exchange of user credentials to access token. All further API calls provide this token in its HTTP header. The services inside are asking the authorization server to check the token and grant access. In the other direction, the services may request data from another service, granted by authorization service using a different client with different permissions than the user, which initiated the request.

As you see, the four OAuth2 roles depend of the direction in which data is requested. For asking protected business data from resource server, the authorization server is what it is, the resource servers also, the application is the client and the service holding the permissions (often the same as authorization server), is the owner. When asking the users data, the authorization service becomes a resource server, and resource server the client.

Scopes and Roles, Clients and Users

With OAuth2 you can define, which application (web, mobile, desktop, additional website) can access which resources. So there is one dimension, where we have to decide which user can access which data, but also which application or service, can access which resource. In other words: scopes are access controlling which endpoints are visible to clients, and authorities filter the data to the user based on his permissions.

In a web shop, the frontend may act as an client, having access to products, orders and customers, but the backend also about logistics, contracts and more, independent of the users authorities. In the other way, a user may have potential access to a service but no access to all its data, because he is using a web application, where other users are permitted to access while he is not. This service-to-service access, is our other dimension. If you are familiar with math, I can say: the client-scope-relation is linear independent to the user-authority-relation in OAuth2.

Why JWT?

OAuth2 is not about, how the token is looking like and where it is stored. So one approach is, to generate random strings and save token related data to these string in a store. Over a token endpoint, other services may ask something “is this token valid, and which permissions does it grant?”. This is the “user info URL” approach, where the authorization server is turning into a resource server for the user info endpoint.

As we talking about microservices, we need a way to replicate such a token store, to make the authorization server scalable. Despite this is a tricky task, there is one more issue with user info URL. For each request against a resource microservice containing a token in the header, the service will perform another request to authorization server to check the token. So without caching tricks, we got twice more request we really need, only for security. So both, scaling token store and token request are affecting the scalability of our architecture heavily. This is where JWT (pronounced as “jot”) come into play.

In short, the answer of that user info URL request, containing info about the OAuth client, optionally the user with its authorities and the granted scope, is serialized into JSON first, encoded with base64 and finally signed using a token. The result is a so called JSON Webtoken, which we use as an access token directly. When these JWTs are signed using RSA, the authorization server first signs it with the RSA private key, assuming every resource server will have a public key. When this token is passed via HTTP header, the resource servers just have to take this JWT, verify it was really signed by the proper private key (meaning this token is coming from authorization server), and instead of asking user info, deserializing the JSON content into a OAuth2Authentication, establishing a SecurityContext based on this.

Using JWT provides a simple way of transmitting hard to fake tokens, containing the permissions and user data in the access token string. Since all the data is already inside, there neither is a need to maintain a token store, nor the resource servers must ask authorization for token checks.

So, using JWT makes OAuth2 available to microservices, without affecting the architectures scalability.

implementing the authorization service

For the later token exchange we first generate a JWT token keystore

1
keytool -genkeypair -alias jwt -keyalg RSA -dname "CN=jwt, L=Berlin, S=Berlin, C=DE" -keypass mySecretKey -keystore jwt.jks -storepass mySecretKey

Then execute

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
$ keytool -list -rfc --keystore jwt.jks | openssl x509 -inform pem -pubkey
Keystore-Kennwort eingeben: mySecretKey
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwR84LFHwnK5GXErnwkmD
mPOJl4CSTtYXCqmCtlbF+5qVOosu0YsM2DsrC9O2gun6wVFKkWYiMoBSjsNMSI3Z
w5JYgh+ldHvA+MIex2QXfOZx920M1fPUiuUPgmnTFS+Z3lmK3/T6jJnmciUPY1pe
h4MXL6YzeI0q4W9xNBBeKT6FDGpduc0FC3OlXHfLbVOThKmAUpAWFDwf9/uUA//l
3PLchmV6VwTcUaaHp5W8Af/GU4lPGZbTAqOxzB9ukisPFuO1DikacPhrOQgdxtqk
LciRTa884uQnkFwSguOEUYf3ni8GNRJauIuW0rVXhMOs78pKvCKmo53M0tqeC6ul
+QIDAQAB
-----END PUBLIC KEY-----
-----BEGIN CERTIFICATE-----
MIIDGTCCAgGgAwIBAgIEOkszIDANBgkqhkiG9w0BAQsFADA9MQswCQYDVQQGEwJE
RTEPMA0GA1UECBMGQmVybGluMQ8wDQYDVQQHEwZCZXJsaW4xDDAKBgNVBAMTA2p3
dDAeFw0xNjAyMDExNzQwMTlaFw0xNjA1MDExNzQwMTlaMD0xCzAJBgNVBAYTAkRF
MQ8wDQYDVQQIEwZCZXJsaW4xDzANBgNVBAcTBkJlcmxpbjEMMAoGA1UEAxMDand0
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwR84LFHwnK5GXErnwkmD
mPOJl4CSTtYXCqmCtlbF+5qVOosu0YsM2DsrC9O2gun6wVFKkWYiMoBSjsNMSI3Z
w5JYgh+ldHvA+MIex2QXfOZx920M1fPUiuUPgmnTFS+Z3lmK3/T6jJnmciUPY1pe
h4MXL6YzeI0q4W9xNBBeKT6FDGpduc0FC3OlXHfLbVOThKmAUpAWFDwf9/uUA//l
3PLchmV6VwTcUaaHp5W8Af/GU4lPGZbTAqOxzB9ukisPFuO1DikacPhrOQgdxtqk
LciRTa884uQnkFwSguOEUYf3ni8GNRJauIuW0rVXhMOs78pKvCKmo53M0tqeC6ul
+QIDAQABoyEwHzAdBgNVHQ4EFgQUxebRVICNPg65T2RgrOe2J5qDMXMwDQYJKoZI
hvcNAQELBQADggEBAAHBF3JQ2ZsEjuYYwU5cp9BzBJoTQyChF37AA76EorrcSeqo
Rui1dUIfXbImIOZ5PBNk34IFWROTwpw80zBCZQ7NQ81ITzuhsxjbX7Wxj6iCq3u9
TDN+IxiaZMvJ2PDfeRqr93HOwMTMttxyW4KVa3geQ+yMMSZrxagEpqMA1Fviqa6T
5u8DNqfXQ8Hg+yG2bMNQs6GleAFkRprkHjR6yY7ehmIVMZ7iBkkXh8IO8fKy2WNK
uWa+DO2lXJj1W7HLXeaeT0twAqwyoNj2/pxMuv/JrTlNkhcUTmP+UBAJZih0KSGD
9TSKs5HlBGsIUpILuauNzZk1VS2RCyVtD1zf7vM=
-----END CERTIFICATE-----

You will be prompted to enter your secret key. Copy the public key (including the dashed lines) into a file named “public.cert”.

Copy this file to src/main/resources.

the plan

In this example we will define a resource “foo”, which can be read with authority FOO_READ and can be written with FOO_WRITE.

On the authentication service we have the user “reader”, who can read a foo, and a “writer”. To make the resource server accessible by a web application, we define a “web_app” client.

First we define our gradle file. Use start.spring.io to generate a gradle boot application with “Web” dependency.

this gradle file will be used for resource server also!

Now we adjust the dependencies to this

1
2
3
4
5
6
dependencies {
//...
compile('org.springframework.security.oauth:spring-security-oauth2')
compile('org.springframework.security:spring-security-jwt')
//..
}

To make the configuration non-confusing, I will use separate configurations instead of mixing all in inside the Application class. In both examples they are as they roll out from spring initialzr.

OAuth2Configuration

We begin with the following configuration

1
2
3
4
5
@Configuration
@EnableAuthorizationServer
public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {
//..
}

To define a default spring configuration, and enable the current application as an OAuth2 authorization server.

We inherit the class from AuthorizationServerConfigurerAdapter, to configure the details.

src/main/java/package/config/OAuth2Configuration.java

1
2
3
4
5
6
7
8
9
    @Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("web_app")
.scopes("FOO")
.autoApprove(true)
.authorities("FOO_READ", "FOO_WRITE")
.authorizedGrantTypes("implicit","refresh_token", "password", "authorization_code");
}

We assume FOO as resource access identity (so we can check this with #oauth2.hasScope(‘FOO’) to apply client access permission), auto approve for the scope for code authorization and pass the authorities for resource server.

Now we configure the OAuth2 endpoints to adjust the authentication manager (which will represent the web-security users), and JWT token store configuration:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore()).tokenEnhancer(jwtTokenEnhancer()).authenticationManager(authenticationManager);
} @Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager; @Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtTokenEnhancer());
} @Bean
protected JwtAccessTokenConverter jwtTokenEnhancer() {
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("jwt.jks"), "mySecretKey".toCharArray());
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setKeyPair(keyStoreKeyFactory.getKeyPair("jwt"));
return converter;
}

We define another configuration for the web security.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Configuration
class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
} @Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling()
.authenticationEntryPoint((request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED))
.and()
.authorizeRequests()
.antMatchers("/**").authenticated()
.and()
.httpBasic();
} @Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("reader")
.password("reader")
.authorities("FOO_READ")
.and()
.withUser("writer")
.password("writer")
.authorities("FOO_READ", "FOO_WRITE");
}
}

Note that there is no “@EnableWebSecurity”, because it’s automatically applied through @EnableAuthorizationServer. We also declare the authenticationManagerBean as a bean, which will be injected in the OAuth configuration above. HttpSecurity and user definition is quite straight forward, and can be implemented in various ways like UserDetailsService.

We configure the application to run on port 9999 for now.

indepth: we are using OAuth2 as authentication protocol, too. This approach is similar to OpenID connect, which is also a standard authentication protocol over OAuth2, more relying to public identity providers, such as Google, GitHub etc.

get access tokens

I will show how to get access token directly via username/password. There are other authorization types such as authorization code, implicit, client credentials.

To get a token, just

1
2
$ curl -XPOST "web_app:@localhost:9999/oauth/token" -d "grant_type=password&username=reader&password=reader"
{"access_token":"eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE0NTQ0MDA3MzQsInVzZXJfbmFtZSI6InJlYWRlciIsImF1dGhvcml0aWVzIjpbIkZPT19SRUFEIl0sImp0aSI6IjU1MWI4MTY4LTMwZmItNDZlNS1iMzJlLTc4ODRjNjJlNzZlYiIsImNsaWVudF9pZCI6IndlYl9hcHAiLCJzY29wZSI6WyJGT08iXX0.cKcgkLcbBECSWlz5fllb5V0EkfvrIq6RxjId34mNvhifS5bseQD5c8SlsQ_MvLf6unmosIHT_WL9TP56UUPX5TFrQpT09c2RPvnyhKD5PLlrf9o2RAAL5xS1yQqAWoSoNlx73m8cs8xOjIEix3mthNzEDlLYgsBbQci0ZWBCQHwnRE3OW4oykm4YH5X59X-8Juq1enztbdcjcyt4aFQOG7KVstW5M0MN3y3MMD4O9QgsatzBWDL2lPoazhKuYkR9LcoBZrKF_WzQgwolMhK_ousOxLEHNbKoWxOWJPJnayi6NW8o_2SlkTs7ykDh_GEGOSswpMGhkw98DI5dwFcTQg","token_type":"bearer","refresh_token":"eyJhbGciOiJSUzI1NiJ9.eyJ1c2VyX25hbWUiOiJyZWFkZXIiLCJzY29wZSI6WyJGT08iXSwiYXRpIjoiNTUxYjgxNjgtMzBmYi00NmU1LWIzMmUtNzg4NGM2MmU3NmViIiwiZXhwIjoxNDU2OTQ5NTM0LCJhdXRob3JpdGllcyI6WyJGT09fUkVBRCJdLCJqdGkiOiI0MTBlZWNjMS01NTRiLTQ0OGQtOGUyOC1iMGE3NTg5N2JlNzMiLCJjbGllbnRfaWQiOiJ3ZWJfYXBwIn0.Rw5ASYQjsJtPfWMMNIQ1TQA53VAqMSoDze8RHzbdRgXkn_BS-Qc84rTNg5deICL_Qdz6D3OtRL2pXgAkOn6ImCDJGaKcroZscZ1Mpy7lmBbsBf1pOolqOsXbCItOPh7h8CpB41ZipTeq-v_-5LQ7wNqwMTOzW_zL8On7bc0ZLF66PY-HK8BlFYUaiJRdJqP1PjfCh8hmOUMYnX8slQcdVMP4V1m6ZzdVFuhywKi3LD6tzrU-q1s2FEUVIpOCKJ6pKv9ts6tSK_lcjLjFO0rRzjTSdtywKE5Gc1rvC4BJALN_ZOn_uiskzo8IIztDUefZJV5OCAZ41igDUXbJHb1NSA","expires_in":43199,"scope":"FOO","jti":"551b8168-30fb-46e5-b32e-7884c62e76eb"}

implementing the resource server

We generate another Spring Boot application with Web starter and take the same gradle dependencies we used for the authorization server before. Copy the public.cert file into src/main/resources.

First, we have to implement the resource itself:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
@RequestMapping("/foo")
public class WebController { @GetMapping
public String readFoo() {
return "read foo " + UUID.randomUUID().toString();
} @PostMapping
public String writeFoo() {
return "write foo " + UUID.randomUUID().toString();
}
}

This is a simple controller. I use UUID random strings to be sure every response will be unique (for cache things).

Since we use JWT tokens, we have to configure the token store and token converter for JWT.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Configuration
public class JwtConfiguration {
@Autowired
JwtAccessTokenConverter jwtAccessTokenConverter; @Bean
@Qualifier("tokenStore")
public TokenStore tokenStore() {
return new JwtTokenStore(jwtAccessTokenConverter);
} @Bean
protected JwtAccessTokenConverter jwtTokenEnhancer() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
Resource resource = new ClassPathResource("public.cert");
String publicKey = null;
try {
publicKey = new String(FileCopyUtils.copyToByteArray(resource.getInputStream()));
} catch (IOException e) {
throw new RuntimeException(e);
}
converter.setVerifierKey(publicKey);
return converter;
}
}

Now lets configure the resource server security:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter{ @Override
public void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/**").authenticated()
.antMatchers(HttpMethod.GET, "/foo").hasAuthority("FOO_READ");
//.antMatchers(HttpMethod.POST, "/foo").hasAuthority("FOO_WRITE");
//you can implement it like this, but I show method invocation security on write
} @Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId("foo").tokenStore(tokenStore);
} @Autowired
TokenStore tokenStore; @Autowired
JwtAccessTokenConverter tokenConverter;
}

Note I commented the access rule for write requests on foo. I will show how to secure this via method invocation level security.

adding method security

To enable method security we just create a configuration like this:

1
2
3
4
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class GlobalMethodSecurityConfiguration {
}

and change the writeFoo method in our rest controller:

1
2
3
4
5
@PreAuthorize("hasAuthority('FOO_WRITE')")
@PostMapping
public String writeFoo() {
return "write foo " + UUID.randomUUID().toString();
}

You may ask why I didn’t use “secureEnabled = true” and the @Secured annotation. Sadly, this doesn’t work at the moment.

We run this application on port 9090.

testing

Now copy the access token from our last curl command and create a local variable TOKEN:

1
$ TOKEN=eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE0NTQ0MDA3MzQsInVzZXJfbmFtZSI6InJlYWRlciIsImF1dGhvcml0aWVzIjpbIkZPT19SRUFEIl0sImp0aSI6IjU1MWI4MTY4LTMwZmItNDZlNS1iMzJlLTc4ODRjNjJlNzZlYiIsImNsaWVudF9pZCI6IndlYl9hcHAiLCJzY29wZSI6WyJGT08iXX0.cKcgkLcbBECSWlz5fllb5V0EkfvrIq6RxjId34mNvhifS5bseQD5c8SlsQ_MvLf6unmosIHT_WL9TP56UUPX5TFrQpT09c2RPvnyhKD5PLlrf9o2RAAL5xS1yQqAWoSoNlx73m8cs8xOjIEix3mthNzEDlLYgsBbQci0ZWBCQHwnRE3OW4oykm4YH5X59X-8Juq1enztbdcjcyt4aFQOG7KVstW5M0MN3y3MMD4O9QgsatzBWDL2lPoazhKuYkR9LcoBZrKF_WzQgwolMhK_ousOxLEHNbKoWxOWJPJnayi6NW8o_2SlkTs7ykDh_GEGOSswpMGhkw98DI5dwFcTQg

and peform a call to read the foo resource

1
$ curl -H "Authorization: Bearer $TOKEN" "localhost:9090/foo"

and you should get a positive result, while

1
$ curl -XPOST -H "Authorization: Bearer $TOKEN" "localhost:9090/foo"

should result in access denied. To get access to write on foo, we must get a token as “writer”.

Conclusion

This should be a very brief introduction into how you can use OAuth2 in spring cloud microservices. If I explained something wrong, please be free to correct me. I am open to any kind of critics :)

The most important is, this sample works so you can try it out and change it in a way you need. May someone find this article useful :)

More resources

  • JHipster UAA docs for using a working setup using this basics to secure spring cloud microservices
  • JHiosoter UAA demo setup: a set of several JHipster microservices, demonstrating both user-to-service (Angular client) and service-to-service authorization (Feign Clients)

Have a great week.

http://stytex.de/blog/2016/02/01/spring-cloud-security-with-oauth2/

https://github.com/xetys/spring-cloud-oauth2-example

Securing Spring Cloud Microservices With OAuth2的更多相关文章

  1. Spring Cloud下基于OAUTH2认证授权的实现

    GitHub(spring -boot 2.0.0):https://github.com/bigben0123/uaa-zuul 示例(spring -boot 2.0.0): https://gi ...

  2. Spring Cloud下基于OAUTH2+ZUUL认证授权的实现

    Spring Cloud下基于OAUTH2认证授权的实现 在Spring Cloud需要使用OAUTH2来实现多个微服务的统一认证授权,通过向OAUTH服务发送某个类型的grant type进行集中认 ...

  3. Spring Cloud Gateway + Jwt + Oauth2 实现网关的鉴权操作

    Spring Cloud Gateway + Jwt + Oauth2 实现网关的鉴权操作 一.背景 二.需求 三.前置条件 四.项目结构 五.网关层代码的编写 1.引入jar包 2.自定义授权管理器 ...

  4. Spring Cloud Feign 使用OAuth2

    Spring Cloud 微服务架构下,服务间的调用采用的是Feign组件,为了增加服务安全性,server之间互相调用采用OAuth2的client模式.Feign使用http进行服务间的通信,同时 ...

  5. Spring Cloud:Security OAuth2 自定义异常响应

    对于客户端开发或者网站开发而言,调用接口返回有统一的响应体,可以针对性的设计界面,代码结构更加清晰,层次也更加分明. 默认异常响应 在使用 Spring Security Oauth2 登录和鉴权失败 ...

  6. Spring Cloud Zuul 网关使用与 OAuth2.0 认证授权服务

    API 网关的出现的原因是微服务架构的出现,不同的微服务一般会有不同的服务地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求,如果让客户端直接与各个微服务通信,会有以下的问题: 客户端会 ...

  7. [Spring Cloud实战 | 第六篇:Spring Cloud Gateway+Spring Security OAuth2+JWT实现微服务统一认证授权

    一. 前言 本篇实战案例基于 youlai-mall 项目.项目使用的是当前主流和最新版本的技术和解决方案,自己不会太多华丽的言辞去描述,只希望能勾起大家对编程的一点喜欢.所以有兴趣的朋友可以进入 g ...

  8. Spring Cloud Security OAuth2.0 认证授权系列(一) 基础概念

    世界上最快的捷径,就是脚踏实地,本文已收录[架构技术专栏]关注这个喜欢分享的地方. 前序 最近想搞下基于Spring Cloud的认证授权平台,总体想法是可以对服务间授权,想做一个基于Agent 的无 ...

  9. OAuth2密码模式已死,最先进的Spring Cloud认证授权方案在这里

    旧的Spring Security OAuth2停止维护已经有一段时间了,99%的Spring Cloud微服务项目还在使用这些旧的体系,严重青黄不接.很多同学都在寻找新的解决方案,甚至还有念念不忘密 ...

随机推荐

  1. GROUP BY,WHERE,HAVING间的区别和用法

    having子句与where都是过滤语句. where 子句的作用是在对查询结果进行分组前,将不符合where条件的行去掉,即在分组之前过滤数据,条件中不能包含聚组函数,使用where条件显示特定的行 ...

  2. Unity Socket TCP

    using UnityEngine; using System.Collections; using System.Collections.Generic; using System.Net.Sock ...

  3. C语言算法--统计字符串中单词的个数

    #include <stdio.h> #include <string.h> #include <stdlib.h> int main(void) { int le ...

  4. Mac OS X 10.10优胜美地如何完美接管iphone上的电话和短信

    自从今年苹果第一次的发布会上毛猫就特别注意这个功能,感觉特别Cool,特别方便.但直到今天毛猫才第一次成功测试出这个功能呀!虽然handoff功能还未测出来,但是觉得在mac上发短信和打电话也已经足够 ...

  5. permutations(全排列)

    Given a collection of distinct numbers, return all possible permutations. For example,[1,2,3] have t ...

  6. 北京一家JAVA开发公司面试题(留给后人)

    1.jsp有哪些内置对象?作用分别是什么? 2.描述一下servlet的生命周期和基本架构. 3.多线程有几种实现方法,都是什么? 同步有几种实现方法,都是什么? 4.作用域public   priv ...

  7. Delphi 项目总结

    Delphi 项目总结 随着项目的失败,这些天一直在总结失败的原因,到底是为什么?     一.技术层面         1.少用指针类型,多用类.             虽然指针类型能有效的节约内 ...

  8. 温故而后知新——对ado.net中常用对象的一些解释

    在使用ado.net连接数据库获取数据,一般的步骤是: 1.设置好web.config    //用来设置服务器数据库的地址以及登录名密码 2.创建Connection对象    //用来创建访问数据 ...

  9. 线上Django项目python2到3升级日记

    这两天干了一个几斤疯狂的事情,花不到一个工作日的时间把一个线上Django项目语言版本从python2升级到Python31.字典的一个语法变化 Python2.7: if dict1.haskey( ...

  10. 数据库导入Excel数据的简易方法

    当然,最糙猛的方式就是自己写程序读取Excel程序然后插进数据库,但那种方式要求太高.说个简单方法,主流数据库的管理工具支持CSV文件格式数据向表导入,而Excel可以另存外CSV文件,这种导入就手工 ...