SpringBoot集成SpringSecurity Oauth2

前期准备

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
buildscript {
ext {
springBootVersion = '1.5.13.BUILD-SNAPSHOT'
}
repositories {
mavenCentral()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

repositories {
mavenCentral()
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/milestone" }
}

dependencies {
compile('org.springframework.boot:spring-boot-starter-data-redis')
compile('org.springframework.boot:spring-boot-starter-security')
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.mybatis.spring.boot:mybatis-spring-boot-starter:1.3.2')
compile('org.springframework.security.oauth:spring-security-oauth2')
runtime('mysql:mysql-connector-java')
compileOnly('org.projectlombok:lombok')
testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile('org.springframework.restdocs:spring-restdocs-mockmvc')
testCompile('org.springframework.security:spring-security-test')
}

配置阶段

1.SecurityWebConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
* <pre>
* Security安全配置类,
* </pre>
* @author tensor
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Autowired
private UserDetailsSecurity userDetailsSecurity;

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsSecurity);
}

/**
*
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers().anyRequest()
.and()
.authorizeRequests()
.antMatchers("/oauth/*").permitAll();
}

@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
AuthenticationManager manager = super.authenticationManagerBean();
return manager;
}
}

2.Oauth2SecurityConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
* <pre>
* Oauth2安全配置类
* </pre>
*
* @author tensor
*/
@Configuration
@EnableAuthorizationServer
public class OAuth2ServerConfiguration extends AuthorizationServerConfigurerAdapter {

@Autowired
private UserDetailsSecurity userDetailsSecurity;
@Autowired
AuthenticationManager authenticationManager;
@Autowired
RedisConnectionFactory redisConnectionFactory;

/**
* 配置Oauth2的client端
* 设置授权方式 {password,refresh_token}
* 设置权限范围 scope
* 设置client_secret
* 设置token过期时间
* @param clients
* @throws Exception
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient("client")
// .resourceIds(DEMO_RESOURCE_ID)
.authorizedGrantTypes("password", "refresh_token")
.scopes("all")
.authorities("client")
.secret("123456")
.refreshTokenValiditySeconds(360);
}

/**
* 配置相关token的存储信息以及设置用户信息验证方式{userDetailsService}
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(new RedisTokenStore(redisConnectionFactory))
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsSecurity)
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST)
.reuseRefreshTokens(true);
}

/**
* 允许信息以表单的形式提交
* @param oauthServer
* @throws Exception
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.allowFormAuthenticationForClients();
oauthServer.checkTokenAccess("isAuthenticated()");
}
}

3.ResourceSecurityConfiguration

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* <pre>
*
* </pre>
* @author tensor
*/
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

public static final String DEMO_RESOURCE_ID = "test";

/**
*
* @param resources
*/
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
// resources.resourceId(DEMO_RESOURCE_ID).stateless(true);
}

/**
* 配置需要进行 token 认证的 restful_api
* @param http
* @throws Exception
*/
@Override
public void configure(HttpSecurity http) throws Exception {
super.configure(http);
http
.authorizeRequests()
.antMatchers(HttpMethod.GET,"/test/**").access("#oauth2.hasScope('all')");
}
}

4.UserDetailsService

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
/**
* <pre>
*
* </pre>
* @author tensor
*/
@Slf4j
@Component
public class UserDetailsSecurity implements UserDetailsService {
/**
* Locates the user based on the username. In the actual implementation, the search
* may possibly be case sensitive, or case insensitive depending on how the
* implementation instance is configured. In this case, the <code>UserDetails</code>
* object that comes back may have a username that is of a different case than what
* was actually requested..
*
* @param username the username identifying the user whose data is required.
* @return a fully populated user record (never <code>null</code>)
* @throws UsernameNotFoundException if the user could not be found or the user has no
* GrantedAuthority
*/

@Qualifier("UserService")
@Autowired
private UserService userService;

/**
*
* @param username
* @return
* @throws UsernameNotFoundException
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userService.login(username).getData();
log.info("User : {}", user);
return new Login(username, user.getUserPassword(), true, true,
true, true, getGrantedAuthorities(user));
}

/**
*
* @param user
* @return
*/
private List<GrantedAuthority> getGrantedAuthorities(User user) {
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return grantedAuthorities;
}
}

参考学习资料

1.从零开始的Spring Security Oauth2(一)

2.理解OAuth 2.0

项目实际运行/测试视频

哔哩哔哩