配置AuthorizationServerConfigurer

  1. import cn.hutool.core.map.MapUtil;
  2. import com.backend.oauth.common.model.JwtTokenConstant;
  3. import com.backend.oauth.common.model.SystemUser;
  4. import com.backend.oauth.service.oauth.JwtTokenUserDetailService;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.context.annotation.Bean;
  7. import org.springframework.context.annotation.Configuration;
  8. import org.springframework.core.io.ClassPathResource;
  9. import org.springframework.http.HttpMethod;
  10. import org.springframework.security.authentication.AuthenticationManager;
  11. import org.springframework.security.crypto.password.PasswordEncoder;
  12. import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
  13. import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
  14. import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
  15. import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
  16. import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
  17. import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
  18. import org.springframework.security.oauth2.provider.ClientDetailsService;
  19. import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;
  20. import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
  21. import org.springframework.security.oauth2.provider.token.TokenEnhancer;
  22. import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
  23. import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
  24. import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
  25. import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;
  26. import javax.sql.DataSource;
  27. import java.security.KeyPair;
  28. import java.util.ArrayList;
  29. import java.util.List;
  30. import java.util.Map;
  31. @Configuration
  32. @EnableAuthorizationServer
  33. public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
  34. /**
  35. * Security的认证管理器,密码模式需要用到
  36. */
  37. @Autowired
  38. private AuthenticationManager authenticationManager;
  39. @Autowired
  40. private JwtTokenUserDetailService jwtTokenUserDetailService;
  41. @Autowired
  42. private DataSource dataSource;
  43. @Autowired
  44. private PasswordEncoder passwordEncoder;
  45. /**
  46. * 客户端存储策略,这里使用内存方式,后续可以存储在数据库
  47. */
  48. @Autowired
  49. private ClientDetailsService clientDetailsService;
  50. /**
  51. * 允许表单认证
  52. */
  53. @Override
  54. public void configure(AuthorizationServerSecurityConfigurer security) {
  55. security
  56. .passwordEncoder(passwordEncoder)
  57. .allowFormAuthenticationForClients();
  58. }
  59. /**
  60. * oauth三方客户端信息配置
  61. * 从oauth_client_details表中获取被允许接入的客户端详情
  62. */
  63. @Override
  64. public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
  65. JdbcClientDetailsService detailsService = new JdbcClientDetailsService(dataSource);
  66. clients.withClientDetails(detailsService);
  67. }
  68. /**
  69. * 配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services)
  70. */
  71. @Override
  72. public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
  73. //访问端点配置
  74. endpoints
  75. //密码模式所需要的authenticationManager
  76. .authenticationManager(authenticationManager)
  77. //oauth token和JWT token转换器
  78. .accessTokenConverter(jwtAccessTokenConverter())
  79. //自定义的用户查询服务
  80. .userDetailsService(jwtTokenUserDetailService)
  81. //令牌管理服务,无论哪种模式都需要
  82. .tokenServices(tokenServices())
  83. //只允许POST提交访问令牌,uri:/oauth/token
  84. .allowedTokenEndpointRequestMethods(HttpMethod.POST);
  85. }
  86. /**
  87. * 令牌管理服务的配置
  88. */
  89. @Bean
  90. public DefaultTokenServices tokenServices() {
  91. DefaultTokenServices services = new DefaultTokenServices();
  92. //JWT token自定义内容增强
  93. TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
  94. List<TokenEnhancer> tokenEnhancers = new ArrayList<>();
  95. tokenEnhancers.add(tokenEnhancer());
  96. tokenEnhancers.add(jwtAccessTokenConverter());
  97. tokenEnhancerChain.setTokenEnhancers(tokenEnhancers);
  98. //添加到增强链
  99. services.setTokenEnhancer(tokenEnhancerChain);
  100. //客户端端配置策略
  101. services.setClientDetailsService(clientDetailsService);
  102. //支持令牌的刷新
  103. services.setSupportRefreshToken(true);
  104. //令牌服务
  105. services.setTokenStore(new JwtTokenStore(jwtAccessTokenConverter()));
  106. //access_token的过期时间
  107. services.setAccessTokenValiditySeconds(60 * 60 * 24);
  108. //refresh_token的过期时间
  109. services.setRefreshTokenValiditySeconds(60 * 60 * 24 * 30);
  110. return services;
  111. }
  112. /**
  113. * 使用非对称加密算法对token签名
  114. * 作用:JWT token和oauth token信息转换
  115. */
  116. @Bean
  117. public JwtAccessTokenConverter jwtAccessTokenConverter() {
  118. JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
  119. converter.setKeyPair(keyPair());
  120. return converter;
  121. }
  122. /**
  123. * 从classpath下的密钥库中获取密钥对(公钥+私钥)
  124. */
  125. @Bean
  126. public KeyPair keyPair() {
  127. KeyStoreKeyFactory factory = new KeyStoreKeyFactory(
  128. new ClassPathResource("scaffold.jks"), "123456".toCharArray());
  129. return factory.getKeyPair(
  130. "scaffold", "123456".toCharArray());
  131. }
  132. /**
  133. * JWT内容增强
  134. * 在JWT token放入一些业务自定义的内容
  135. */
  136. @Bean
  137. public TokenEnhancer tokenEnhancer() {
  138. return (accessToken, authentication) -> {
  139. Map<String, Object> additionalInfo = MapUtil.newHashMap();
  140. Object principal = authentication.getUserAuthentication().getPrincipal();
  141. if(principal instanceof SystemUser){
  142. SystemUser user = (SystemUser) principal;
  143. additionalInfo.put(JwtTokenConstant.USER_ID, user.getUserId());
  144. additionalInfo.put(JwtTokenConstant.USER_NAME, user.getUsername());
  145. }
  146. ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
  147. return accessToken;
  148. };
  149. }
  150. }

配置securityConfig

import com.backend.oauth.service.oauth.JwtTokenUserDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
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.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.PasswordEncoder;

/**
 * web路径安全控制
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtTokenUserDetailService jwtTokenUserDetailService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
//                .formLogin().permitAll()
//                .and().httpBasic().and()
                .authorizeRequests().requestMatchers(EndpointRequest.toAnyEndpoint()).permitAll()
                .and()
                .authorizeRequests().antMatchers("/oauth/**","/getPublicKey").permitAll()
                // 其余所有请求全部需要鉴权认证
                .anyRequest().authenticated()
                //关闭跨域保护
                .and().csrf().disable();
    }


    public static void main(String[] args) {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String encode = encoder.encode("123");
        System.out.println(encode);
        boolean matches = encoder.matches("123", "$2a$10$q.tlmZjrZHYDNbna.SQ7ye6AhSR2/w2aCkzK5eMCxL5Q1HgumNOvK");
        System.out.println(matches);
    }
    /**
     * 密码加密算法
     */
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        //从数据库中查询用户信息
        auth.userDetailsService(jwtTokenUserDetailService);
    }


    /**
     * AuthenticationManager对象在OAuth2认证服务中要使用,提前放入IOC容器中
     * Oauth的密码模式需要
     */
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}
  1. 提供JWT token对象
  2. 提供filter过滤器,作用
    1. 黑白名单
    2. 特定url放行
    3. 其他特殊需求,限流,匿名用户。。。
  3. 提供认证用的provider,作用
    1. 根据认证模式判定用户是否能颁发令牌
  4. 登录成功处理器
  5. 登录失败处理器

image.png