范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

OAuth2。0分布式系统环境搭建

  介绍
  OAuth(开放授权)是一个开放标准,允许用户授权第三方应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方应用或分享他们数据的所有内容。OAuth2.0的系统大致分由客户端,认证授权服务器以及资源服务器三部分组成。客户端如果想要访问资源服务器中的资源,就必须要持有认证授权服务器颁发的Token。认证流程如下图所示:
  这篇文章将通过一个具体的案例来展示如何搭建一个分布式的OAuth2.0系统。整体的结构图如下所示。有网关,认证授权服务以及资源服务三个部分组成。既然OAuth2是一个标准,如果我们想用的话,必然是用它的实现,也就是Spring-Security-OAuth2,它可以很方便地和Spring Cloud集成。OAuth2.0的更多细节会在案例中继续介绍。
  那么就开始吧!数据库
  要完成这套系统,需要准备好用到的一些数据表。
  oauth_client_details:这个数据库存放了客户端的配置信息,客户端有什么样的权限才可以访问服务器。表中的字段是固定的,下面会详细提到。oauth_code:用户数据库存取授权码模式存放授权码的,表中的字段也是固定的,下面会详细说明。后面的5张表存放了用户的一些信息,如果角色、权限等信息。登录验证的时候需要。
  建表的sql我放在了源码的README.md文件中,下载地址见文末。注册中心
  微服务项目得先有个注册中心吧,我们选用Eureka。先搭建一个父工程OAuth2Demo,然后在父工程中创建一个Module叫oauth2_eureka。然后添加配置文件及启动类即可。所需要的依赖我就不在这里贴了,太占篇幅了。有需要的小伙伴直接去我源码中拷就行了。spring:   application:     name: eureka server:   port: 8000 #启动端口 …………@SpringBootApplication @EnableEurekaServer public class EurekaApplication {     public static void main(String[] args) {         SpringApplication.run(EurekaApplication.class,args);     } }
  这样注册中心就搭建好了。认证授权服务服务搭建
  在OAuth2Demo中创建一个Module叫oauth2_uaa作为认证服务。添加启动类和配置文件。spring.application.name=uaa server.port=8001 eureka.client.serviceUrl.defaultZone = http://localhost:8000/eureka/ …………@SpringBootApplication @EnableEurekaClient @MapperScan("com.robod.uaa.mapper") public class UaaApplication {     public static void main(String[] args) {         SpringApplication.run(UaaApplication.class, args);     } }配置
  回顾上一篇Spring Security的文章中提到的几点内容用户来源的Service实现UserDetailsService接口,实现loadUserByUsername()方法,从数据库中获取数据Spring Security的配置类继承自WebSecurityConfigurerAdapter,重写里面的两个configure()方法
  public interface UserService extends UserDetailsService { } //----------------------------------------------------------- @Service("userService") public class UserServiceImpl implements UserService { 	…………     @Override     public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {         SysUser sysUser = userMapper.findByUsername(username);         return sysUser;     } }@Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 	…………     @Bean     public PasswordEncoder passwordEncoder() {         return new BCryptPasswordEncoder();     }      @Bean     @Override     protected AuthenticationManager authenticationManager() throws Exception {         return super.authenticationManager();     }      //认证用户的来源     @Override     protected void configure(AuthenticationManagerBuilder auth) throws Exception {         auth.userDetailsService(userService).passwordEncoder(passwordEncoder());     }      //配置SpringSecurity相关信息     @Override     protected void configure(HttpSecurity http) throws Exception {         http.csrf().disable()                 .authorizeRequests()                 .antMatchers("/r/r1").hasAnyAuthority("p1")                 .antMatchers("/login*").permitAll()                 .anyRequest().authenticated()                 .and()                 .formLogin();     }  }
  解释一下上面的代码,WebSecurityConfig是Spring Security的配置类,第一个configure()方法配置的是用户的来源,这里配置了自定义的实现了UserDetailsService接口的UserService,里面的loadUserByUsername()方法从数据库中查询出对应的实现了UserDetails接口的SysUser对象,里面的SysPermission封装了用户所拥有的权限。然后就交给后续的过滤器去处理了,我们就不用去管了。
  然后我们就可以去进行OAuth2.0的相关配置了,方法很简单,只要在配置类上添加@EnableAuthorizationServer注解并让其继承自AuthorizationServerConfigurerAdapter。最后重写其中的三个configure()方法即可。@Configuration @EnableAuthorizationServer public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {      @Autowired     private AuthenticationManager authenticationManager;    //从WebSecurityConfig中获取的      @Autowired     private AuthorizationCodeServices authorizationCodeServices;    //本类中的,授权码模式需要      @Autowired     private TokenStore tokenStore;  //TokenConfig中的      @Autowired     private PasswordEncoder passwordEncoder;//从WebSecurityConfig中获取的      @Autowired     private ClientDetailsService clientDetailsService;   //本类中的      @Autowired     private JwtAccessTokenConverter jwtAccessTokenConverter;    //TokenConfig中的      //用来配置令牌端点的安全约束     @Override     public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {         security.tokenKeyAccess("permitAll")    // /oauth/token_key 提供公有密匙的端点 允许任何人访问                 .checkTokenAccess("permitAll")  // /oauth/check_token :用于资源服务访问的令牌解析端点 允许任何人访问                 .allowFormAuthenticationForClients();   //表单认证(申请令牌)     }      //用来配置客户端详情服务,客户端详情信息在这里进行初始化,     //你能够把客户端详情信息写死在这里或者是通过数据库来存储调取详情信息     @Override     public void configure(ClientDetailsServiceConfigurer clients) throws Exception {         clients.withClientDetails(clientDetailsService);     }      //用来配置令牌(token)的访问端点(url)和令牌服务(token services)     @Override     public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {         endpoints.authenticationManager(authenticationManager)  //认证管理器,密码模式需要                 .authorizationCodeServices(authorizationCodeServices)   //授权码服务,授权码模式需要                 .tokenServices(tokenService())                 .allowedTokenEndpointRequestMethods(HttpMethod.POST);   //允许post提交     }      @Bean     public AuthorizationCodeServices authorizationCodeServices(DataSource dataSource) {         //设置授权码模式的授权码存取到数据中         return new JdbcAuthorizationCodeServices(dataSource);     }      //客户端详情服务,从数据库中获取     @Bean     public ClientDetailsService clientDetailsService(DataSource dataSource) {         ClientDetailsService clientDetailsService = new JdbcClientDetailsService(dataSource);         ((JdbcClientDetailsService)clientDetailsService).setPasswordEncoder(passwordEncoder);         return clientDetailsService;     }      //令牌管理服务     @Bean     public AuthorizationServerTokenServices tokenService() {         DefaultTokenServices service = new DefaultTokenServices();         service.setClientDetailsService(clientDetailsService);  //客户端信息服务         service.setSupportRefreshToken(true);               //支持自动刷新         service.setTokenStore(tokenStore);         //令牌增强         TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();         tokenEnhancerChain.setTokenEnhancers(Arrays.asList(jwtAccessTokenConverter));         service.setTokenEnhancer(tokenEnhancerChain);          service.setAccessTokenValiditySeconds(7200);        //令牌默认有效期2小时         service.setRefreshTokenValiditySeconds(259200);     //刷新令牌默认有效期3天         return service;     } }
  现在来解释一下上面代码中的内容ClientDetailsService我们配置了从数据库中获取客户端配置。但是是怎么从数据库中获取的呢,这里用到了一个JdbcClientDetailsService,点击源码里看看
  可以看到,它是从 oauth_client_details 这张表里查出来的,所以我们的数据库中只要创建出这张表,表里再添加这些字段即可。JdbcAuthorizationCodeServices原理和JdbcClientDetailsService差不多,都是创建出指定的表。TokenStore 和 JwtAccessTokenConverter为了方便管理,我们使用TokenConfig这个类去配置Token相关的内容。添加了@Bean注解将其添加到Spring容器后就可以在其它的类中去注入使用了。@Configuration public class TokenConfig { private String SIGNING_KEY = "robod_hahaha"; //对称加密的密钥 @Bean public TokenStore tokenStore() { //JWT令牌方案 return new JwtTokenStore(jwtAccessTokenConverter()); } @Bean public JwtAccessTokenConverter jwtAccessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey(SIGNING_KEY); //对称秘钥,资源服务器使用该秘钥来验证 return converter; } } 采用了JWT令牌管理方式,然后使用了对称密钥去进行加密。还有另外几种令牌管理方式:InMemoryTokenStore:在内存中存储令牌(默认)JdbcTokenStore:令牌存储在数据库中RedisTokenStore:令牌存储在Redis中AuthorizationServerTokenServices这个是用来配置令牌管理服务的,我们配置了客户端详情服务,令牌增强等内容。申请令牌的四种方式
  到现在为止,我们的认证授权服务就已经配置好了,那么现在就可以去申请令牌了,申请令牌的方式一共有四种:授权码模式第一步申请授权码http://localhost:8001/uaa/oauth/authorize?client_id=c1&response_type=code&scope=ROLE_ADMIN&redirect_uri=http://localhost注意,这里的client_id,scope和redirect_uri都是在oauth_client_details表中设置过的,要一一对应上,否则不行,response_type授权码模式固定为code。成功访问后,在页面上输入用户名和密码,验证通过后,在浏览器的地址栏中就可以看到返回的授权码。然后我们拿着授权码就可以向服务器去申请Token了,参数列表必须和数据库中配置的一致。简化模式http://localhost:8001/uaa/oauth/authorize?client_id=c1&response_type=token&scope=ROLE_ADMIN&redirect_uri=http://localhost在简化模式下,我们只需要去指定client_id,response_type,scope和redirect_uri即可,请求成功后,就会跳转到指定的uri界面,然后令牌就在url中。密码模式在密码模式下,我们需要将用户名和密码传到服务器中,验证通过后,服务器会直接将Token返回给我们客户端模式该模式最简单,也是最不安全的。网关
  搭建完了认证授权服务再来创建网关服务。在父工程下创建一个名为oauth2_gateway的Module。启动类没什么好说的,配置文件中有几点需要注意:spring.application.name=gateway server.port=8010  zuul.routes.uaa.stripPrefix = false zuul.routes.uaa.path = /uaa/**  zuul.routes.order.stripPrefix = false zuul.routes.order.path = /order/**  eureka.client.serviceUrl.defaultZone = http://localhost:8000/eureka/ …………
  我们配置了微服务的名称及端口,还配置了将路径为/zuul/uaa/**和 /zuul/order/**的请求转发给uaa和order微服务。
  老样子,第一步进行一些安全配置@Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter {      @Override     protected void configure(HttpSecurity http) throws Exception {         http.authorizeRequests()                 .antMatchers("/**").permitAll()                 .and().csrf().disable();     }  }
  我们在这里设置了可以接收任何请求,不需要任何的权限。
  接下来就需要对具体的资源服务进行配置:@Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter {      public static final String RESOURCE_ID = "res1";      @Autowired     private TokenStore tokenStore;      @Override     public void configure(ResourceServerSecurityConfigurer resources) {         resources.tokenStore(tokenStore)                 .resourceId(RESOURCE_ID)                 .stateless(true);     }      @Override     public void configure(HttpSecurity http) throws Exception {         http.authorizeRequests()                 .antMatchers("/uaa/**")                 .permitAll()                 .antMatchers("/order/**")                 .access("#oauth2.hasScope("ROLE_API")");     }  }
  在这里面,配置了访问认证服务不需要任何的权限。访问订单资源服务需要用户必须具有 "ROLE_API"的scope权限。其中注入的tokenStore和认证服务中的TokenConfig一致。
  因为订单微服务还没有创建,所以我们来测试一下网关访问认证授权服务。网关的端口是8010。
  来测试一下,先是通过网关获取令牌,网关微服务的端口是8010。
  可以看到,申请到了令牌,说明请求成功地被转发到了认证服务。订单资源服务
  最后,我们就可以去创建资源服务了。在父工程下创建一个名为oauth2_order的Module。
  第一步,先进行一些安全配置:@Configuration @EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true) public class WebSecurityConfig extends WebSecurityConfigurerAdapter {      @Override     protected void configure(HttpSecurity http) throws Exception {         http.csrf().disable()                 .authorizeRequests()                 .antMatchers("/r/**").authenticated()   //所有/r/**的请求必须认证通过                 .anyRequest().permitAll();  //除了/r/**,其它的请求可以访问     }  }
  这个@EnableGlobalMethodSecurity是干吗的呢?是为了开启注解权限控制的,只有开启了之后,我们才可以在需要进行权限控制的地方去添加注解实现权限控制。
  接下来就是对资源服务器的配置了。在@Configuration注解的配置类上添加@EnableResourceServer注解,然后继承自ResourceServerConfigurerAdapter类,然后重写里面的configure()方法即可。@Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter {      public static final String RESOURCE_ID = "res1";    //资源服务的id      @Autowired     private TokenStore tokenStore;  //管理令牌的方式,TokenConfig中的      @Override     public void configure(ResourceServerSecurityConfigurer resources) throws Exception {         resources.resourceId(RESOURCE_ID)                 .tokenStore(tokenStore)                 .stateless(true);     }      @Override     public void configure(HttpSecurity http) throws Exception {         http.authorizeRequests()                 .antMatchers("/**").access("#oauth2.hasScope("ROLE_ADMIN")")                 .and().csrf().disable()                 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);     }  }
  接下来就是在需要进行权限控制的方法上面添加注解。@RestController public class OrderController {      @GetMapping(value = "/r1")     @PreAuthorize("hasAuthority("p1")")//拥有p1权限方可访问此url     public String r1() {         return "访问资源成功";     }  }
  ok!成功了。再来试一下通过网关去访问order中的资源,用一个没有权限的用户访问试试。
  说明网关成功转发了我们请求,并且我们配置的权限控制也起了作用。总结
  使用OAuth2.0搭建分布式系统到这里就结束了。内容还是挺多的,希望小伙伴们能有静下心来细品。因为考虑到篇幅,很多非核心的内容我都没有贴出来,比如pom文件,配置文件的部分内容等。小伙伴们可以下载源码再配合着这篇文章看。
  ————关注我,转发文章之后私信回复【源码】即可免费下载源码

盐城。连云港市,路扩宽反而拆了收费站,农民集中住别墅,国道大堵车5月23日,晴,一人一车,环山东半岛。渤海湾骑行第3天。在老家盐城市滨海县凭身份证做了个全民免费体检,休息2天,今天继续向北骑,准备环山东半岛,早晨5时从滨海县城出发,沿着204国谁能抢先布局1520万元级新能源市场,谁就拿到了头部车企入场券问当前市场,最火爆的新能源汽车是哪辆?答非国民代步车五菱宏光MINI莫属。以绝对销量优势碾压一众对手的五菱宏光MINI,稳坐新能源车型销量榜单榜首。若以销量论成败,五菱宏光可以说是富德生命人寿贵州分公司小海豚计划公益活动走进黔东南9月28日,富德生命人寿贵州分公司小海豚计划公益活动第三次走进黔东南州大风洞乡老君寨小学,举办2020年小海豚计划公益活动,为学生们送去关心和温暖。小海豚计划是富德生命人寿2013富德生命人寿贵州分公司举办第四届客户新春音乐会音乐会现场暖春繁花似锦绣,感恩一路紧相随,12月19日下午,富德生命人寿贵州分公司携手贵阳交响乐团在贵阳大剧院举办VIP艺术季第四届春和乐章红色经典音乐会,客户合作单位以及社会各界鲁大师Pro正式发布云上的公司与家鲁大师诞生10年来,受到了非常多用户的支持,在大家的支持下,我们的产品矩阵越来越丰富,有鲁大师移动鲁大师手游助手鲁蛋硬件海外dualspaceEsayclean等等。十年来,鲁大师全球知名技术公司布勒集团选用TeamViewer实现设备远程维护与调试TeamViewer条件访问功能为访问核心基础架构提供了高安全性的解决方案。通过实时提供技术支持,减少了停机时间,在提高客户满意度的同时减少差旅出行次数,实现可持续发展。全球知名的TeamViewer收购3D可视化和混合现实创新公司Viscopic这家慕尼黑初创公司为改进的工业流程提供交互式全息图和低代码MR内容的创建2021年5月12日,领先的全球安全远程连接解决方案和工作场所数字化技术提供商TeamViewer宣布收购V文剑居士谈音乐和器材之六,AKGK14p和电视剧绝代双雄风雷动变化瞬息间英雄泪如何说从头前尘灰飞烟没叹回首月明中往事如烟似梦转眼岁月匆匆谁为谁等候谁为谁蹉跎到此刻依然模糊在其中人间悲欢缘分不同你拥有你的来时去时路我若同行命运如何聚散离合经典大屏如期而至!比亚迪F5DMi内饰谍照曝光日前,汽车有智慧从相关渠道获悉到了一组,关于比亚迪F5DMi的内饰谍照。作为比亚迪最为经典的元素之一的车机大屏如期而至。可以看到,比亚迪F5DMi的内饰,整体设计风格偏向于简约时尚Win11怎么恢复Win10经典菜单?相信Win11的发布一定让很多用户猝不及防,在Win11发布之后大家肯定有很多不习惯的地方,那么我们怎么恢复到Win10的菜单呢,今天就让小编来带大家看看吧,希望可以帮到各位。怎么海尔中央空调聚焦医药行业生态发展,打造健康场景方案2021海尔中央空调医药行业生态交互峰会在青岛盛大召开,本次交互峰会吸引了暖通行业专家医药行业精英代表等荣聚一堂,结合医药行业发展趋势共同探讨未来医药行业的生态发展。医药行业一直以
向十国宣战,俄罗斯黑客又公开搞事情,国际头号黑客组织匿名者发声祝你们好运当地时间16日,据俄罗斯报纸报报道,俄罗斯黑客组织Killnet正式向10个支持恐俄症的国家宣战。Killnet在其社交媒体账号上发布的视频中指出,他们的攻击目标国家是美国英国德国巴西女企业家从中国取经探索巴西电商未来2016年7月16日,卡米拉加塔斯参加一场在巴西圣保罗举办的虚拟现实技术发展讨论会。(受访者供图)新华社北京5月12日电(记者吴昊周永穗)线上购物团购拼单直播带货外卖点单巴西商人卡未来世界的和谐与稳定只能构筑在全民所有制主导之上全国老百姓的智能手机是覆盖全球的超级基础设施,所有科技公司寄生在它上面,休闲时间是互联网世界的劳动力,整个互联网的内容都是消费者创造的,消费者创造内容,管理市场,启蒙AI提供人一般担心家里的门锁不安全?试试德施曼智能Q50FPro指纹锁我们大多数的人平时在公司上班的时候,总是会担心家里的门有没有锁好,会不会家里进了小偷,担心家里进了小偷,家里那些贵重的东西都要被偷了,当然这是正常的表现,今天我就给大家讲讲这款德施上了网课才知道,家里有台打印机有多重要停课不停学,DCPB7520DW黑白激光一体机,在家学习小帮手DCPB7520DW因为疫情,孩子已经在家上了一个多月的网课了。真是上了网课才知道,家用打印机有多重要老师在群里布置的罗技Lift垂直无线鼠标解析主打人体工学设计罗技近期推出了一款型号为Lift的无线蓝牙鼠标,其主打人体工学设计,可以让用户在办公室感觉更为舒适。目前这款鼠标已经在电商平台开启预售,价格为599元。下面我们就来看看罗技Lift一条线走天下?iPhone15传出新消息,感觉苹果14已经不香了想在如今的手机市场中立足真的不是一件容易的事情,一方面是需要经常做出改变才可以,不然用户会觉得厂商懈怠了,没有什么创新亮点值得去期待。另一方面,现在的手机产品同质化也变得越来越严重中新财评道歉不是奥迪广告抄袭事件的终点中新财经5月22日电奥迪小满广告抄袭一事刷屏。22日,奥迪发布声明就该事件中因监管不力审核不严向刘德华北大满哥及相关方致歉,并下架相关视频。违法侵权,不是小事。事件的影响不会因一句51岁的马斯克,会不会竞选美国下届总统?话题大发明家图片源自网络马斯克最近宣布收购推特,有关他的新闻每天都在不断地更新,他的言论也常常吸引世人的眼球,人们都在关注并揣测这位世界首富的态度及其真实的政治倾向。图片源自网络马巴西总统马斯克提议收购推特,带来希望的气息路透社5月20日消息,当地时间20日,巴西总统博索纳罗与特斯拉CEO马斯克在巴西会面,讨论农村互联网连接和对亚马孙雨林的监测措施。博索纳罗表示,马斯克对推特公司的收购提议是希望的气为什么比亚迪突然就霸榜了?随着比亚迪换装独家黑科技刀片电池后,比亚迪新能源汽车开始发力,才两年不到,旗下众多车型的销量开始呈井喷式爆发,直至目前,比亚迪已牢牢站稳全球新能源汽车第一的宝座。相信很多之前并不待