java rest api oauth,Spring+Spring Security+OAuth2实现REST API权限控制 | 大道至简

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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值