Preface
After climbing for two days, the pit finally came up. It was very simple to see what others wrote. When they wrote, they had various problems. There were many SSO articles on the Internet, and when they wrote, they had various problems (they were too dishy). Make a note. It's easy to check later.
For the OAuth2 Authentication and Authorization Server, see the previous article
https://zcsherrydc.github.io/2019/10/07/SpringCloud-OAuth2%E5%92%8CJWT/
<font color=ff> project address </font>:
https://github.com/zcsherrydc/SpringCloudStudy Using git tools
git checkout sso
reference material:
https://www.cnblogs.com/cjsblog/p/10548022.html
Ruan Yifeng's OAuth 2 Explanation https://blog.csdn.net/WSM960921/article/details/98222004
What is SSO?
English full name single Sign On, Chinese list login. In a multi-application system, users only need to log in once to access all trust services. SSO solves the problem of accessing user session s from other services without login by mapping user login information to browser cookie s.
General framework
There are five modules in one project:
-
oauth-server is an authentication and authorization service responsible for token issuance
-
zuul is a gateway service to achieve unified authorization
-
Eureka-client and eureka-client 1 are two application services
-
eureka-server-single is the eureka registry
To achieve the function is to access eureka-client through zuul port, first need to log in, then jump to oauth-server to authenticate and authorize, after success, you can also access eureka-client 1 without login.
oauth-server
See for details
https://zcsherrydc.github.io/2019/10/07/SpringCloud-OAuth2%E5%92%8CJWT/
Changed several places
AuthorizationServerConfig
@Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("zuul") .secret(new BCryptPasswordEncoder().encode("secret")) .scopes("app") .authorizedGrantTypes("authorization_code", "password") .redirectUris("http://localhost:9110/login") ; // clients.withClientDetails(new JdbcClientDetailsService(dataSource)); }
UserController
This function provides validation for other module resource servers
@RestController @RequestMapping("/oauth2_token") public class UserController { @GetMapping("/current") public Principal user(Principal principal) { return principal; } }
ResourceServerConfig
@Override public void configure(HttpSecurity http) throws Exception { http // AnMatcher indicates that requests for / oauth2_token can only be processed .antMatcher("/oauth2_token/**") .authorizeRequests() .anyRequest().authenticated() ; }
application.yml
Add the root address, that is, add / oauth-server every time you visit the service
server: port: 9120 # invalid_token error is reported if the url root address is not configured # Or you can configure it in zuul servlet: context-path: /oauth-server
Zuul
zuul serves as the entrance of the system, providing routing, unified authorization and other functions.
Dependencies are shown in the project
<font color='red'> Note: All modules introduce spring-cloud-starter-oauth2 dependencies, so they are put into the project's public pom.xml. To achieve oauth2, only one reference is needed to </font>.
application.yml
Post out the main configuration as detailed in the project
sensitiveHeaders: This must be done. zuul rewrites the header information in the request when forwarding the route. Setting it to empty is no filtering.
security.oauth2.resource: This is the configuration associated with parsing tokens
Resource servers need to parse tokens to verify correctness in three ways:
- If the token is not jwt asymmetric encryption, then access / oauth/check_token verifies token directly. If it is asymmetric, access / oauth/token_key to obtain the public key for parsing
- Access the method in the controller of the authentication server and get Principal to verify it
- Locally configure the resource server, inherit the ResourceServer Configurer Adapter interface, and implement the same encryption method as the authentication server.
zuul: routes: eureka-client: path: /eureka-client/** sensitiveHeaders: serviceId: eureka-client eureka-client1: path: /eureka-client1/** sensitiveHeaders: serviceId: eureka-client1 oauth-server: path: /oauth-server/** sensitiveHeaders: serviceId: eureka-client #Authentication server address oauth-server: http://localhost:9120/oauth-server security: oauth2: # Corresponding to the client setting in the authentication server client: client-id: zuul client-secret: secret # Get the token address access-token-uri: ${oauth-server}/oauth/token # Authentication address user-authorization-uri: ${oauth-server}/oauth/authorize resource: # Perform token verification # 1. Access controller to get Principal # user-info-uri: ${oauth-server}/oauth2_token/current # prefer-token-info: false # Accessing Authorization Server to Obtain Public Key Resolution Token jwt: key-uri: ${oauth-server}/oauth/token_key
Configure Web Security Config
The entire zuul module can be added with this configuration
@EnableOAuth2Sso @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http //URLs requiring authorization .authorizeRequests() .antMatchers("/login").permitAll() .anyRequest().authenticated() .and().csrf().disable() ; } }
eureka-client (resource server)
application.yml
Add the following to verify that the requested token is correct
security: oauth2: resource: id: eureka-client # Three authentication token methods for resource server # Local configuration in ResourceServer Config # 2. Get the user information from the authentication server and resolve the token # user-info-uri: ${oauth-server}/oauth2_token/current # prefer-token-info: false # 3. Remotely Acquiring Public Key Resolution token jwt: key-uri: ${oauth-server}/oauth/token_key
Configure ResourceServer Config
The resource server only needs to add this configuration.
@Configuration @EnableResourceServer //Spring Security disables annotations by default and opens annotations here // Combining @PreAuthorize("hasRole('admin')) to determine whether a user has access to a method at a control layer @EnableGlobalMethodSecurity(prePostEnabled = true) public class ResourceServerConfig extends ResourceServerConfigurerAdapter { @Override public void configure(HttpSecurity http) throws Exception { http // Configure URLs that require permissions .authorizeRequests() .anyRequest().authenticated() .and().csrf().disable(); ; } //The following is the local method of token validation. If you use this method, comment out the configuration of the above application.yml and put oauth2.jks in the resources folder // @Override // public void configure(ResourceServerSecurityConfigurer resources) throws Exception { // resources.resourceId("app").tokenStore(tokenStore()); // } // // @Bean // public TokenStore tokenStore() { // return new JwtTokenStore(jwtAccessTokenConverter()); // } // // /** // * Signature of token by asymmetric encryption algorithm // * // * @return // */ // @Bean // public JwtAccessTokenConverter jwtAccessTokenConverter() { // final JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); // // Import Certificate // KeyStoreKeyFactory keyStoreKeyFactory = // new KeyStoreKeyFactory(new ClassPathResource("oauth2.jks"), "mypass".toCharArray()); // converter.setKeyPair(keyStoreKeyFactory.getKeyPair("oauth2")); // return converter; // } }
<font color='red'>Note: </font>
If you use local validation methods, you may not be able to report an error reading oauth2.jks, because by default you do not refer to files in the resources directory and you need to add configuration under < build > in pom.xml
<resources> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.*</include> </includes> </resource> </resources>
test
Start order:
- eureka-server-single
- oauth-server
- zuul
- eureka-client and eureka-ciient1
Access method under eureka-client through zuul port http://localhost:9110/eureka-client/hi
It will automatically jump to the login page of oauth-server and enter the username and password to login.
Look at url, jump to oauth/authorize, which is the authorization interface, and then carry some zuul configuration information.
Success
Accessing eureka-client 1 does not require login
summary
It's concise, but it really took two days to make it (it's still too good).
There is no literary grace, and the principled things can not be written out. We can only record the practice, and we can communicate with each other.
See Personal Blog for more articles https://zcsherrydc.github.io/