Small knowledge, big challenge! This paper is participating in theEssentials for programmers”Creative activities

This paper has participated inProject DigginTo win the creative gift package and challenge the creative incentive money.

📖 preface

Good attitude, not so tired. In a good mood, all you see is beautiful scenery.Copy the code

"If you can't solve a problem for a while, use this opportunity to see your limitations and put yourself out of order." As the old saying goes, it's easy to let go. If you are distracted by something, learn to disconnect. Cut out the paranoia, the trash in the community, and get rid of the negative energy. Good attitude, not so tired. In a good mood, all you see is beautiful scenery.

🚓Introduction of depend on


<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <! -- Freemarker, page rendering engine -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-freemarker</artifactId>
    </dependency>

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

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

    <! -- SpringBoot monitor client -->
    <dependency>
        <groupId>de.codecentric</groupId>
        <artifactId>spring-boot-admin-starter-client</artifactId>
        <version>${spring-boot-admin.version}</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>

    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>

    <! --redis-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>

    <! Mysql > introduce database password encryption -->
    <dependency>
        <groupId>com.github.ulisesbocchio</groupId>
        <artifactId>jasypt-spring-boot-starter</artifactId>
        <version>${jasypt.version}</version>
    </dependency>

    <! Mysql > insert link dependency
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>${mysql-connector}</version>
        <scope>provided</scope>
    </dependency>

    <! - introduction of Druid rely on Java. SQL. SQLFeatureNotSupportedException http://www.vmfor.com/p/101494868463.html-- >
    <dependency>
        <! -- Automatic configuration -->
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>${druid.version}</version>
    </dependency>

    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
        <version>${common-pool.version}</version>
    </dependency>

    <! --<dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-micro-spring-boot-starter</artifactId> <version>${knife4j.version}</version> </dependency>-->

    <! -- Introduce MybatisPlus dependency -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>${mybatis-plus.version}</version>
    </dependency>

    <! -- Introduce multi-source dependencies -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
        <version>${mybatis-plus-dynamic.version}</version>
    </dependency>
    
</dependencies>
Copy the code

1. Enable class addition


@EnableFeignClients
// Enable the API interface for obtaining the token externally
@EnableResourceServer
@EnableDiscoveryClient
Copy the code

2. Create an authorization profileAuthorizationServerConfig.java


According to the official instructions we need to create a configuration class to implementAuthorizationServerConfigurerSo let’s create a class that inherits its implementation classAuthorizationServerConfigurerAdapter, the specific code is as follows:

package com.cyj.dream.auth.config;

import com.cyj.dream.auth.entity.SysUser;
import com.cyj.dream.auth.persistence.service.impl.CustomUserServiceImpl;
import com.cyj.dream.core.constant.Constant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
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.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.CompositeTokenGranter;
import org.springframework.security.oauth2.provider.TokenGranter;
import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenGranter;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.code.AuthorizationCodeTokenGranter;
import org.springframework.security.oauth2.provider.implicit.ImplicitTokenGranter;
import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter;
import org.springframework.security.oauth2.provider.refresh.RefreshTokenGranter;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;

import javax.sql.DataSource;
import java.util.*;
import java.util.concurrent.TimeUnit;

/ * * *@Description: Authorization profile *@BelongsProject: DreamChardonnay
 * @BelongsPackage: com.cyj.dream.auth.config
 * @Author: ChenYongJia
 * @CreateTime: 2021-09-30 
 * @Email: [email protected]
 * @Version: 1.0 * /
// Configure the authentication service center
@Configuration / / configuration class
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private CustomUserServiceImpl userDetailsService;

    /**
     * accessToken 有效期 2小时
     */
    private static final int ACCESS_TOKEN_VALIDITY_SECONDS = 7200 * 12 * 7;

    /**
     * accessToken 有效期 2小时
     */
    private static final int REFRESH_TOKEN_VALIDITY_SECONDS = 7200 * 12 * 7;

    TokenStore is stored in redis * <p> *. You can consider whether to store access_tokens in redis ** based on your own business scenario@return* /
    @Bean
    public TokenStore redisTokenStore(a) {
        RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory);
        // Redis key prefix --DreamCloud
        tokenStore.setPrefix(Constant.tokenPrefix + "_");
        return tokenStore;
    }

    /** * Config client management is JDBC **@param clients
     * @throws Exception
     */
    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory().withClient("dream").secret(passwordEncoder.encode("c83fb51ff6e807e8805c6dd9d5707365"))
                // Entitlement code Callback address in authorization mode
                .redirectUris("http://www.baidu.com")
                .authorizedGrantTypes("authorization_code"."password"."refresh_token").scopes("all")
                .accessTokenValiditySeconds(ACCESS_TOKEN_VALIDITY_SECONDS)
                // Authorization type
                .refreshTokenValiditySeconds(REFRESH_TOKEN_VALIDITY_SECONDS);
        //clients.withClientDetails(new JdbcClientDetailsService(dataSource));
    }

    /** * Authentication server Endpoints configuration **@return
     * @author ChenYongJia
     * @date2021/9/30 * /
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
        tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer()));
        endpoints.authenticationManager(authenticationManager).allowedTokenEndpointRequestMethods(HttpMethod.GET,
                HttpMethod.POST, HttpMethod.PUT,
                HttpMethod.DELETE)
                .tokenEnhancer(tokenEnhancerChain)
                // Use Redis to configure tokenStore management
                .tokenStore(redisTokenStore()).userDetailsService(userDetailsService)
                // Configure the authorization mode
                .tokenGranter(tokenGranter(endpoints));
        // Configure the tokenServices parameter +
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        // Set the accessToken expiration time
        defaultTokenServices.setAccessTokenValiditySeconds((int) TimeUnit.HOURS.toSeconds(2));
        // Configure the expiration time of refreshToken
        defaultTokenServices.setRefreshTokenValiditySeconds((int) TimeUnit.DAYS.toSeconds(30));
        // Set the support for refreshing tokens
        defaultTokenServices.setReuseRefreshToken(true);
        defaultTokenServices.setSupportRefreshToken(true);
        defaultTokenServices.setTokenStore(endpoints.getTokenStore());
        defaultTokenServices.setClientDetailsService(endpoints.getClientDetailsService());
        defaultTokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());
        endpoints.tokenServices(defaultTokenServices);
    }

    /** * Authentication server related interface permission management **@return
     * @author ChenYongJia
     * @date2021/9/30 * /
    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        // Configure to allow form access
        security.allowFormAuthenticationForClients()
                .tokenKeyAccess("isAuthenticated()")
                .checkTokenAccess("permitAll()");
    }

    / * * * configure authorization model can also add custom (not write also have default) * * to see AuthorizationServerEndpointsConfigurer getDefaultTokenGranters in method Later add a mobile phone verification code function * *@param endpoints
     * @return* /
    private TokenGranter tokenGranter(AuthorizationServerEndpointsConfigurer endpoints) {
        List<TokenGranter> list = new ArrayList<>();
        // Add a refresh token
        list.add(new RefreshTokenGranter(endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory()));
        // Authorization code mode
        list.add(new AuthorizationCodeTokenGranter(endpoints.getTokenServices(), endpoints.getAuthorizationCodeServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory()));
        // Client credential mode
        list.add(new ClientCredentialsTokenGranter(endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory()));
        // Password mode
        list.add(new ResourceOwnerPasswordTokenGranter(authenticationManager, endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory()));
        / / hidden
        list.add(new ImplicitTokenGranter(endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory()));
        return new CompositeTokenGranter(list);
    }

    /** * Create a token enhancement method to add some additional information that we want to return ourselves **@return* /
    @Bean
    public TokenEnhancer tokenEnhancer(a) {
        return (accessToken, authentication) -> {
            final Map<String, Object> additionalInfo = new HashMap<>(2);
            additionalInfo.put("license"."SunnyChen-DreamChardonnay");
            SysUser user = (SysUser) authentication.getUserAuthentication().getPrincipal();
            if(user ! =null) {
                additionalInfo.put("userId", user.getSysUserId());
                additionalInfo.put("userPhone", user.getSysUserPhone());
                additionalInfo.put("userDeptId", user.getSysUserInfoDepartmentId());
            }
            ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
            return accessToken;
        };
    }

    /** * is used for verification **@return* /
    @Bean
    AuthenticationManager authenticationManager(a) {
        AuthenticationManager authenticationManager = new AuthenticationManager() {
            @Override
            public Authentication authenticate(Authentication authentication) throws AuthenticationException {
                returndaoAuhthenticationProvider().authenticate(authentication); }};return authenticationManager;
    }

    /** * is used for verification **@return* /
    @Bean
    public AuthenticationProvider daoAuhthenticationProvider(a) {
        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
        daoAuthenticationProvider.setUserDetailsService(userDetailsService);
        daoAuthenticationProvider.setHideUserNotFoundExceptions(false);
        daoAuthenticationProvider.setPasswordEncoder(passwordEncoder);
        returndaoAuthenticationProvider; }}Copy the code

3. Since the authorization server is itself a resource server, create a resource configuration as follows


package com.cyj.dream.auth.config;

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;

/ * * *@Description: Resource configurator *@BelongsProject: DreamChardonnay
 * @BelongsPackage: com.cyj.dream.auth.config
 * @Author: ChenYongJia
 * @CreateTime: 2021-09-30
 * @Email: [email protected]
 * @Version: 1.0 * /
@Configuration
// Enable the resource service
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    HTTP. AuthorizeRequests () = HTTP. AuthorizeRequests () = HTTP. AuthorizeRequests () = HTTP. Instead of http.authorizerequests (), * instead uses requestMatchers().antmatchers (""), which is configured with an array of urls that need to be intercepted by the resource interface@param http
     * @return void
     */
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http    // Configure the resource interface to be protected
                .requestMatchers().
                antMatchers("/user"."/test/need_token"."/logout"."/remove"."/update"."/test/need_admin"."/test/scope") .and().authorizeRequests().anyRequest().authenticated(); }}Copy the code

4. CreatewebSecurityconfiguration


/ * * OK, I want to say more about the configuration of two words: * * 1. First of all, when we want to customize Spring Security we need to inherit from WebSecurityConfigurerAdapter to complete, relevant configuration can rewrite the corresponding * method. 2. We register our CustomUserService Bean here and add our own custom authentication by overriding the configure method. Configure (HttpSecurity HTTP); configure(HttpSecurity HTTP); configure(HttpSecurity HTTP); .anyRequest().authenticated() means that all other requests must be authenticated. ** antMatchers("/admin/**"). HasRole ("ROLE "). * antMatchers("/admin/**")_ADMIN"), you can also set the files in the ADMIN folder to be accessed by multiple roles, * written as follows:.antmatchers ("/ ADMIN /**").hasanyrole ("ROLE_ADMIN","ROLE_USER") * 6. HasIpAddress specifies whether an IP address is allowed to access the admin resource. AntMatchers ("/admin/**").hasipaddress ("210.210.210.210") * 7 For more permission control, see the source code: */Copy the code

The code is as follows:

package com.cyj.dream.auth.config;

import com.cyj.dream.auth.handler.*;
import com.cyj.dream.auth.persistence.service.impl.CustomUserServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
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.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/ * * *@Description: WebSecurity configuration *@BelongsProject: DreamChardonnay
 * @BelongsPackage: com.cyj.dream.auth.config
 * @Author: ChenYongJia
 * @CreateTime: 2021-09-30
 * @Email: [email protected]
 * @Version: 1.0 * /
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomUserServiceImpl userDetailsService;

    /** * Custom login success handler */
    @Autowired
    private MyAuthenticationSuccessHandler userLoginSuccessHandler;

    /** * Custom logon failed handler */
    @Autowired
    private MyAuthenticationFailureHandler userLoginFailureHandler;

    /** * Customizes the logout success handler */
    @Autowired
    private UserLogoutSuccessHandler userLogoutSuccessHandler;

    /** * Custom temporary no permission processor */
    @Autowired
    private UserAuthAccessDeniedHandler userAuthAccessDeniedHandler;

    /** * Customize the unlogged processor */
    @Autowired
    private UserAuthenticationEntryPointHandler userAuthenticationEntryPointHandler;

    @Bean
    public BCryptPasswordEncoder passwordEncoder(a) {
        return new BCryptPasswordEncoder();
    }

    @Override
    @Bean
    public UserDetailsService userDetailsService(a) {
        return new CustomUserServiceImpl();
    }

    /** * Configure login authentication logic */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService())
                .passwordEncoder(passwordEncoder());
    }

    /** * Grant type ** support password grant type **@returnAuthentication Managed object *@throwsException Indicates authentication Exception information */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean(a) throws Exception {
        return super.authenticationManagerBean();
    }

    /** * Security request configuration, where the Security part of the request is passed, Security interception in the resource server configuration * <p> * HTTP Security configuration **@paramHTTP HTTP security object *@throwsException HTTP security Exception information */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // Configure allowed requests and cross-domain issues
        http.authorizeRequests()
                .antMatchers("/webjars/**"."/js/**"."/css/**"."/images/*"."/fonts/**"."/**/*.png"."/**/*.jpg"."/static/**")
                // .anyRequest()
                .permitAll()
                // All requests are accessible, and local development opens the comment on the following line
                //.antMatchers("/**").permitAll()
                // Requests or resources without permission validation (read from configuration files), local development can, comment out this line
                .antMatchers("/login"."/oauth/**")
                .permitAll()
                .antMatchers("/ * *")
                .fullyAuthenticated()
                .and()
                // Configure the unlogged custom processing class
                .httpBasic()
                .authenticationEntryPoint(userAuthenticationEntryPointHandler)
                .and()
                .csrf()
                .disable()
                // Set the login address
                .formLogin()
                / / local
                //.loginPage("/login/userLogin")
                //.loginProcessingUrl("/login/userLogin")
                .loginPage("/login")
                // Configure the logon success custom processing class
                .successHandler(userLoginSuccessHandler)
                // Configure a custom handling class for login failures
                .failureHandler(userLoginFailureHandler)
                .permitAll()
                .and()
                // Configure the logout address
                .logout()
                // /userInfo/loginOutByToken
                .logoutUrl("/login/loginOut")
                // Configure the user to log in to the custom processing class
                .logoutSuccessHandler(userLogoutSuccessHandler)
                .and()
                // Config does not have permission to customize processing classes
                .exceptionHandling()
                .accessDeniedHandler(userAuthAccessDeniedHandler)
                .and()
                // Enable cross-domain
                .cors()
                .and()
                // Cancel cross-site request forgery protection
                .csrf().disable();
                /*.cors().and() .addFilterAt(ignoreLogoutFilter, LogoutFilter.class); * /
        // In order to be able to use iframe embedded page load
        http.headers().frameOptions().sameOrigin();
        // No session is required based on Token
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
        // Disable caching
        http.headers().cacheControl();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        // Set resources to be ignored
        web.ignoring().antMatchers(
                "/error"."/v2/api-docs/**"."/favicon.ico"."/css/**"."/js/**"."/images/*"."/fonts/**"."/**/*.png"."/**/*.jpg")
                // Do not intercept the configuration of Swagger2
                .antMatchers("/templates/**")
                .antMatchers("/static/**")
                .antMatchers("/webjars/**")
                .antMatchers("/swagger-ui.html/**")
                .antMatchers("/v2/**")
                .antMatchers("/doc.html")
                .antMatchers("/api-docs-ext/**")
                .antMatchers("/swagger-resources/**"); ; }}Copy the code

5. Create onecontrollerConduct access tests


package com.cyj.dream.auth.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cyj.dream.auth.entity.SysUser;
import com.cyj.dream.auth.persistence.service.ITbSysUserService;
import com.cyj.dream.core.aspect.annotation.ResponseResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.security.Principal;

/ * * *@Description: User controller *@BelongsProject: DreamChardonnay
 * @BelongsPackage: com.cyj.dream.auth.controller
 * @Author: ChenYongJia
 * @CreateTime: the 2021-09-30 10:40: *@Email: [email protected]
 * @Version: 1.0 * /
@Slf4j
@ResponseResult
@RestController
@requestMapping (value = "/authUser", name = "user controller ")
@api (value = "authUser", tags = "user controller ")
public class UserController {

    @Autowired
    private ITbSysUserService iTbSysUserService;

    @apiOperation (" Get user information by name ")
    @APIIMPLICITParams ({@APIIMPLICITParam (name = "userName", value = "userName", dataType = "String", Required = true)}) @APIIMPLICITParams ({@APIIMPLICITParam (name = "userName", value = "userName", dataType = "String", Required = true)}
    @requestMapping (value = "getByName", method = requestmethod. GET, name = "name ")
    public SysUser getByName(@RequestParam(value = "userName") String userName){
        LambdaQueryWrapper<SysUser> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysUser::getUsername, userName);
        return iTbSysUserService.getOne(wrapper);
    }

    @apiOperation (" Get authorized user information ")
    @APIIMPLICITParams ({@APIIMPLicitParam (name = "principal", value = "current user ", dataType = "Principal", required = true)})
    @requestMapping (value = "current", method = requestmethod. GET, name = "")
    public Principal user(Principal principal){
        // Authorization information
        returnprincipal; }}Copy the code

Request with token

Don’t taketokenThe request of

With a token, but without the ROLE_ADMIN permission

6. Finally aboutFeginCall the serviceTokenThe problem of loss


In microservices, RestTemplate or Fegin is often used to call between services, which leads to a problem. When we call other services, the token will be lost and we have no permission to access them.

So we need to add some interceptors to take our tokens away. The configuration code for Fegin is as follows:

public class FeignRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assertattributes ! =null;
        HttpServletRequest request = attributes.getRequest();    
    // Set the request header
    Enumeration<String> headerNames = request.getHeaderNames();
    if(headerNames ! =null) {
        while(headerNames.hasMoreElements()) { String name = headerNames.nextElement(); String value = request.getHeader(name); requestTemplate.header(name, value); }}// Set the request body, in this case mainly to pass access_token
    Enumeration<String> parameterNames = request.getParameterNames();
    StringBuilder body = new StringBuilder();
    if(parameterNames ! =null) {
        while (parameterNames.hasMoreElements()) {
            String name = parameterNames.nextElement();
            String value = request.getParameter(name);

            // Add the Token to the request header
            if ("access_token".equals(name)) {
                requestTemplate.header("authorization"."Bearer " + value);
            }

            // Add other parameters to the request body
            else {
                body.append(name).append("=").append(value).append("&"); }}}// Set the request body
    if (body.length() > 0) {
        // Remove the last ampersand
        body.deleteCharAt(body.length() - 1); requestTemplate.body(body.toString()); }}}Copy the code

Then add this interceptor to our Fegin request interceptor:

@Configuration
public class FeignRequestConfiguration {
	@Bean
	public RequestInterceptor requestInterceptor(a) {
    	return newFeignRequestInterceptor(); }}Copy the code

7. Spring SecurityShiro


Similarities:

1: indicates authentication

2: authorization function

3: encryption function

4: Session management

5: Cache support

6: rememberMe function…….

Difference:

Advantages:

1. Spring Security is developed based on Spring. If the project uses Spring as the basis, it is more convenient to do permissions with Spring Security, while Shiro needs to integrate development with Spring

2. Spring Security has more features than Shiro, such as Security protection

3: The Spring Security community has more resources than Shiro

Disadvantages:

1: Shiro is relatively simple to configure and use, while Spring Security is complicated to get started

2: Shiro has low dependency and does not require any framework or container and can run independently, while Spring Security relies on the Spring container

8. Database tables

-- used in tests that use HSQL
create table oauth_client_details (
  client_id VARCHAR(256) PRIMARY KEY,
  resource_ids VARCHAR(256),
  client_secret VARCHAR(256),
  scope VARCHAR(256),
  authorized_grant_types VARCHAR(256),
  web_server_redirect_uri VARCHAR(256),
  authorities VARCHAR(256),
  access_token_validity INTEGER,
  refresh_token_validity INTEGER,
  additional_information VARCHAR(4096),
  autoapprove VARCHAR(256));create table oauth_client_token (
  token_id VARCHAR(256),
  token LONGVARBINARY,
  authentication_id VARCHAR(256) PRIMARY KEY,
  user_name VARCHAR(256),
  client_id VARCHAR(256));create table oauth_access_token (
  token_id VARCHAR(256),
  token LONGVARBINARY,
  authentication_id VARCHAR(256) PRIMARY KEY,
  user_name VARCHAR(256),
  client_id VARCHAR(256),
  authentication LONGVARBINARY,
  refresh_token VARCHAR(256));create table oauth_refresh_token (
  token_id VARCHAR(256),
  token LONGVARBINARY,
  authentication LONGVARBINARY
);

create table oauth_code (
  code VARCHAR(256), authentication LONGVARBINARY
);

create table oauth_approvals (
	userId VARCHAR(256),
	clientId VARCHAR(256),
	scope VARCHAR(256),
	status VARCHAR(10),
	expiresAt TIMESTAMP,
	lastModifiedAt TIMESTAMP
);

-- customized oauth_client_details table
create table ClientDetails (
  appId VARCHAR(256) PRIMARY KEY,
  resourceIds VARCHAR(256),
  appSecret VARCHAR(256),
  scope VARCHAR(256),
  grantTypes VARCHAR(256),
  redirectUrl VARCHAR(256),
  authorities VARCHAR(256),
  access_token_validity INTEGER,
  refresh_token_validity INTEGER,
  additionalInformation VARCHAR(4096),
  autoApproveScopes VARCHAR(256));Copy the code

Finally, thank you for your patience after watching, specific requests and some results can be returned to the content of the previous chapter, leaving a “like” collection is your biggest encouragement to me!


🎉 summary:

  • For more references, see here:The Blog of Chan Wing Kai
  • integrationauthThere are some classes that I didn’t put there, so you can read the article, and I’ll post the code latergitOn convenient everyone reference study ~
  • Like the small partner of the blogger can add a concern, a thumbs-up oh, continue to update hey hey!