利用Spring Security OAuth2 进行API权限
2017-10-19 本文已影响1085人
AlienJunX
客户端在访问API时候需要经过权限控制,方便在服务端进行控制引入了Spring Security OAuth2 。
客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。OAuth 2.0定义了四种授权方式。
- 授权码模式(authorization code)
- 简化模式(implicit)
- 密码模式(resource owner password credentials)
- 客户端模式(client credentials)
自有项目采用客户端模式进行授权
客户端通过密码和服务端注册的client_id、client_secret、grant_type进行授权,直接获取token,而不需要提示用户是否同意授权。授权后token和用户、客户端是绑定的,通过token可以拿到用户也可以知道用户客户端来源
客户端授权.jpg服务端配置security配置
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
PathLoginAuthenticationEntryPoint loginEntryPoint;
@Autowired
PathUrlAuthenticationFailureHandler loginFailureHandler;
@Autowired
PathUrlLogoutSuccessHandler logoutSuccessHandler;
@Override
@Bean
public UserDetailsService userDetailsService() {
return new LoginUserDetailsService();
}
@Bean
public PathTokens pathTokens() {
return new PathTokens(Arrays.asList("user", "admin", "partner"));
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
CacheManager cacheManager() {
SimpleCacheManager cacheManager = new SimpleCacheManager();
cacheManager.setCaches(Arrays.asList(new GuavaCache(CommonConstant.WECHAT_CODE,
CacheBuilder.newBuilder().expireAfterAccess(5, TimeUnit.MINUTES).build())));
return cacheManager;
}
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/js/**", "/css/**", "/images/**", "/fonts/**" , "/upload/**", "/MP*.txt");
}
// 注意将/oauth/*路径开放
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests()
.antMatchers("/login", "/resetpwd", "/sendsms", "/common/**","/register","/oauth/**").permitAll()
.antMatchers("/user/**").hasAuthority(User.Role.USER.toString())
.antMatchers("/admin/**").hasAuthority(User.Role.ADMIN.toString())
.anyRequest().authenticated();
http.formLogin().loginProcessingUrl("/login")
.usernameParameter("username").passwordParameter("password")
.defaultSuccessUrl("/default", true)
.failureHandler(loginFailureHandler);
http.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.deleteCookies("remember-me")
.invalidateHttpSession(true)
.logoutSuccessHandler(logoutSuccessHandler);
http.rememberMe()
.tokenValiditySeconds(604800);
http.exceptionHandling().authenticationEntryPoint(loginEntryPoint);
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
oauth2配置
@Configuration
public class OAuth2Config {
private static final String RESOURCE_ID = "restservice";
@Configuration
@EnableResourceServer
protected static class ResourceServerConfiguration extends
ResourceServerConfigurerAdapter {
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources
.resourceId(RESOURCE_ID);
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatchers().antMatchers("/api/**")
.and()
.authorizeRequests()
.antMatchers("/api/**").authenticated();
}
}
@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends
AuthorizationServerConfigurerAdapter {
private TokenStore tokenStore = new InMemoryTokenStore();
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Autowired
private LoginUserDetailsService loginUserDetailsService;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints
.tokenStore(this.tokenStore)
.authenticationManager(this.authenticationManager)
.userDetailsService(loginUserDetailsService);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("clientapp")
.authorizedGrantTypes("password", "refresh_token")
.scopes("read", "write")
.resourceIds(RESOURCE_ID)
.secret("123456");
}
@Bean
@Primary
public DefaultTokenServices tokenServices() {
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setSupportRefreshToken(true);
tokenServices.setTokenStore(this.tokenStore);
return tokenServices;
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
// 允许对客户端进行表单身份验证
oauthServer.allowFormAuthenticationForClients();
}
}
}
测试:
http://localhost:9090/oauth/token
grant_type:password
client_id:clientapp
client_secret:123456
scope:read write
username:admin
password:000000
得到token:
{"access_token":"f8e1509f-f7a3-40fc-ac8a-4815852c47e3","token_type":"bearer","refresh_token":"4ae758f1-d9a3-40c4-8d76-3bb57a4ae7d9","expires_in":42476,"scope":"read write"}
使用token进行api请求:
http://localhost:9090/api/test?access_token=4730a768-3176-475a-91bb-a6d299b8f198
参考资料:
http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
http://www.dannysite.com/blog/181/
http://www.cnblogs.com/lexiaofei/p/7152326.html?utm_source=itdadao&utm_medium=referral
http://www.cnblogs.com/xingxueliao/p/5911292.html