上一篇博客使用,过程稍微比较复杂,依赖的是我们自己控制token生成、校验。 那么这一篇文章将使用spring cloud 和 spring-security-oauth2 做一个无缝集成,实现nosession,和权限控制。
为了快速的实现目标效果,拓扑结构如上图,我们将采用 InMemory的形式实现,相关换成JDBC实现位置,我会在文章中说明,主要看代码的注释。
auth-server
认证实现
@Configuration@EnableAuthorizationServerclass AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private UserDetailsService userDetailsService; @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore()).userDetailsService(userDetailsService); } @Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception { oauthServer.tokenKeyAccess("permitAll()"); } //可以改成JDBC从库里读或者其他方式。 @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("browser") .authorizedGrantTypes("authorization_code", "refresh_token", "password") .scopes("ui") .and() .withClient("resource-server") .secret("root") .authorizedGrantTypes("client_credentials", "refresh_token") .scopes("server"); } //这里配置的配置可以改成 jdbc redis 等其他方式 @Bean public InMemoryTokenStore tokenStore() { return new InMemoryTokenStore(); }}// security配置主要是userDetailsService @Configuration@EnableWebSecurityclass WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService); } @Override protected void configure(HttpSecurity http) throws Exception { http.anonymous().disable() .authorizeRequests() .anyRequest().authenticated(); }}
resource-server
关于为什么要配置loadBalancerInterceptor这个bean 我会在这篇文章总结部分说明
@SpringBootApplication@EnableEurekaClient@EnableResourceServerpublic class ResourceApplication { public static void main(String[] args) { SpringApplication.run(ResourceApplication.class, args); } @Bean LoadBalancerInterceptor loadBalancerInterceptor(LoadBalancerClient loadBalance) { return new LoadBalancerInterceptor(loadBalance); }}
还有一个最重要的,就是我们受保护的资源。。
@RestControllerpublic class ResourceController { @GetMapping("/getResource") public String getResource(Principal principal) { return "SUCCESS,授权成功拿到资源啦.当前用户:" + principal.getName(); }}
配置application.yml
security: sessions: stateless oauth2: resource: loadBalanced: true user-info-uri: http://gateway-server/uaa/user prefer-token-info: false service-id: resource-server
gateway 配置
zuul: ignored-services: '*' routes: auth-server: path: /uaa/** serviceId: auth-server sensitiveHeaders: strip-prefix: false resource-server: path: /demo/** serviceId: resource-server sensitiveHeaders: strip-prefix: false
运行使用
服务 | 端口 |
---|---|
gateway-server | 6666 |
auth-server | 7777 |
resource-server | 8888 |
eureka-server |
通过网关访问auth-server 获取access-token
//curl 不会用的可以参考文章总结里面 Rest Client 那个报文工具。// 这里的账户是在 auth-server里面写死的,service实现里面。 curl -H "Authorization:Basic YnJvd3Nlcjo=" -d "grant_type=password&scope=ui&username=123&password=456" localhost:6666/uaa/oauth/token {"access_token":"c8df8942-f032-4403-92fc-f23019819da9","token_type":"bearer","refresh_token":"993a94b4-5335-4f0a-9981-e1ad4e4776a8","expires_in":43199,"scope":"ui"}
通过access-token 访问受保护的资源
curl -H "Authorization:Bearer c8df8942-f032-4403-92fc-f23019819da9" localhost:6666/demo/getResourceSUCCESS,授权成功拿到资源啦.当前用户:123
片尾总结
- 坑。自定义对象的时候,默认使用的加密是PlaintextPasswordEncoder。如果使用其他,记得用对应的工具类处理一下密码再插入。
- 关于oauth server 认证的loadBalanced 设置。
security: sessions: stateless oauth2: resource: loadBalanced: true #设置这个才可以使用eureka的服务名,配合loadBalancerInterceptor bean。
3.关于CURL 工具 可以用 Git Bash ,提供了curl 工具的。或者chrome里面这个插件挺好用。
源码
- 源码可以参考:
springcloud-security-oauth-server
springcloud-security-oauth-resource springcloud-security-oauth-gateway这个三个模块