最近在项目中使用了OAuth2做鉴权服务,将主要步骤整理一下:
使用Spring Cloud OAuth2起步依赖会比较简单,在pom.xml中添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>
//父项目中使用了cloud版本 Brixton.SR5
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Brixton.SR5</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
加入Spring Cloud OAuth2后会包含Spring-Security,Spring-Security-OAuth2等依赖.
OAuth2两部分AuthorizationServer和ResourceServer,使用注解@EnableAuthorizationServer的类实现AuthorizationServerConfigurer(一般AuthorizationServerConfigurerAdapter)接口,就可以对授权服务进行配置.
主要配置三个部分,ClientDetailsServiceConfigurer客户端连接详情,grant_type,scopes等,AuthorizationServerSecurityConfigurer,访问token接口的安全限制,如tokenKeyAccess,checkTokenAccess,AuthorizatinoServerEndpointsConfigurer,授权和token的服务,如authenticationManager,passwordEncode,userDetailsService.
@Configuration
@EnableAuthorizationServer
protected static class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
private TokenStore tokenStore = new InMemoryTokenStore();
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Autowired
private AuthUserDetailsService userDetailsService;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("browser")
.authorizedGrantTypes("refresh_token", "password")
.scopes("ui");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(tokenStore)
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer
.tokenKeyAccess("permitAll()")
.checkTokenAccess("isAuthenticated()");
}
}
配置WebSecurityConfig,是token服务能够访问.
@Configuration
@EnableWebSecurity
protected static class webSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private AuthUserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().anyRequest().authenticated()
.and()
.csrf().disable();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
将配置类集成到Application.java类中,
@SpringBootApplication
@EnableResourceServer
@EnableDiscoveryClient
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
protected static class webSecurityConfig extends WebSecurityConfigurerAdapter;
protected static class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter;
}
实现UserDetailsService类,
@Service
public class AuthUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository repository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = repository.findByUsername(username);
if (user == null) {
throw new UsernameNotFoundException(username);
}
return user;
}
}
通过JPA查询数据库当前用户,密码匹配即可生成access-token.
测试, 通过curl命令发送POST请求到接口uaa/oauth/token:
curl -H "Authorization:Basic YnJvd3Nlcjo=" -d "grant_type=password&scope=ui&username=test01&password=123456" localhost:4000/uaa/oauth/token
//得到结果
{"access_token":"18471940-5d80-4f17-8b57-8bb920214121","token_type":"bearer","refresh_token":"db4ed1dc-8ce1-4b91-8fad-9749022fea64","expires_in":41394,"scope":"ui"}
得到access_token后,可以在请求中携带信息获得ResourceServer中的资源:
curl -H "Authorization:Bearer 057c2f03-e69a-446e-bdf1-2e9d183e8814" localhost/accounts/current
//结果
{"id":2,"name":"test01","description":"test01"}