1,oauth2需要配置三部分
(1)配置spring security 因为oauth2是基于security的
用来验证用户名和密码的
(2)配置认证服务器
用来分发token并且存储token,因为本地没有安装redis,所以本文采用数据库的形式存储token
(3)配置资源服务器
保护被需要访问的资源,解析token
导入依赖
org.springframework.boot spring-boot-starter-security org.springframework.boot spring-boot-starter-data-redis org.springframework.boot spring-boot-starter-actuator org.springframework.security.oauth spring-security-oauth2 RELEASE org.mybatis.spring.boot mybatis-spring-boot-starter 1.3.0 mysql mysql-connector-java
一,配置认证服务器
//认证服务器,用来认证用户分发token,并存储 @Configuration @EnableAuthorizationServer public class MyAuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; // @Autowired // RedisConnectionFactory redisConnectionFactory; @Autowired private DataSource dataSource; @Override //配置令牌端点的安全约束 public void configure(AuthorizationServerSecurityConfigurer security) throws Exception { //允许表单登录 security.allowFormAuthenticationForClients(); } @Override //配置客户端详情服务 两种客户端模式 password 和 client public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() //clientid .withClient("client_2") //resourceIds自定义随便起 .resourceIds("abc") //认证模式为password模式 .authorizedGrantTypes("password", "refresh_token") .scopes("select") .authorities("client") //由于设置的加密方式,所以client密码和用户的password都需要加密 //client密码 .secret(new BCryptPasswordEncoder().encode("123456")); } @Bean public TokenStore tokenStore() { return new JdbcTokenStore(dataSource); } //设置token 比如token的有效时长等 @Bean public AuthorizationServerTokenServices tokenServices() { DefaultTokenServices defaultTokenServices = new DefaultTokenServices(); defaultTokenServices.setAccessTokenValiditySeconds(1000000); defaultTokenServices.setRefreshTokenValiditySeconds(200000); defaultTokenServices.setSupportRefreshToken(true); defaultTokenServices.setReuseRefreshToken(false); defaultTokenServices.setTokenStore(tokenStore()); return defaultTokenServices; } @Override //配置授权以及令牌的访问端点和令牌服务 public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { //redis token存储 // endpoints .tokenStore(new RedisTokenStore(redisConnectionFactory)) // .authenticationManager(authenticationManager); //数据库存储 endpoints.tokenStore(tokenStore()) .authenticationManager(authenticationManager) //设置访问token端点的方法类型,允许get提交 .allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.GET); } }
二,配置spring security
@Configuration @EnableWebSecurity public class MySecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .requestMatchers().anyRequest() //设置符合条件的端点通过,不被保护 .and().authorizeRequests().antMatchers("/oauth/*").permitAll(); } //设置内存用户(本文把用户信息存到内存,也可以采用查询数据库的方式) @Bean @Override protected UserDetailsService userDetailsService() { InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); manager.createUser(User.withUsername("user_1").password(new BCryptPasswordEncoder().encode("123456")).authorities("USER").build()); return manager; } //这一步的配置是必不可少的,否则SpringBoot会自动配置一个AuthenticationManager,覆盖掉内存中的用户 @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { AuthenticationManager manager = super.authenticationManagerBean(); return manager; } @Bean PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } //设置密码加密规则 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder()); } //设置不用密码加密 不推荐 // @Bean // public static NoOpPasswordEncoder passwordEncoder() { // return (NoOpPasswordEncoder) NoOpPasswordEncoder.getInstance(); // } }
三,配置资源服务器
//资源服务器用来验证token @Configuration @EnableResourceServer public class MyResourceServerConfigurer extends ResourceServerConfigurerAdapter { @Override public void configure(ResourceServerSecurityConfigurer resources) throws Exception { resources.resourceId("abc").stateless(true); } @Override public void configure(HttpSecurity http) throws Exception { http .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) .and() .requestMatchers().anyRequest() .and() .anonymous() .and() .authorizeRequests() .antMatchers("/abc/**").authenticated();//配置abc访问控制,必须认证过后才可以访问 } }
四,编写需要收保护的资源
@RestController public class CeShiapi { Logger logger = LoggerFactory.getLogger(CeShiapi.class); @GetMapping("/abc") public String testSwagger() { logger.info("我是日志"); System.out.println("aaaaaa"); return "bbbbb"; } }
数据库存储token的表结构一共是两张表
DROP TABLE IF EXISTS `oauth_access_token`; CREATE TABLE `oauth_access_token` ( `token_id` varchar(256) DEFAULT NULL, `token` blob, `authentication_id` varchar(256) DEFAULT NULL, `user_name` varchar(256) DEFAULT NULL, `client_id` varchar(256) DEFAULT NULL, `authentication` blob, `refresh_token` varchar(256) DEFAULT NULL ) ENGINE=MyISAM DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `oauth_refresh_token`; CREATE TABLE `oauth_refresh_token` ( `token_id` varchar(256) DEFAULT NULL, `token` blob, `authentication` blob ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
启动项目
访问http://localhost:8111/oauth/token?username=user_1&password=123456&grant_type=password&scope=select&client_id=client_2&client_secret=123456
结果
访问资源http://localhost:8111/abc 受保护
加上token http://localhost:8111/abc?access_token=cd43d91f-c222-4db1-84df-a2dcb312f029
访问成功!