Spring Cloud OAuth2.0安全之路(一) 搭建OAuth2.0服务
1.创建SpringBoot项目,导入相关的包,工程结构如下:
2.pom文件代码示例:
<parent>
<artifactId>cloud-root</artifactId>
<groupId>com.cto.cloud</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-jdbc</artifactId>
</dependency>
</dependencies>
parent在父pom中有引入公共jar,核心内容如下:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Greenwich.SR2</spring-cloud.version>
<spring-boot.version>2.1.6.RELEASE</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
3.配置AOuth2.0
先贴代码
@Configuration
@EnableJdbcHttpSession
@EnableAuthorizationServer
public class AuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private DataSource dataSource;
@Autowired
private UserDetailsService userDetailsService;
@Bean
public TokenStore tokenStore() {
// return new JdbcTokenStore(dataSource);
return new JwtTokenStore(jwtAccessTokenConverter());
}
@Bean
public JwtAccessTokenConverter jwtAccessTokenConverter(){
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
// converter.setSigningKey("qRU5LLDPOJ0s7niuE!LyjETh*EPKdOE9TBURAhWS2n3fAXXy#!mqdPDljOHInWGf"); //签名的key
KeyStoreKeyFactory keyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource("594cto.jks"), "123456".toCharArray());
converter.setKeyPair(keyStoreKeyFactory.getKeyPair("594cto"));
return converter;
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.userDetailsService(userDetailsService)
.tokenStore(tokenStore())
.tokenEnhancer(jwtAccessTokenConverter())
.authenticationManager(authenticationManager);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
/* clients.inMemory()
.withClient("order") //应用ID
.secret(passwordEncoder.encode("123456")) //应用密码
.scopes("read","write") //应用权限
.accessTokenValiditySeconds(1800) //token的失效时间
.resourceIds("order-server") //允许访问的服务ID
.authorizedGrantTypes("password"); //授权方式*/
clients.jdbc(dataSource);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("isAuthenticated()") //暴露验证服务/oauth/token_key permitAll()为关闭
.checkTokenAccess("isAuthenticated()");//暴露验证服务/oauth/check_token
}
}
TokenStore我采用了jwt的方式,也可以用jdbc或者redis
JwtAccessTokenConverter 配置JWT,其中.jks密钥文件可以通过keytool命令生成,具体可以自行查一下资料,一段命令即可。
ClientDetailsServiceConfigurer 该配置我采用了jdbc存库的方式,Spring已经写好了所有的方法,只需要自己新建数据表即可,如下:
CREATE TABLE `oauth_client_details` (
`client_id` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT '服务ID',
`resource_ids` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '可访问哪些服务,为空则是全部',
`client_secret` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '访问密码',
`scope` varchar(256) COLLATE utf8mb4_general_ci DEFAULT NULL,
`authorized_grant_types` varchar(256) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '加密方式一共四种,目前使用了两种',
`web_server_redirect_uri` varchar(256) COLLATE utf8mb4_general_ci DEFAULT NULL,
`authorities` varchar(256) COLLATE utf8mb4_general_ci DEFAULT NULL,
`access_token_validity` int(11) DEFAULT NULL COMMENT 'token有效期',
`refresh_token_validity` int(11) DEFAULT NULL COMMENT 'refreshToken有效期',
`additional_information` varchar(4096) COLLATE utf8mb4_general_ci DEFAULT NULL,
`autoapprove` varchar(256) COLLATE utf8mb4_general_ci DEFAULT NULL,
PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
INSERT INTO `cloud-security`.`oauth_client_details`(`client_id`, `resource_ids`, `client_secret`, `scope`, `authorized_grant_types`, `web_server_redirect_uri`, `authorities`, `access_token_validity`, `refresh_token_validity`, `additional_information`, `autoapprove`) VALUES ('order', NULL, '$2a$10$I/Nei5gpxssWZchTx5Or6O4KQlcI5PW7FgbUM2.bRE7ZJHf65QAQW', 'read,write', 'password,refresh_token', NULL, NULL, 3600, 7200, NULL, NULL);
INSERT INTO `cloud-security`.`oauth_client_details`(`client_id`, `resource_ids`, `client_secret`, `scope`, `authorized_grant_types`, `web_server_redirect_uri`, `authorities`, `access_token_validity`, `refresh_token_validity`, `additional_information`, `autoapprove`) VALUES ('price', NULL, '$2a$10$I/Nei5gpxssWZchTx5Or6O4KQlcI5PW7FgbUM2.bRE7ZJHf65QAQW', 'read,write', 'password,refresh_token', NULL, NULL, 3600, 7200, NULL, NULL);
INSERT INTO `cloud-security`.`oauth_client_details`(`client_id`, `resource_ids`, `client_secret`, `scope`, `authorized_grant_types`, `web_server_redirect_uri`, `authorities`, `access_token_validity`, `refresh_token_validity`, `additional_information`, `autoapprove`) VALUES ('zuul', NULL, '$2a$10$I/Nei5gpxssWZchTx5Or6O4KQlcI5PW7FgbUM2.bRE7ZJHf65QAQW', 'read,write', 'password,refresh_token', NULL, NULL, 3600, 7200, NULL, NULL);
WebSecurityConfigurer配置如下:
@Configuration
@EnableWebSecurity
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
UserDetailsService需要手动去实现一下,验证用户信息在此处做
@Component
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private FrontUserMapper frontUserMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
FrontUser frontUser = frontUserMapper.queryFrontUserByName(username);
if(frontUser == null){
throw new OAuth2Exception("用户名不存在");
}
return User.withUsername(username)
.password(passwordEncoder.encode(frontUser.getPassword()))
.authorities("ROLE_ADMIN")
.build();
}
}
FrontUserMapper
@Repository
public class FrontUserMapper {
@Autowired
private JdbcTemplate jdbcTemplate;
public FrontUser queryFrontUserByName(String username){
List<FrontUser> list = jdbcTemplate.query("select * from front_user where user_name = ?",new BeanPropertyRowMapper<>(FrontUser.class), username);
if(list != null && list.size() > 0){
return list.get(0);
}
return null;
}
}
Application启动类没变化,默认的就可以
@SpringBootApplication
public class AuthApplication {
public static void main(String[] args) {
SpringApplication.run(AuthApplication.class, args);
}
}
yml配置文件
spring:
application:
name: auth
datasource:
url: jdbc:mysql://localhost:3306/cloud-security?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&useSSL=false&allowPublicKeyRetrieval=true
username: root
password: root1234
driver-class-name: com.mysql.cj.jdbc.Driver
server:
port: 9090
servlet:
session:
timeout: 3600
至此,验证服务搭建完毕。
第一次写博客,主要目的是强迫自己加深理解,如果文中有不对的地方,欢迎各大佬指教。
有兴趣一起学的小伙伴可以加好友一起学习。
下一章写一下网关的配置
源码地址:https://gitee.com/bigger-xu/oauthZuul
喜欢的小伙伴可以请关注我的站点:我的站点