在阅读本文章前,我假设读者已经有了OAuth2、SpringBoot和Spring Security基础。下面我将会从编码的顺序来讲,如何通过Spring Security OAuth2逐步实现OAuth2密码模式。

一、Maven 依赖

这里只列出一些主要的jar包。

1.SpringBoot

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.4.RELEASE</version>
    <relativePath/>
</parent>

2.Spring Security

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

3.Spring Security OAuth2

<dependency>
    <groupId>org.springframework.security.oauth</groupId>
    <artifactId>spring-security-oauth2</artifactId>
    <version>2.3.8.RELEASE</version>
</dependency>

4.Redis

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

5.lombok

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.20</version>
</dependency>

6.Swagger

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.9.2</version>
</dependency>

二、Spring Security OAuth2 表结构

以下俩张表必须要有,这里我用的是Oracle。另外,可以根据业务添加其他的拓展字段。
1.应用表

create table oauth_client_details (
  client_id               varchar2(128) not null
    constraint pk_oauth_client_details
    primary key,
  resource_ids            varchar2(128) default null,
  client_secret           varchar2(128) default null,
  scope                   varchar2(128) default null,
  authorized_grant_types  varchar2(128)  default null,
  web_server_redirect_uri varchar2(128)  default null,
  authorities             varchar2(128)  default null,
  access_token_validity   number(9)       default null,
  refresh_token_validity  number(9)       default null,
  additional_information  varchar2(4000) default null,
  autoapprove             varchar2(128)  default null
);
comment on table oauth_client_details is '应用表';
comment on column oauth_client_details.client_id is '应用id';
comment on column oauth_client_details.resource_ids is '授权资源id集合';
comment on column oauth_client_details.client_secret is '应用密钥';
comment on column oauth_client_details.scope is '授权作用域';
comment on column oauth_client_details.authorized_grant_types is '授权允许类型';
comment on column oauth_client_details.web_server_redirect_uri is '授权回调地址';
comment on column oauth_client_details.authorities is '拥有权限集合';
comment on column oauth_client_details.access_token_validity is 'access_token有效期(秒)';
comment on column oauth_client_details.refresh_token_validity is 'refresh_token有效期(秒)';
comment on column oauth_client_details.additional_information is '附加信息(预留)';
comment on column oauth_client_details.autoapprove is '自动同意授权(true,false,read,write)';

2.用户表

create table client_user (
  user_id          number(9) not null
    constraint pk_client_user
    primary key,
  username         varchar2(128),
  password         varchar2(128),
  client_id        varchar2(128),
  status           number(1)
);

comment on table client_user is '用户表';
comment on column client_user.user_id is '用户id';
comment on column client_user.username is '用户名';
comment on column client_user.password is '密码';
comment on column client_user.client_id is '应用id';
comment on column client_user.status is '状态:0-已禁用,1-已启用';
alter table client_user add constraint uq_client_user unique (username);
create sequence seq_client_user
maxvalue 999999999;
/

三、Java代码

1.配置Swagger

SwaggerConfig.java

package com.leven.auth.api.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger.web.UiConfigurationBuilder;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
 * swagger文档配置
 * @author Leven
 * @date 2020-04-15
 */
@Configuration
@EnableSwagger2
@Profile("dev")
public class SwaggerConfig {
    /**
     * 添加摘要信息(Docket)
     */
    @Bean
    public Docket controllerApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(new ApiInfoBuilder()
                        .title("OAuth2之密码模式")
                        .description("接口文档")
                        .contact(new Contact("Leven", null, "leven0106@163.com"))
                        .version("V1.0")
                        .build())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.leven.auth.api.controller"))
                .paths(PathSelectors.any())
                .build();
    }

    @Bean
    public UiConfiguration uiConfiguration() {
        return UiConfigurationBuilder.builder().defaultModelsExpandDepth(0).build();
    }
}

2.配置Redis

RedisConfig.java

package com.leven.auth.api.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * Redis缓存配置
 * @author Leven
 * @date 2020-04-08
 */
@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);

        GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

3.配置Security

WebSecurityConfiguration.java

package com.leven.auth.api.security;

import com.leven.auth.api.security.custom.CustomAuthenticationProvider;
import com.leven.auth.model.constant.AuthConstant;
import lombok.extern.slf4j.Slf4j;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.csrf.CookieCsrfTokenRepository;

import java.util.HashMap;
import java.util.Map;

/**
 * spring security核心配置
 * @author Leven
 * @date 2019-08-06
 */
@Slf4j
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private CustomAuthenticationProvider customAuthenticationProvider;

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        Map<String, PasswordEncoder> idToPasswordEncoder = new HashMap<>(2);
        idToPasswordEncoder.put(AuthConstant.ID_FOR_ENCODE_DEFAULT, new BCryptPasswordEncoder());
        return new DelegatingPasswordEncoder(AuthConstant.ID_FOR_ENCODE_DEFAULT, idToPasswordEncoder);
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) {
        auth.authenticationProvider(customAuthenticationProvider);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 不需要拦截的请求
                .antMatchers("/**").permitAll()
                // CSRF防护
                .and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
    }
}

CustomAuthenticationProvider.java

package com.leven.auth.api.security.custom;

import com.leven.commons.model.exception.SPIException;
import com.leven.auth.core.service.ClientUserService;
import com.leven.auth.model.constant.AuthExceptionCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

/**
 * 自定义认证服务实现
 * @author Leven
 * @date 2019-08-06
 */
@Slf4j
@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {

    @Autowired
    private ClientUserService clientUserService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        UsernamePasswordAuthenticationToken token = (UsernamePasswordAuthenticationToken) authentication;
        String username = token.getName();
        UserDetails userDetails = null;

        if (username != null) {
            userDetails = clientUserService.loadUserByUsername(username);
        }

        if (userDetails == null) {
            throw new SPIException(AuthExceptionCode.USERNAME_NOT_FOUND);
        } else if (!userDetails.isEnabled()) {
            throw new SPIException(AuthExceptionCode.ACCOUNT_DISABLED);
        } else if (!userDetails.isAccountNonExpired()) {
            throw new SPIException(AuthExceptionCode.ACCOUNT_EXPIRED);
        } else if (!userDetails.isAccountNonLocked()) {
            throw new SPIException(AuthExceptionCode.ACCOUNT_LOCKED);
        } else if (!userDetails.isCredentialsNonExpired()) {
            throw new SPIException(AuthExceptionCode.CREDENTIALS_EXPIRED);
        }

        //数据库存储的密文
        String password = userDetails.getPassword();
        //用户输入的明文
        String plainPwd = (String)token.getCredentials();
        if (StringUtils.isBlank(plainPwd)) {
            throw new SPIException(AuthExceptionCode.PWD_IS_EMPTY);
        }
        //校验密码是否正确
        if (!passwordEncoder.matches(plainPwd, password)) {
            throw new SPIException(AuthExceptionCode.BAD_CREDENTIALS);
        }

        //授权
        return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
    }

    @Override
    public boolean supports(Class<?> aClass) {
        //返回true后才会执行上面的authenticate方法,这步能确保authentication能正确转换类型
        return UsernamePasswordAuthenticationToken.class.equals(aClass);
    }
}

ClientUserService

package com.leven.auth.core.service;

import org.springframework.security.core.userdetails.UserDetailsService;

/**
 * 授权用户接口
 * @author Leven
 * @date 2019-03-20
 */
public interface ClientUserService extends UserDetailsService {
}

ClientUserServiceImpl

package com.leven.auth.core.service.impl;

import com.leven.commons.model.exception.SPIException;
import com.leven.auth.core.mapper.ClientUserMapper;
import com.leven.auth.core.service.ClientUserService;
import com.leven.auth.model.constant.AuthExceptionCode;
import com.leven.auth.model.enums.ClientUserStatusEnum;
import com.leven.auth.model.pojo.dto.ClientUserDTO;
import com.leven.auth.model.pojo.query.ClientUserQuery;
import com.leven.auth.model.pojo.security.ClientUserDetails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
/**
 * 授权用户接口实现
 * @author Leven
 * @date 2019-03-20
 */
@Service
public class ClientUserServiceImpl implements ClientUserService, UserDetailsService {
    
    @Autowired
    private ClientUserMapper clientUserMapper;

    /**
     * 根据用户名查找授权用户
     * @param username 用户名
     * @return 授权应用用户详情
     * @throws UsernameNotFoundException 用户不存在异常
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        ClientUserQuery clientUser = new ClientUserQuery();
        clientUser.setUsername(username);
        ClientUserDTO userDTO = clientUserMapper.getByQuery(clientUser);
        if (userDTO == null) {
            throw new SPIException(AuthExceptionCode.CLIENT_USER_NOT_EXISTS);
        }
        //设置用户
        boolean enabled = ClientUserStatusEnum.BAN.getValue() != userDTO.getStatus();
        return new ClientUserDetails(userDTO, enabled, true, true,
                true, null);
    }
}

4.配置授权服务

AuthorizationServerConfiguration.java

package com.leven.auth.api.security;

import com.leven.auth.api.security.custom.CustomAccessDeniedHandler;
import com.leven.auth.api.security.custom.CustomTokenEnhancer;
import com.leven.auth.api.security.custom.CustomWebResponseExceptionTranslator;
import com.leven.auth.core.service.ClientUserService;
import com.leven.auth.model.constant.AuthConstant;
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.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.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
import org.springframework.security.web.AuthenticationEntryPoint;

import javax.sql.DataSource;

/**
 * Oauth2.0 认证授权服务配置
 * @author Leven
 * @date 2019-08-02
 */
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private ClientUserService clientUserService;

    @Autowired
    private CustomWebResponseExceptionTranslator webResponseExceptionTranslator;

    /**
     * 注入authenticationManager
     * 来支持 password grant type
     */
    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private CustomTokenEnhancer customTokenEnhancer;

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Autowired
    private AuthenticationEntryPoint authenticationEntryPoint;

    @Autowired
    private CustomAccessDeniedHandler customAccessDeniedHandler;

    /**
     * 声明TokenStore实现
     * @return
     */
    @Bean
    public TokenStore tokenStore() {
        RedisTokenStore tokenStore = new RedisTokenStore(redisConnectionFactory);
        tokenStore.setPrefix(AuthConstant.APPLICATION + ":");
        return tokenStore;
    }

    /**
     * 声明 ClientDetails实现
     * @return
     */
    @Bean
    public ClientDetailsService clientDetails() {
        return new JdbcClientDetailsService(dataSource);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.withClientDetails(clientDetails());
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) {
        security.authenticationEntryPoint(authenticationEntryPoint).accessDeniedHandler(customAccessDeniedHandler);
    }

    @SuppressWarnings("unchecked")
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints.authenticationManager(authenticationManager);
        endpoints.userDetailsService(clientUserService);
        endpoints.exceptionTranslator(webResponseExceptionTranslator);
        endpoints.tokenStore(tokenStore());
        endpoints.tokenEnhancer(customTokenEnhancer);
    }
}

CustomWebResponseExceptionTranslator.java

package com.leven.auth.api.security.custom;

import com.leven.commons.core.web.bean.OuterResult;
import com.leven.commons.model.exception.BasicEcode;
import com.leven.commons.model.exception.SPIException;
import com.leven.auth.model.constant.AuthExceptionCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.oauth2.provider.error.WebResponseExceptionTranslator;
import org.springframework.stereotype.Component;

/**
 * 认证相关的异常处理
 * @author Leven
 * @date 2019-08-07
 */
@Slf4j
@Component
public class CustomWebResponseExceptionTranslator implements WebResponseExceptionTranslator {

    @Override
    public ResponseEntity translate(Exception e) {
        log.error("web response exception translator:", e);
        OuterResult result;
        if (e instanceof SPIException) {
            SPIException spi = (SPIException) e;
            result = new OuterResult(spi.getEcode(), spi.getMsg());
        } else {
            result = new OuterResult(AuthExceptionCode.OAUTH2_ERROR, BasicEcode.getMsg(AuthExceptionCode.OAUTH2_ERROR));
        }
        return new ResponseEntity<>(result, HttpStatus.UNAUTHORIZED);
    }
}

CustomTokenEnhancer.java

package com.leven.auth.api.security.custom;

import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * 自定义Token增强
 * @author Leven
 * @date 2019-08-07
 */
@Component
public class CustomTokenEnhancer implements TokenEnhancer {

    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        if (accessToken instanceof DefaultOAuth2AccessToken) {
            DefaultOAuth2AccessToken token = ((DefaultOAuth2AccessToken) accessToken);
            Map<String, Object> additionalInformation = new HashMap<>(1);
            additionalInformation.put("expiration", token.getExpiration());
            token.setAdditionalInformation(additionalInformation);
            return token;
        }
        return accessToken;
    }
}

CustomAccessDeniedHandler.java

package com.leven.auth.api.security.custom;

import com.leven.auth.api.helper.ResponseHelper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 权限相关的异常处理
 * @author Leven
 * @date 2019-08-02
 */
@Slf4j
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) {
        log.error("access denied exception:", e);
        ResponseHelper.fail(request, response, HttpStatus.FORBIDDEN.getReasonPhrase(), e.getMessage());
    }
}

ResponseHelper.java

package com.leven.auth.security.custom;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.leven.commons.core.web.bean.OuterResult;
import com.leven.commons.model.exception.BasicEcode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 自定义响应JSON
 * @author Leven
 */
@Slf4j
public class ResponseHelper {

    private static final String CONTENT_TYPE = "application/json;charset=UTF-8";

    private ResponseHelper(){}

    /**
     * 成功返回结果
     * @param response
     * @param obj
     * @throws IOException
     */
    public static void success(HttpServletResponse response, Object obj) {
        print(response, BasicEcode.SUCCESS, null, obj);
    }

    /**
     * 异常返回结果
     * @param response
     * @param ecode
     * @throws IOException
     */
    public static void error(HttpServletResponse response, String ecode) {
        error(response, ecode, BasicEcode.getMsg(ecode));
    }

    /**
     * 异常返回结果
     * @param response
     * @param ecode
     * @throws IOException
     */
    public static void error(HttpServletResponse response, String ecode, String msg) {
        print(response, ecode, msg, null);
    }

    /**
     * 异常返回结果
     * @param response
     * @param ecode
     * @throws IOException
     */
    public static void error(HttpServletResponse response, String ecode, Object... args) {
        print(response, ecode, null, null, args);
    }

    private static void print(HttpServletResponse response, String ecode, String msg, Object data, Object... args) {
        OuterResult result = OuterResult.newInstance();
        result.setEcode(ecode);
        if (StringUtils.isBlank(msg)) {
            msg = BasicEcode.getMsg(ecode);
        }
        if (args != null && args.length > 0) {
            msg = String.format(msg, args);
        }
        result.setMsg(msg);
        result.setData(data);
        response.setContentType(CONTENT_TYPE);
        try {
            response.getWriter().print(JSON.toJSONString(result, SerializerFeature.WriteMapNullValue));
        } catch (IOException e) {
            log.error("打印返回结果报错:", e);
        }
    }
}

5.配置资源服务

ResourceServerConfiguration.java

package com.leven.auth.api.security;

import com.leven.auth.api.security.custom.CustomAccessDeniedHandler;
import org.springframework.beans.factory.annotation.Autowired;
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.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.web.AuthenticationEntryPoint;

/**
 * Oauth2.0 资源服务配置
 * @author Leven
 * @date 2019-08-02
 */
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

    @Autowired
    private AuthenticationEntryPoint authenticationEntryPoint;

    @Autowired
    private CustomAccessDeniedHandler customAccessDeniedHandler;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers("/**").authenticated();
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) {
        resources.authenticationEntryPoint(authenticationEntryPoint).accessDeniedHandler(customAccessDeniedHandler);
    }
}

6.Swagger文档过滤拦截:排除静态资源过滤

WebMvcConfiguration.java

package com.leven.auth.api.security;

import com.leven.auth.api.interceptor.SecurityInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
 * spring mvc配置
 * @author Leven
 * @date 2019-08-05
 */
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {

    @Autowired
    private SecurityInterceptor transformInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(transformInterceptor)
                .excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**")
                .addPathPatterns("/**");
    }
}

7.启动类

AuthApiApplication.java

package com.leven.auth.api;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import tk.mybatis.spring.annotation.MapperScan;

/**
 * SpringBoot启动类
 * @author Leven
 * @date 2019-03-20
 */
@SpringBootApplication(scanBasePackages = {"com.leven"})
@MapperScan(basePackages = { "com.leven.auth.core.mapper" })
@ServletComponentScan
@EnableTransactionManagement
@EnableAsync
public class AuthApiApplication {
    public static void main(String[] args) {
        SpringApplication.run(AuthApiApplication.class, args);
    }
}

8.数据层(tk.mybatis)和application.yml我就不写了......

四、后续

本文为思否原创文章,未经允许不得转载。
如读者发现有错误,欢迎留言!


Leven
10 声望1 粉丝

德以明理、学以精工


引用和评论

0 条评论