在這裏咱們使用Spring boot中的 secruity 和 Oauth2.0 搭建一個受權服務器 java
讓其餘應用或者服務使用用戶名和密碼 POST到這個服務器 來換取access_token spring
這種場景在實際應用中仍是很常見的api
具體方法請訪問 https://my.oschina.net/u/659068/blog/1549186服務器
<!-- security --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> </dependency> <!-- security oauth2 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> </dependency>
這裏主要就是設置了訪問密碼 路徑配置等 其中 AuthenticationManager 是必須的app
@Configuration @EnableWebSecurity @Order(2) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private ClientDetailsService clientDetailsService; @Configuration protected static class AuthenticationConfiguration extends GlobalAuthenticationConfigurerAdapter { @Override public void init(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("user").password("zzz123") .roles("USER").and().withUser("admin").password("zzz123") .roles("USER", "ADMIN"); } } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication().withUser("shili").password("zzz123").roles("ADMIN"); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable() .anonymous().disable() .authorizeRequests() .antMatchers("/oauth/token").permitAll() .and().exceptionHandling().authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/")); } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @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; } }
其中 allowFormAuthenticationForClients 是必須的 這裏的 client_id 和 secret 也能夠按照需求註冊受權less
這裏是寫死的 這裏之後會修改curl
@Configuration @EnableAuthorizationServer public class SecurityOauth2Config 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("13890999") .authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit") .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT") .scopes("read", "write", "trust") .secret("secret") .accessTokenValiditySeconds(120).//Access token is only valid for 2 minutes. refreshTokenValiditySeconds(600);//Refresh token is only valid for 10 minutes. } @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { //enable client to get the authenticated when using the /oauth/token to get a access token //there is a 401 authentication is required if it doesn't allow form authentication for clients when access /oauth/token oauthServer.allowFormAuthenticationForClients().realm(REALM+"/client"); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler) .authenticationManager(authenticationManager); } }
@Configuration @EnableResourceServer @Order(6) 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("/sayhello") .and().authorizeRequests() .antMatchers("/sayhello").access("hasRole('ADMIN')") .and().exceptionHandling().accessDeniedHandler(new OAuth2AccessDeniedHandler()); } }
curl https://localhost:8080/oauth/token -k -d client_id=13890999 -d client_secret=secret -d grant_type=password -d username=shili -d password=zzz123
參數增長-k 跳過了證書的驗證 不然就會出現錯誤提示 證書鏈是由不受信任的頒發機構頒發的。ide
看到以下信息 表示獲取ACCESS_token 成功了! spring-boot
{"access_token":"66e5ab1d-427f-4801-a3c5-b47d3a96fbad","token_type":"bearer","re fresh_token":"cc9ef96f-d771-4ec9-a4fc-9064809886e3","expires_in":119,"scope":"re ad write trust"}