Spring集成Spring Security、OAuth2实现资源访问授权认证。后端主要做的是认证服务器和资源服务。客户端主要是用前端的js请求。因为只是要做一个demo,所以这里的用户信息和授权token都是保存在内存中,后面会根据项目需要将用户信息保存到数据库,授权信息保存到redis。
源码地址:https://github.com/li5454yong/SpringSecurityOAuth2.git
1、首先来看pom依赖
XHTML
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
65
66
67
68
69
70
71
72
73
74
75
76
77
UTF-8
4.3.1.RELEASE
4.1.4.RELEASE
2.0.12.RELEASE
2.7.5
org.springframework
spring-core
${springframework.version}
org.springframework
spring-web
${springframework.version}
org.springframework
spring-webmvc
${springframework.version}
org.springframework.security
spring-security-web
${springsecurity.version}
org.springframework.security
spring-security-config
${springsecurity.version}
org.springframework.security.oauth
spring-security-oauth2
${springsecurityoauth2.version}
com.fasterxml.jackson.core
jackson-databind
${jackson.library}
com.fasterxml.jackson.dataformat
jackson-dataformat-xml
${jackson.library}
javax.servlet
javax.servlet-api
3.1.0
compile
maven-compiler-plugin
1.7
1.7
UTF-8
SpringSecurityOAuth2
这里需要注意的是:Spring的版本,如果没有特殊需要的话请保持现在的不变,因为我刚开始是使用的是4.0.0,但是项目启动时回报ClassNotFoundException,说找不到org.springframework.web.filter.CorsFilter这个类,后来查看源码,确实没有这个java类。
2、Spring配置
demo中使用的都是java config风格的配置,没有xml,首先来看Spring的配置。
Java
1
2
3
4
5
6
7
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.lxg.spring")
public class SpringConfiguration {
}
这里只需要指定注解扫描的包。
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class SpringInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class>[] getRootConfigClasses() {//获取Spring应用容器的配置文件
return new Class[] { SpringConfiguration.class };
}
@Override
protected Class>[] getServletConfigClasses() {//获取Spring MVC应用容器
return null;
}
@Override
protected String[] getServletMappings() {//指定需要由DispatcherServlet映射的路径,这里给定的是"/",意思是由DispatcherServlet处理所有向该应用发起的请求。
return new String[] { "/" };
}
@Override
protected Filter[] getServletFilters() {//添加拦截器
Filter [] singleton = { new CORSFilter()};
return singleton;
}
}
配置DispatcherServlet、初始化Spring MVC容器和Spring容器。
可以看到,在这段代码中设置了一下SpringMVC相关的信息,同时还注册了一个拦截器。
下面来看拦截器的代码。
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class CORSFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
System.out.println("Filtering on...........................................................");
HttpServletResponse response = (HttpServletResponse) res;
response.setHeader("Access-Control-Allow-Origin", "*");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "POST, GET, PUT, OPTIONS, DELETE");
response.setHeader("Access-Control-Max-Age", "3600");
response.setHeader("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Authorization, Origin, Accept, Access-Control-Request-Method, Access-Control-Request-Headers");
chain.doFilter(req, res);
}
public void init(FilterConfig filterConfig) {}
public void destroy() {}
}
这里和普通web项目中的拦截器并没有什么区别,都是实现了javax.servlet.Filter接口。设置response的header可以解决POST请求跨域的问题。
3、Spring Security配置
Java
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
65
66
@Configuration
@EnableWebSecurity
public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private ClientDetailsService clientDetailsService;
/**
* 在内存中创建两个用户
* @param auth
* @throws Exception
*/
@Autowired
public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("bill").password("abc123").roles("admin1").and()
.withUser("bob").password("abc123").roles("USER");
}
/**
* 设置获取token的url
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.anonymous().disable()
.authorizeRequests()
.antMatchers("/oauth/token").permitAll();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
/**
* 实例化一个TokenStore,他的实现是InMemoryTokenStore,会把OAuth授权的token保存在内存中
* @return
*/
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
@Bean
@Autowired
public TokenStoreUserApprovalHandler userApprovalHandler(TokenStore tokenStore){
TokenStoreUserApprovalHandler handler = new TokenStoreUserApprovalHandler();
handler.setTokenStore(tokenStore);
handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService));
handler.setClientDetailsService(clientDetailsService);
return handler;
}
@Bean
@Autowired
public ApprovalStore approvalStore(TokenStore tokenStore) throws Exception {
TokenApprovalStore store = new TokenApprovalStore();
store.setTokenStore(tokenStore);
return store;
}
}
在这个配置中,创建了两个用户存储在内存中,指定了token的保存方式为内存存储。
下面,需要开启Spring Security的注解
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@SuppressWarnings("unused")
@Autowired
private OAuth2SecurityConfiguration securityConfig;
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
return new OAuth2MethodSecurityExpressionHandler();
}
}
3、OAuth2配置
首先是认证服务配置
Java
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
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {
private static String REALM="MY_OAUTH_REALM";
@Autowired
private TokenStore tokenStore;
@Autowired
private UserApprovalHandler userApprovalHandler;
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("my-trusted-client")//客户端ID
.authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")
.authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")
.scopes("read", "write", "trust")//授权用户的操作权限
.secret("secret")//密码
.accessTokenValiditySeconds(6000);//token有效期为120秒
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler)
.authenticationManager(authenticationManager);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.realm(REALM+"/client");
}
}
资源服务配置
Java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
private static final String RESOURCE_ID = "my_rest_api";
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId(RESOURCE_ID).stateless(false);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.
anonymous().disable()
.requestMatchers().antMatchers("/user*/**")
.and().authorizeRequests()
.antMatchers("/user*/**").permitAll()
.and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler());
}
}
4、测试
OK,里面还有几个URL,感兴趣的话可以自己去测试,另外,demo中也包含了一个使用Http工具来测试的代码。
这篇文章中,用户信息和token都是保存在内存中,我后面还会发文章,使用spring boot来集成,同时把用户信息保存在MySQL中,token保存在redis,这样会更接近与实际项目场景。
喜欢 (12)or分享 (0)