配置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
@EnableAuthorizationServer
public 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,作用
- 根据认证模式判定用户是否能颁发令牌
- 登录成功处理器
- 登录失败处理器