1.首先spring security基本配置
public class ServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { ...... @Override public void onStartup(ServletContext servletContext) throws ServletException { super.onStartup(servletContext); /** UrlRewriteFilter **/ /* * servletContext.addFilter("UrlRewriteFilter", * UrlRewriteFilter.class).addMappingForUrlPatterns(null, false, "/*"); */ DelegatingFilterProxy filter = new DelegatingFilterProxy("springSecurityFilterChain"); filter.setContextAttribute("org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcher"); servletContext.addFilter("springSecurityFilterChain", filter).addMappingForUrlPatterns(null, false, "/*"); } }
@Configuration @EnableWebSecurity @Order(2) public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService myUserDetailsService; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // auth.inMemoryAuthentication().withUser("marissa").password("koala").roles("USER").and().withUser("paul") // .password("emu").roles("USER"); auth.userDetailsService(myUserDetailsService); } @Override public void configure(WebSecurity web) throws Exception { web.ignoring().antMatchers("/webjars/**", "/images/**", "/oauth/uncache_approvals", "/oauth/cache_approvals"); } @Override protected UserDetailsService userDetailsService() { return myUserDetailsService; } @Override @Bean public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); } @Override protected void configure(HttpSecurity http) throws Exception { System.out.println("==============SecurityConfiguration.configure(HttpSecurity http)"); // @formatter:off http .authorizeRequests() .antMatchers("/login.jsp").permitAll() .anyRequest().hasRole("USER") .and() .exceptionHandling() .accessDeniedPage("/login.jsp?authorization_error=true") .and() // TODO: put CSRF protection back into this endpoint .csrf() .requireCsrfProtectionMatcher(new AntPathRequestMatcher("/oauth/authorize")) .disable() .logout() .logoutUrl("/logout") .logoutSuccessUrl("/login.jsp") .and() .formLogin() .loginProcessingUrl("/login") .failureUrl("/login.jsp?authentication_error=true") .loginPage("/login.jsp"); // @formatter:on } }
@Configuration public class OAuth2ServerConfig { @Configuration @EnableResourceServer @Order(6) protected static class ResourceServerConfiguration extends ResourceServerConfigurerAdapter { @Override public void configure(ResourceServerSecurityConfigurer resources) { resources.resourceId(ResourcesIDs.USER_RESOURCE_ID).stateless(false); } @Override public void configure(HttpSecurity http) throws Exception { System.out.println("====================ResourceServerConfiguration.configure(HttpSecurity http)"); // @formatter:off http // Since we want the protected resources to be accessible in the UI as well we need // session creation to be allowed (it's disabled by default in 2.0.6) .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) .and() .requestMatchers() .antMatchers("/user/**") .and() .authorizeRequests() .antMatchers("/user/profile").access("#oauth2.hasScope('read') or (!#oauth2.isOAuth() and hasRole('ROLE_USER'))"); // @formatter:on } } @Configuration @EnableAuthorizationServer protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter { @Autowired @Qualifier("myClientDetailsService") private ClientDetailsService clientDetailsService; @Autowired private TokenStore tokenStore; @Autowired private UserApprovalHandler userApprovalHandler; @Autowired @Qualifier("authenticationManagerBean") private AuthenticationManager authenticationManager; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.withClientDetails(clientDetailsService); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.tokenStore(tokenStore).userApprovalHandler(userApprovalHandler) .authenticationManager(authenticationManager); /* * .pathMapping("/oauth/authorize", "/oauth2/authorize") * .pathMapping("/oauth/token", "/oauth2/token"); */ // 以上的注释掉的是用来改变配置的 } @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { // oauthServer.realm("sparklr2/client"); oauthServer.allowFormAuthenticationForClients(); } @Bean public TokenStore tokenStore() { return new InMemoryTokenStore(); } } /** * @author admin * * some bean denfinition * */ @Configuration protected static class Stuff { @Autowired @Qualifier("myClientDetailsService") private ClientDetailsService clientDetailsService; @Autowired private TokenStore tokenStore; @Bean public ApprovalStore approvalStore() throws Exception { TokenApprovalStore store = new TokenApprovalStore(); store.setTokenStore(tokenStore); return store; } @Bean @Lazy @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) public MyUserApprovalHandler userApprovalHandler() throws Exception { MyUserApprovalHandler handler = new MyUserApprovalHandler(); handler.setApprovalStore(approvalStore()); handler.setRequestFactory(new DefaultOAuth2RequestFactory(clientDetailsService)); handler.setClientDetailsService(clientDetailsService); handler.setUseApprovalStore(true); return handler; } }
一定注意: ResourceServerConfiguration 和 SecurityConfiguration上配置的顺序, SecurityConfiguration一定要在ResourceServerConfiguration 之前,因为spring实现安全是通过添加过滤器(Filter)来实现的,基本的安全过滤应该在oauth过滤之前, 所以在SecurityConfiguration设置@Order(2), 在ResourceServerConfiguration上设置@Order(6)
其它类:
MyUserApprovalHandler.java
public class MyUserApprovalHandler extends ApprovalStoreUserApprovalHandler { private boolean useApprovalStore = true; private ClientDetailsService clientDetailsService; /** * Service to load client details (optional) for auto approval checks. * * @param clientDetailsService * a client details service */ public void setClientDetailsService(ClientDetailsService clientDetailsService) { this.clientDetailsService = clientDetailsService; super.setClientDetailsService(clientDetailsService); } /** * @param useApprovalStore * the useTokenServices to set */ public void setUseApprovalStore(boolean useApprovalStore) { this.useApprovalStore = useApprovalStore; } /** * Allows automatic approval for a white list of clients in the implicit * grant case. * * @param authorizationRequest * The authorization request. * @param userAuthentication * the current user authentication * * @return An updated request if it has already been approved by the current * user. */ @Override public AuthorizationRequest checkForPreApproval(AuthorizationRequest authorizationRequest, Authentication userAuthentication) { boolean approved = false; // If we are allowed to check existing approvals this will short circuit // the decision if (useApprovalStore) { authorizationRequest = super.checkForPreApproval(authorizationRequest, userAuthentication); approved = authorizationRequest.isApproved(); } else { if (clientDetailsService != null) { Collection<String> requestedScopes = authorizationRequest.getScope(); try { ClientDetails client = clientDetailsService .loadClientByClientId(authorizationRequest.getClientId()); for (String scope : requestedScopes) { if (client.isAutoApprove(scope)) { approved = true; break; } } } catch (ClientRegistrationException e) { } } } authorizationRequest.setApproved(approved); return authorizationRequest; } }
@Service public class MyClientDetailsService implements ClientDetailsService { private ClientDetailsService clientDetailsService; @PostConstruct public void init() { InMemoryClientDetailsServiceBuilder inMemoryClientDetailsServiceBuilder = new InMemoryClientDetailsServiceBuilder(); // @formatter:off inMemoryClientDetailsServiceBuilder. withClient("tonr") .resourceIds(ResourcesIDs.USER_RESOURCE_ID) .authorizedGrantTypes("authorization_code", "implicit") .authorities("ROLE_CLIENT") .scopes("read", "write") .secret("secret") .and() .withClient("tonr-with-redirect") .resourceIds(ResourcesIDs.USER_RESOURCE_ID) .authorizedGrantTypes("authorization_code", "implicit") .authorities("ROLE_CLIENT") .scopes("read", "write") .secret("secret") // .redirectUris(tonrRedirectUri) .and() .withClient("my-client-with-registered-redirect") .resourceIds(ResourcesIDs.USER_RESOURCE_ID) .authorizedGrantTypes("authorization_code", "client_credentials") .authorities("ROLE_CLIENT") .scopes("read", "trust") .redirectUris("http://anywhere?key=value") .and() .withClient("my-trusted-client") .authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit") .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT") .scopes("read", "write", "trust") .accessTokenValiditySeconds(60) .and() .withClient("my-trusted-client-with-secret") .authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit") .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT") .scopes("read", "write", "trust") .secret("somesecret") .and() .withClient("my-less-trusted-client") .authorizedGrantTypes("authorization_code", "implicit") .authorities("ROLE_CLIENT") .scopes("read", "write", "trust") .and() .withClient("my-less-trusted-autoapprove-client") .authorizedGrantTypes("implicit") .authorities("ROLE_CLIENT") .scopes("read", "write", "trust") .autoApprove(true); // @formatter:on try { clientDetailsService = inMemoryClientDetailsServiceBuilder.build(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override public ClientDetails loadClientByClientId(String clientId) throws ClientRegistrationException { System.out.println("loadClientByClientId:" + clientId + " ----------------------"); return clientDetailsService.loadClientByClientId(clientId); } }