current position:Home>Use of spring security in distributed architecture

Use of spring security in distributed architecture

2022-02-04 17:13:04 MG-net

1、 Distributed system authentication requirements

Every distributed service needs authentication and authorization . If each service has some authentication, the logic of authorization will be redundant . So we need to extract the authentication authorization , Conduct unified authentication and authorization .

Authentication authorization service , You need to support a variety of authentication and authorization methods , Such as user name and password 、 SMS verification code 、 Qr code and so on . At the same time, the authentication of other application access shall be provided for other services .

2、 Distributed system authentication scheme

1、 The selection

  • be based on session Method of authentication : There is session The problem of sharing . There are many plans , Common direct use redis For storage ,spring boot It also provides related plug-ins . The disadvantage is that different clients cookie The mechanism may be different .
  • be based on token authentication : After successful certification , The server returns a message to the client token, Including user information, etc , In this way, the client saves itself , Every time you ask, bring token that will do . The disadvantage is that it accounts for the loan 、 Every request requires signature verification . It is also a commonly used verification method at this stage .

2、OAuth2.0 Introduce

 OAuth2.0 Is the standard of open Authorization , Allow users to authorize third-party applications to access the information they store on another provider , Instead of providing user names and passwords to third-party applications or sharing all of their data .( and OSS The difference between ,OSS Used for module authentication inside the system 、OAuth2.0 Suitable for third party certification ).

For example, users need to log in to a website with wechat , If the website needs to obtain identity information from wechat, it is considered that the user authentication is successful . Wechat, with the consent of the user , Generate... For the website token, Site use token Get user information from wechat .

  • Customer segment : The example is the website , The authentication server will issue the client ID and key
  • Resource owners : The user himself
  • Authentication server : The WeChat OAuth2.0 Authentication server , There are two parts: authentication customer segment and resource owner
  • Resource server : Wechat resource server , Store user information  

3、 ... and 、Spring cloud security OAuth2.0

yes spring security Provided OAuth2.0 function , The whole includes 2 A service :

1、 Authorized service

  • TokenEndpoint: Service access token request . The default path :/oauth/token
  • AuthorizationEndpoint: Service authentication request . The default path :/oauth/authorize

2、 Resource service

  • OAuth2AuthorztionProcessingFilter: Used to resolve and authenticate the identity token given by the request

3、 The certification process is as follows :

  • Client request UAA Authorize services to authenticate
  • After certification UAA Service method token
  • The client carries token Token request resource service
  • The legal line of the resource service verification token , If it is legal, the resource information will be returned

Four 、 Authentication server configuration

1、 Server configuration

package com.mg.uaa.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeServices;
import org.springframework.security.oauth2.provider.code.InMemoryAuthorizationCodeServices;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;


/**
 *  Authorized service 
 * 1、 Since the verification is to be completed , You need to know where the client information comes from , Therefore, configure the client information 
 * 2、 Since we have to find a way token, Need to define token dependent endpoint, And know how to access token And the client supports those types of token
 * 3、 Since the report is missing endpoint, That's what we need to do endpoint Carry out safety restraint 
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServer implements AuthorizationServerConfigurer {

    @Autowired
    private TokenStore tokenStore;

    @Autowired
    private ClientDetailsService clientDetailsService;

    @Autowired
    private AuthorizationCodeServices authorizationCodeServices;

    @Autowired
    private AuthenticationManager authenticationManager;

    /**
     *  Security constraints used to configure tokens 
     * @param authorizationServerSecurityConfigurer
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerSecurityConfigurer authorizationServerSecurityConfigurer) throws Exception {
        authorizationServerSecurityConfigurer
                //  /oauth/token_key  Open 
                .tokenKeyAccess("permitAll()")
                // /oauth/check_token  Open 
                .checkTokenAccess("permitAll()")
                // Form request token 
                .allowFormAuthenticationForClients();
    }

    /**
     *  Client details , Authenticate the identity of the client 
     *  Specify supported clients 
     *  This configuration is responsible for querying the client , There are several properties :
     * 1、clientId: Client identity 
     * 2、secret: Client key 
     * 3、scope: Used to display the access range of the client 
     * 4、authorizedGrantTypes: The type of authorization that the client can use 
     * 5、authorities: Permission of the client , Smaller particle size 
     * @param clientDetailsServiceConfigurer
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clientDetailsServiceConfigurer) throws Exception {
        clientDetailsServiceConfigurer.inMemory()
                // Client name 
                .withClient("c1")
                // password 
                .secret(new BCryptPasswordEncoder().encode("123"))
                // resource list 
                .resourceIds("res1")
                // Supported authentication types 
                .authorizedGrantTypes("implicit","refresh_token", "password", "authorization_code", "client_credentials")
                // Scope of Authorization :  Permissions allowed, such as  user_base_info
                .scopes("all")
                //token When it comes to the way , Whether to jump to the authorization page 
                .autoApprove(false)
                // Add visa callback address 
                .redirectUris("http://www.baidu.com");
    }

    /**
     *  To apply for the access endpoint of the token and the service of the token 
     * @param authorizationServerEndpointsConfigurer
     * @throws Exception
     */
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer authorizationServerEndpointsConfigurer) throws Exception {
        /**
         * 1、authenticationManager: Resource authorizer when you use password authorization type   Use 
         * 2、userDetailsService:? Self realized userDetailsService
         * 3、authorizationCodeServices: Authorization code mode 
         * 4、tokenGranter: Custom authorization mode 
         *
         *  Configure the authorization endpoint . Users can configure it themselves , The framework has given the default :
         * 1、/oauth/authorize: Authorization endpoint 
         * 2、/oauth/token: Token endpoint 
         * 3、/oauth/confirm_access: Authorization service error message endpoint 
         * 4、/oauth/error: Authorization service error message endpoint 
         * 5、/oauth/check_token: User resource service access token resolution endpoint 
         * 6、/oauth/token_key: Provide the endpoint of the public key ( Use JWT situation , Is to provide a public key for asymmetric encryption )
         */
        authorizationServerEndpointsConfigurer
                // Password mode requires 
                .authenticationManager(authenticationManager)
                // Authorization mode 
                .authorizationCodeServices(authorizationCodeServices)
                // Token management service 
                .tokenServices(tokenService())
                //post Submit 
                .allowedTokenEndpointRequestMethods(HttpMethod.POST);
    }

    @Bean
    public AuthorizationCodeServices authorizationCodeServices() {
        // How to set the authorization code of authorization code mode   access , Temporarily use memory mode 
        return new InMemoryAuthorizationCodeServices();
    }

    /**
     *  Token service 
     * @return
     */
    @Bean
    public AuthorizationServerTokenServices tokenService() {
        DefaultTokenServices service=new DefaultTokenServices();
        // Client information service 
        service.setClientDetailsService(clientDetailsService);
        // Whether to refresh the token 
        service.setSupportRefreshToken(true);
        // Storage strategy 
        service.setTokenStore(tokenStore);
        // Valid time 
        service.setAccessTokenValiditySeconds(7200);
        // Refresh time 
        service.setRefreshTokenValiditySeconds(259200);
        return service;
    }
}
package com.mg.uaa.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author Administrator
 * @version 1.0
 **/
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    // Authentication manager 
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
    // Coder 
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    // Security interception mechanism ( above all )
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/r/r1").hasAnyAuthority("p1")
                .antMatchers("/login*").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin();
    }
}
package com.mg.uaa.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

/**
 * @author Administrator
 * @version 1.0
 **/
@Configuration
public class TokenConfig {

    @Bean
    public TokenStore tokenStore() {
        //1、InMemoryTokenStore: be-all token Will be stored in memory 
        //2、JdbcTokenStore:token Save in database 
        //3、JwtTokenStore: be based on JWT Generated token, Because the information is stored in token in , So there's no need to store , But it's hard to undo ten , It is usually used to deal with short declaration period token
        return new InMemoryTokenStore();
    }
}

 

 ​​ Mode testing :

  • Authorization code mode :( A safer model , This is what wechat authorizes )
    • /uaa/oauth/authorize?client_id=c1&response_type=code&scope=all&redirect_uri=http://www.baidu.com
    • /uaa/oauth/token?
      client_id=c1&client_secret=secret&grant_type=authorization_code&code=5PgfcD&redirect_uri=http://www.baidu.com
  • Simplified mode : Just jump to the page , And carry token, Client for purely static pages
    • /uaa/oauth/authorize?client_id=c1&response_type=token&scope=all&redirect_uri=http://www.baidu.com
  • Password mode , You need to bring your user name and password , Used for the first stage of self-development
    • /uaa/oauth/token?client_id=c1&client_secret=secret&grant_type=password&username=shangsan&password=123
  • Client mode , Relatively simple , Just pass the client credentials , Full trust in the client
    • /uaa/oauth/token?client_id=c1&client_secret=secret&grant_type=client_credentials

2、 Resource server configuration

package com.mg.order.conifg;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices;

/**
 *  Configuration of service resources 
 */
@Configuration
@EnableResourceServer
public class ResouceServerConfig extends ResourceServerConfigurerAdapter {

    private static final String RESOURCE_ID = "res1";

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources
                // resources ID
                .resourceId(RESOURCE_ID)
                // The service that validates the token 
                .tokenServices(tokenService())
                .stateless(true);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/**")
                // Token  scope  Must be  all
                .access("#oauth2.hasScope('all')")
                .and().csrf().disable()
                // Unpractical  session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    /**
     *  Remote authentication service token 
     * @return
     */
    @Bean
    public ResourceServerTokenServices tokenService() {
        // Use the remote service request authorization server to verify token, Verification must be specified token  Of url、client_id,client_secret
        RemoteTokenServices service=new RemoteTokenServices();
        service.setCheckTokenEndpointUrl("http://localhost:53020/uaa/oauth/check_token");
        service.setClientId("c1");
        service.setClientSecret("123");
        return service;
    }
}
package com.mg.order.conifg;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * @author Administrator
 * @version 1.0
 **/
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    // Security interception mechanism ( above all )
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
//                .antMatchers("/r/r1").hasAuthority("p2")
//                .antMatchers("/r/r2").hasAuthority("p2")
                .antMatchers("/r/**").authenticated()// all /r/** Your request must be authenticated 
                .anyRequest().permitAll()// except /r/**, Other requests can access 
        ;


    }
}

test :

  So you can visit . summary

1、 Authentication server : It is mainly used for token The way to , Also specify which clients 、 Which resources can be accessed

2、 Resource server : Resources need to be configured ID、scope etc.

3、token Generation can also use JWT,JWT Itself contains customer information , So you don't have to call remotely every time to verify user information .

copyright notice
author[MG-net],Please bring the original link to reprint, thank you.
https://en.cdmana.com/2022/02/202202041713001243.html

Random recommended