首页 > 其他分享 >5.OAuth2详解

5.OAuth2详解

时间:2022-11-25 02:44:34浏览次数:80  
标签:Exception OAuth2 return throws token 详解 public 客户端

 

理论

OAuth是一个关于授权(authorization)的开放网络标准,用来授权第三方应用获取用户数据,是目前最流行的授权机制,它当前的版本是2.0。

应用场景

假如你正在“网站A”上冲浪,看到一篇帖子表示非常喜欢,当你情不自禁的想要点赞时,它会提示你进行登录操作。

 

 

 打开登录页面你会发现,除了最简单的账户密码登录外,还为我们提供了微博、微信、QQ等快捷登录方式。假设选择了快捷登录,它会提示我们扫码或者输入账号密码进行登录。

登录成功之后便会将QQ/微信的昵称和头像等信息回填到“网站A”中,此时你就可以进行点赞操作了。

名词定义

在详细讲解oauth2之前,我们先来了解一下它里边用到的名词定义吧:

  • Client:客户端,它本身不会存储用户快捷登录的账号和密码,只是通过资源拥有者的授权去请求资源服务器的资源,即例子中的网站A;
  • Resource Owner:资源拥有者,通常是用户,即例子中拥有QQ/微信账号的用户;
  • Authorization Server:认证服务器,可以提供身份认证和用户授权的服务器,即给客户端颁发token和校验token
  • Resource Server:资源服务器,存储用户资源的服务器,即例子中的QQ/微信存储的用户信息;

认证流程

 

 

 

如图是oauth2官网的认证流程图,我们来分析一下:

  • A客户端向资源拥有者发送授权申请;
  • B资源拥有者同意客户端的授权,返回授权码;
  • C客户端使用授权码向认证服务器申请令牌token
  • D认证服务器对客户端进行身份校验,认证通过后发放令牌;
  • E客户端拿着认证服务器颁发的令牌去资源服务器请求资源;
  • F资源服务器校验令牌的有效性,返回给客户端资源信息;

为了大家更好的理解,阿Q特地画了一张图:

 

 

 

到这儿,相信大家对理论知识已经掌握的差不多了,接下来我们就进入实战训练吧。

实战

在正式开始搭建项目之前我们先来做一些准备工作:要想使用oauth2的服务,我们得先创建几张表。

数据库

oauth2相关的建表语句可以参考官方初始化sql,也可以查看阿Q项目中的init.sql文件,回复“oauth2”获取源码。

 

 

 

至于表结构,大家可以先大体了解下,其中字段的含义,在init.sql文件中阿Q已经做了说明。

  • oauth_client_details:存储客户端的配置信息,操作该表的类主要是JdbcClientDetailsService.java
  • oauth_access_token:存储生成的令牌信息,操作该表的类主要是JdbcTokenStore.java
  • oauth_client_token:在客户端系统中存储从服务端获取的令牌数据,操作该表的类主要是JdbcClientDetailsService.java
  • oauth_code:存储授权码信息与认证信息,即只有grant_typeauthorization_code时,该表才会有数据,操作该表的类主要是JdbcAuthorizationCodeServices.java
  • oauth_approvals:存储用户的授权信息;
  • oauth_refresh_token:存储刷新令牌的refresh_token,如果客户端的grant_type不支持refresh_token,那么不会用到这张表,操作该表的类主要是JdbcTokenStore

oauth_client_details表中添加一条数据

1 client_id:cheetah_one //客户端名称,必须唯一
2 resource_ids:product_api //客户端所能访问的资源id集合,多个资源时用逗号(,)分隔
3 client_secret:$2a$10$h/TmLPvXozJJHXDyJEN22ensJgaciomfpOc9js9OonwWIdAnRQeoi //客户端的访问密码
4 scope:read,write //客户端申请的权限范围,可选值包括read,write,trust。若有多个权限范围用逗号(,)分隔
5 authorized_grant_types:client_credentials,implicit,authorization_code,refresh_token,password //指定客户端支持的grant_type,可选值包括authorization_code,password,refresh_token,implicit,client_credentials, 若支持多个grant_type用逗号(,)分隔
6 web_server_redirect_uri:http://www.baidu.com //客户端的重定向URI,可为空, 当grant_type为authorization_code或implicit时, 在Oauth的流程中会使用并检查与注册时填写的redirect_uri是否一致
7 access_token_validity:43200 //设定客户端的access_token的有效时间值(单位:秒),可选, 若不设定值则使用默认的有效时间值(60 * 60 * 12, 12小时)
8 autoapprove:false //设置用户是否自动Approval操作, 默认值为 'false', 可选值包括 'true','false', 'read','write'

数据库中对密码进行了加密处理,大家可以在此路径下自行生成

 

 

 用户角色相关的表也在init.sql文件中,表结构非常简单,大家自行查阅。我的初始化数据为

依赖引入

 1 <dependency>
 2  <groupId>org.springframework.boot</groupId>
 3  <artifactId>spring-boot-starter-web</artifactId>
 4 </dependency>
 5 <dependency>
 6  <groupId>org.springframework.cloud</groupId>
 7  <artifactId>spring-cloud-starter-security</artifactId>
 8 </dependency>
 9 <dependency>
10  <groupId>org.springframework.cloud</groupId>
11  <artifactId>spring-cloud-starter-oauth2</artifactId>
12 </dependency>
13 <dependency>
14  <groupId>org.springframework.security</groupId>
15  <artifactId>spring-security-jwt</artifactId>
16 </dependency>

至于其它依赖,大家可以根据需要自行引入,不再赘述,回复“oauth2”获取源码。

资源服务

配置文件对服务端口、应用名称、数据库、mybatis和日志进行了配置。

写了一个简单的控制层代码,用来模拟资源访问

1 @RestController
2 @RequestMapping("/product")
3 public class ProductController {
4 
5     @GetMapping("/findAll")
6     public String findAll(){
7         return "产品列表查询成功";
8     }
9 }

接着创建配置类继承ResourceServerConfigurerAdapter并增加@EnableResourceServer注解开启资源服务,重写两个configure方法

 1 /**
 2  * 指定token的持久化策略
 3  * InMemoryTokenStore 表示将token存储在内存中
 4  * RedisTokenStore 表示将token存储在redis中
 5  * JdbcTokenStore 表示将token存储在数据库中
 6  * @return
 7  */
 8 @Bean
 9 public TokenStore jdbcTokenStore(){
10     return new JdbcTokenStore(dataSource);
11 }
12 
13 /**
14  * 指定当前资源的id和token的存储策略
15  * @param resources
16  * @throws Exception
17  */
18 @Override
19 public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
20     //此处的id可以写在配置文件中,这里我们先写死
21  resources.resourceId("product_api").tokenStore(jdbcTokenStore());
22 }
23 
24 
25 /**
26  * 设置请求权限和header处理
27  * @param http
28  * @throws Exception
29  */
30 @Override
31 public void configure(HttpSecurity http) throws Exception {
32  //固定写法
33  http.authorizeRequests()
34    //指定不同请求方式访问资源所需的权限,一般查询是read,其余都是write
35    .antMatchers(HttpMethod.GET,"/**").access("#oauth2.hasScope('read')")
36    .antMatchers(HttpMethod.POST,"/**").access("#oauth2.hasScope('write')")
37    .antMatchers(HttpMethod.PATCH,"/**").access("#oauth2.hasScope('write')")
38    .antMatchers(HttpMethod.PUT,"/**").access("#oauth2.hasScope('write')")
39    .antMatchers(HttpMethod.DELETE,"/**").access("#oauth2.hasScope('write')")
40    .and()
41    .headers().addHeaderWriter((request,response) -> {
42     //域名不同或者子域名不一样并且是ajax请求就会出现跨域问题
43     //允许跨域
44     response.addHeader("Access-Control-Allow-Origin","*");
45     //跨域中会出现预检请求,如果不能通过,则真正请求也不会发出
46     //如果是跨域的预检请求,则原封不动向下传递请求头信息,否则预检请求会丢失请求头信息(主要是token信息)
47     if(request.getMethod().equals("OPTIONS")){
48      response.setHeader("Access-Control-Allow-Methods",request.getHeader("Access-Control-Allow-Methods"));
49      response.setHeader("Access-Control-Allow-Headers",request.getHeader("Access-Control-Allow-Headers"));
50     }
51  });
52 }

当然我们也可以配置忽略校验的url,在上边的public void configure(HttpSecurity http) throws Exception中进行配置

1 ExpressionUrlAuthorizationConfigurer<HttpSecurity>
2   .ExpressionInterceptUrlRegistry config = http.requestMatchers().anyRequest()
3   .and()
4   .authorizeRequests();
5 properties.getUrls().forEach(e -> {
6  config.antMatchers(e).permitAll();
7 });

因为我们是需要进行校验的,所以我把对应的代码给注释掉了,大家可以回复“oauth2”下载源码自行查看。

然后将实现了UserDetailsSysUser和实现了GrantedAuthoritySysRole放到项目中,当请求发过来时,oauth2会帮我们自行校验。

认证服务

配置文件对服务端口、应用名称、数据库、mybatis和日志进行了配置。

Security配置

还是和之前Security+JWT组合拳的配置大同小异,不了解的可以先看下该文。

①将继承了UserDetailsServiceISysUserService的实现类SysUserServiceImpl重写loadUserByUsername方法

1 @Override
2 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
3  return this.baseMapper.selectOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername, username));
4 }

②继承WebSecurityConfigurerAdapter类,增加@EnableWebSecurity注解并重写方法

 1 /**
 2  * 指定认证对象的来源和加密方式
 3  * @param auth
 4  * @throws Exception
 5  */
 6 @Override
 7 public void configure(AuthenticationManagerBuilder auth) throws Exception {
 8  auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
 9 }
10 
11 /**
12  * 安全拦截机制(最重要)
13  * @param httpSecurity
14  * @throws Exception
15  */
16 @Override
17 public void configure(HttpSecurity httpSecurity) throws Exception {
18  httpSecurity
19    //CSRF禁用,因为不使用session
20    .csrf().disable()
21    .authorizeRequests()
22    //登录接口和静态资源不需要认证
23    .antMatchers("/login*","/css/*").permitAll()
24    //除上面的所有请求全部需要认证通过才能访问
25    .anyRequest().authenticated()
26    //返回HttpSecurity以进行进一步的自定义,证明是一次新的配置的开始
27    .and()
28    .formLogin()
29    //如果未指定此页面,则会跳转到默认页面
30 //                .loginPage("/login.html")
31    .loginProcessingUrl("/login")
32    .permitAll()
33    //认证失败处理类
34    .failureHandler(customAuthenticationFailureHandler);
35 }
36 
37 /**
38  * AuthenticationManager 对象在OAuth2.0认证服务中要使用,提前放入IOC容器中
39  * @return
40  * @throws Exception
41  */
42 @Override
43 @Bean
44 public AuthenticationManager authenticationManagerBean() throws Exception {
45  return super.authenticationManagerBean();
46 }

AuthorizationServer配置

①继承AuthorizationServerConfigurerAdapter类,增加@EnableAuthorizationServer注解开启认证服务

②依赖注入,注入7个实例Bean对象

 1 /**
 2  * 数据库连接池对象
 3  */
 4 private final DataSource dataSource;
 5 
 6 /**
 7  * 认证业务对象
 8  */
 9 private final ISysUserService userService;
10 
11 /**
12  * 授权码模式专用对象
13  */
14 private final AuthenticationManager authenticationManager;
15 
16 /**
17  * 客户端信息来源
18  * @return
19  */
20 @Bean
21 public JdbcClientDetailsService jdbcClientDetailsService(){
22    return new JdbcClientDetailsService(dataSource);
23 }
24 
25 /**
26  * token保存策略
27  * @return
28  */
29 @Bean
30 public TokenStore tokenStore(){
31  return new JdbcTokenStore(dataSource);
32 }
33 
34 /**
35  * 授权信息保存策略
36  * @return
37  */
38 @Bean
39 public ApprovalStore approvalStore(){
40  return new JdbcApprovalStore(dataSource);
41 }
42 
43 /**
44  * 授权码模式数据来源
45  * @return
46  */
47 @Bean
48 public AuthorizationCodeServices authorizationCodeServices(){
49  return new JdbcAuthorizationCodeServices(dataSource);
50 }

③重写方法进行配置

 1 /**
 2  * 用来配置客户端详情服务(ClientDetailsService)
 3  * 客户端详情信息在这里进行初始化
 4  * 指定客户端信息的数据库来源
 5  * @param clients
 6  * @throws Exception
 7  */
 8 @Override
 9 public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
10  clients.withClientDetails(jdbcClientDetailsService());
11 }
12 
13 /**
14  * 检测 token 的策略
15  * @param security
16  * @throws Exception
17  */
18 @Override
19 public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
20  security
21    //允许客户端以form表单的方式将token传达给我们
22    .allowFormAuthenticationForClients()
23    //检验token必须需要认证
24    .checkTokenAccess("isAuthenticated()");
25 }
26 
27 
28 /**
29  * OAuth2.0的主配置信息
30  * @param endpoints
31  * @throws Exception
32  */
33 @Override
34 public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
35  endpoints
36    //刷新token时会验证当前用户是否已经通过认证
37    .userDetailsService(userService)
38    .approvalStore(approvalStore())
39    .authenticationManager(authenticationManager)
40    .authorizationCodeServices(authorizationCodeServices())
41    .tokenStore(tokenStore());
42 }

 

标签:Exception,OAuth2,return,throws,token,详解,public,客户端
From: https://www.cnblogs.com/midiyu/p/16924013.html

相关文章

  • 操作符详解(day13)
    操作符是直接对内存里存储的值进行操作,而函数是更外层的操作方式。以操作整形变量举例:在内存中,整数都是以补码形式存储的,所以操作符可以直接操纵内存中的补码的值,而printf函......
  • Windows server 2008 R2 多用户远程桌面配置详解(超过两个用户)
    这篇文章主要介绍了Windowsserver2008R2多用户远程桌面配置详解(超过两个用户),需要的朋友可以参考下 注意:一下是针对win2008 serverr2的操作1、创建三个本地......
  • Maven学习-Profile详解
    Profile能让你为一个特殊的环境自定义一个特殊的构建;profile使得不同环境间构建的可移植性成为可能。Maven中的profile是一组可选的配置,可以用来设置或者覆盖配置默认值。有......
  • COCO-WholeBody 注释详解
    官方数据集说明:https://github.com/jin-s13/COCO-WholeBody1.如何预览json文件?使用Vscode,右键格式化文档即可。2.字段解读2.1关键字段之"images""images":[......
  • @Aspect 注解使用详解
    AOP为AspectOrientedProgramming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是​​OOP​​​的延续,是软件开发中的一个......
  • golang 反向代理 Gin框架反向代理详解
    前言想用gin框架做一个反向代理服务,搜索了一圈,全是只讲解些皮毛的帖子,今天我就总结一下gin做反向代理的详细操作和原理正文开始之前我们先了解一些前置知识gin的通配符......
  • 网络性能评估工具Iperf详解
     一、网络性能评估工具Iperf网络性能评估主要是监测网络带宽的使用率,将网络带宽利用最大化是保证网络性能的基础,但是由于网络设计不合理、网络存在安全漏洞等原因,都会导......
  • SD NAND 的 SDIO在STM32上的应用详解(中篇)
    四.SDIO功能框图(重点)SDIO包含2个部分:●SDIO适配器模块:实现所有MMC/SD/SDI/O卡的相关功能,如时钟的产生、命令和数据的传送。●AHB总线接口:操作SDIO适配器模块中的寄存器......
  • VC++模拟键盘输入(keybd_event() 、 PostMessage() /SendMessage()、SendInput())详解
                                           VC++模拟键盘输入找了一周,终于找到模拟键......
  • pat 并查集题目代码详解
    不得不吐槽并查集的题太少了1118:1//一道并查集查询的题目2//需要注意的几个点3//输入的时候在进行合并时,是一个一个输入的,所以需要引入一个变量来存储前一个输......