配置AuthorizationServerConfigurer
import cn.hutool.core.map.MapUtil;import com.backend.oauth.common.model.JwtTokenConstant;import com.backend.oauth.common.model.SystemUser;import com.backend.oauth.service.oauth.JwtTokenUserDetailService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.core.io.ClassPathResource;import org.springframework.http.HttpMethod;import org.springframework.security.authentication.AuthenticationManager;import org.springframework.security.crypto.password.PasswordEncoder;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.ClientDetailsService;import org.springframework.security.oauth2.provider.client.JdbcClientDetailsService;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.store.JwtAccessTokenConverter;import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory;import javax.sql.DataSource;import java.security.KeyPair;import java.util.ArrayList;import java.util.List;import java.util.Map;@Configuration@EnableAuthorizationServerpublic class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { /** * Security的认证管理器,密码模式需要用到 */ @Autowired private AuthenticationManager authenticationManager; @Autowired private JwtTokenUserDetailService jwtTokenUserDetailService; @Autowired private DataSource dataSource; @Autowired private PasswordEncoder passwordEncoder; /** * 客户端存储策略,这里使用内存方式,后续可以存储在数据库 */ @Autowired private ClientDetailsService clientDetailsService; /** * 允许表单认证 */ @Override public void configure(AuthorizationServerSecurityConfigurer security) { security .passwordEncoder(passwordEncoder) .allowFormAuthenticationForClients(); } /** * oauth三方客户端信息配置 * 从oauth_client_details表中获取被允许接入的客户端详情 */ @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { JdbcClientDetailsService detailsService = new JdbcClientDetailsService(dataSource); clients.withClientDetails(detailsService); } /** * 配置授权(authorization)以及令牌(token)的访问端点和令牌服务(token services) */ @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) { //访问端点配置 endpoints //密码模式所需要的authenticationManager .authenticationManager(authenticationManager) //oauth token和JWT token转换器 .accessTokenConverter(jwtAccessTokenConverter()) //自定义的用户查询服务 .userDetailsService(jwtTokenUserDetailService) //令牌管理服务,无论哪种模式都需要 .tokenServices(tokenServices()) //只允许POST提交访问令牌,uri:/oauth/token .allowedTokenEndpointRequestMethods(HttpMethod.POST); } /** * 令牌管理服务的配置 */ @Bean public DefaultTokenServices tokenServices() { DefaultTokenServices services = new DefaultTokenServices(); //JWT token自定义内容增强 TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain(); List<TokenEnhancer> tokenEnhancers = new ArrayList<>(); tokenEnhancers.add(tokenEnhancer()); tokenEnhancers.add(jwtAccessTokenConverter()); tokenEnhancerChain.setTokenEnhancers(tokenEnhancers); //添加到增强链 services.setTokenEnhancer(tokenEnhancerChain); //客户端端配置策略 services.setClientDetailsService(clientDetailsService); //支持令牌的刷新 services.setSupportRefreshToken(true); //令牌服务 services.setTokenStore(new JwtTokenStore(jwtAccessTokenConverter())); //access_token的过期时间 services.setAccessTokenValiditySeconds(60 * 60 * 24); //refresh_token的过期时间 services.setRefreshTokenValiditySeconds(60 * 60 * 24 * 30); return services; } /** * 使用非对称加密算法对token签名 * 作用:JWT token和oauth token信息转换 */ @Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setKeyPair(keyPair()); return converter; } /** * 从classpath下的密钥库中获取密钥对(公钥+私钥) */ @Bean public KeyPair keyPair() { KeyStoreKeyFactory factory = new KeyStoreKeyFactory( new ClassPathResource("scaffold.jks"), "123456".toCharArray()); return factory.getKeyPair( "scaffold", "123456".toCharArray()); } /** * JWT内容增强 * 在JWT token放入一些业务自定义的内容 */ @Bean public TokenEnhancer tokenEnhancer() { return (accessToken, authentication) -> { Map<String, Object> additionalInfo = MapUtil.newHashMap(); Object principal = authentication.getUserAuthentication().getPrincipal(); if(principal instanceof SystemUser){ SystemUser user = (SystemUser) principal; additionalInfo.put(JwtTokenConstant.USER_ID, user.getUserId()); additionalInfo.put(JwtTokenConstant.USER_NAME, user.getUsername()); } ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo); return accessToken; }; }}
配置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();
}
}
- 提供JWT token对象
- 提供filter过滤器,作用
- 黑白名单
- 特定url放行
- 其他特殊需求,限流,匿名用户。。。
- 提供认证用的provider,作用
- 根据认证模式判定用户是否能颁发令牌
- 登录成功处理器
- 登录失败处理器
