打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
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
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <springframework.version>4.3.1.RELEASE</springframework.version>
        <springsecurity.version>4.1.4.RELEASE</springsecurity.version>
        <springsecurityoauth2.version>2.0.12.RELEASE</springsecurityoauth2.version>
        <jackson.library>2.7.5</jackson.library>
    </properties>
    <dependencies>
        <!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <!-- Spring Security -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${springsecurity.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${springsecurity.version}</version>
        </dependency>
        <!-- Spring Security OAuth2-->
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>${springsecurityoauth2.version}</version>
        </dependency>
        <!-- Jackson libraries -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson.library}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-xml</artifactId>
            <version>${jackson.library}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
        </dependency>
    </dependencies>
    <build>
        <defaultGoal>compile</defaultGoal>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
        <finalName>SpringSecurityOAuth2</finalName>
    </build>

这里需要注意的是: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、测试

这里使用PostMan来做http测试工具
首先测试获取token
输入url http://localhost:8080/oauth/token?grant_type=password&username=bob&password=abc123

测试获取用户列表,这里在后台对这个方法要求需要拥有“USER”角色
http://localhost:8080/userList/?access_token=a375bb21-f090-4280-ac6a-98323da16e78

OK,里面还有几个URL,感兴趣的话可以自己去测试,另外,demo中也包含了一个使用Http工具来测试的代码。

这篇文章中,用户信息和token都是保存在内存中,我后面还会发文章,使用spring boot来集成,同时把用户信息保存在MySQL中,token保存在redis,这样会更接近与实际项目场景。

转载请注明:大道至简 » Spring+Spring Security+OAuth2实现REST API权限控制

喜欢 (12)or分享 (0)
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
写了一个 SSO 单点登录的代码示例给胖友!
Spring Roo 的中文支持
pom.xml
基于Maven的Spring + Spring MVC + Mybatis的环境搭建 | AmazingHarry
SpringCloud SpringBoot OAuth2 Spring Security Redi...
使用Spring Cloud Eureka实现服务注册与发现
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服