实战:画了几张图,终于把OAuth2搞清楚了

网站建设3年前发布
41 0 0

OAuth​是一个关于授权(authorization)的开放网络标准,用来授权第三方应用获取用户数据,是目前最流行的授权机制,它当前的版本是2.0。,假如你正在“网站A”上冲浪,看到一篇帖子表示非常喜欢,当你情不自禁的想要点赞时,它会提示你进行登录操作。,20230306131610a2c3d5b756220bb709b8972709cf777cd0c864821,打开登录页面你会发现,除了最简单的账户密码登录外,还为我们提供了微博、微信、QQ等快捷登录方式。假设选择了快捷登录,它会提示我们扫码或者输入账号密码进行登录。,202303061316107202087965426d112ac178162cbb18275427d9716,登录成功之后便会将QQ/微信的昵称和头像等信息回填到“网站A”中,此时你就可以进行点赞操作了。,在详细讲解oauth2之前,我们先来了解一下它里边用到的名词定义吧:,Client:客户端,它本身不会存储用户快捷登录的账号和密码,只是通过资源拥有者的授权去请求资源服务器的资源,即例子中的网站A;,Resource Owner:资源拥有者,通常是用户,即例子中拥有QQ/微信账号的用户;,Authorization Server:认证服务器,可以提供身份认证和用户授权的服务器,即给客户端颁发token和校验token;,Resource Server:资源服务器,存储用户资源的服务器,即例子中的QQ/微信存储的用户信息;,2023030613161292653c0671dcd7cee6734121a30e44ca0f4204934,如图是oauth2官网的认证流程图,我们来分析一下:,为了大家更好的理解,阿Q特地画了一张图:,2023030613161299b35be85ef7da7c0b709856a9d4c9ac909877117,到这儿,相信大家对理论知识已经掌握的差不多了,接下来我们就进入实战训练吧。,在正式开始搭建项目之前我们先来做一些准备工作:要想使用oauth2的服务,我们得先创建几张表。,oauth2相关的建表语句可以参考官方初始化sql,也可以查看阿Q项目中的init.sql文件,回复“oauth2”获取源码。,20230306131710823f0ca613b3e3aceec9540f887dcb9a04576c877,至于表结构,大家可以先大体了解下,其中字段的含义,在init.sql文件中阿Q已经做了说明。,在oauth_client_details表中添加一条数据,数据库中对密码进行了加密处理,大家可以在此路径下自行生成,20230306131612b732f1d89aa306efd0d26332d01574435ce3d1252,用户角色相关的表也在init.sql文件中,表结构非常简单,大家自行查阅。我的初始化数据为,20230306131613b451d5487ab708eb152548e518864f5b47086e304,至于其它依赖,大家可以根据需要自行引入,不再赘述,回复“oauth2”获取源码。,配置文件对服务端口、应用名称、数据库、mybatis和日志进行了配置。,写了一个简单的控制层代码,用来模拟资源访问,接着创建配置类继承ResourceServerConfigurerAdapter并增加@EnableResourceServer注解开启资源服务,重写两个configure方法,当然我们也可以配置忽略校验的​​url​​,在上边的​​public void configure(HttpSecurity http) throws Exception​​中进行配置,因为我们是需要进行校验的,所以我把对应的代码给注释掉了,大家可以回复“oauth2”下载源码自行查看。,然后将实现了UserDetails​的SysUser​和实现了GrantedAuthority​的SysRole​放到项目中,当请求发过来时,oauth2会帮我们自行校验。,配置文件对服务端口、应用名称、数据库、mybatis和日志进行了配置。,还是和之前Security+JWT组合拳的配置大同小异,不了解的可以先看下该文。,①将继承了UserDetailsService​的ISysUserService​的实现类SysUserServiceImpl​重写loadUserByUsername方法,②继承WebSecurityConfigurerAdapter​类,增加@EnableWebSecurity注解并重写方法,①继承AuthorizationServerConfigurerAdapter类,增加@EnableAuthorizationServer注解开启认证服务,②依赖注入,注入7个实例Bean对象,③重写方法进行配置,其它关于用户表和权限表的代码可参考源码,回复“oauth2”获取源码。,我们前边所讲的内容都是基于授权码模式,授权码模式被称为最安全的一种模式,它获取令牌的操作是在两个服务端进行的,极大的减小了令牌泄漏的风险。,启动两个服务,当我们再次请求127.0.0.1:9002/product/findAll接口时会提示以下错误,①调用接口获取授权码,发送127.0.0.1:9001/oauth/authorize?response_type=code&client_id=cheetah_one​请求,前边的路径是固定形式的,response_type=code​表示获取授权码,client_id=cheetah_one表示客户端的名称是我们数据库配置的数据。,2023030613161357bfe261402dac5d14034885f5ae9d3a2b620d434,该页面是oauth2​的默认页面,输入用户的账户密码点击登录会提示我们进行授权,这是数据库oauth_client_details​表我们设置autoapprove​为false起到的效果。,20230306131711314836753047861d544525cac8729f792452bb224,选择Approve​点击Authorize​按钮,会发现我们设置的回调地址(oauth_client_details​表中的web_server_redirect_uri​)后边拼接了code值,该值就是授权码。,20230306131615487e934078e6e04078344548f48fca83493047622,查看数据库发现oauth_approvals和oauth_code表已经存入数据了。,拿着授权码去获取token,20230306131616e832f8157dff028dcb9981e49c2b18e634b8f4619,获取到token​之后oauth_access_token和oauth_refresh_token​表中会存入数据以用于后边的认证。而oauth_code​表中的数据被清除了,这是因为code​值是直接暴漏在网页链接上的,oauth2​为了防止他人拿到code非法请求而特意设置为仅用一次。,拿着获取到的token去请求资源服务的接口,此时有两种请求方式,20230306131617e6df835226704af875f407fd1e1b7ae22eada0507,​接下来我们再来看一下oauth2的其它模式。,所谓简化模式是针对授权码模式进行的简化,它将授权码模式中获取授权码的步骤省略了,直接去请求获取token。​,2023030613161787e0227674348f53e2e34523f96e9567ba441a260,流程:发送请求127.0.0.1:9001/oauth/authorize?response_type=token&client_id=cheetah_one​跳转到登录页进行登录,response_type=token​表示获取token。,输入账号密码登录之后会直接在浏览器返回token​,我们就可以像授权码方式一样携带token去请求资源了。,2023030613161752fa3d280c3df5b535a694300775d51c60f4d7376,该模式的弊端就是token直接暴漏在浏览器中,非常不安全,不建议使用。,密码模式下,用户需要将账户和密码提供给客户端向认证服务器申请令牌,所以该种模式需要用户高度信任客户端。,2023030613171292c1e7e516dc044edb49119ed999e006ceb514845,流程:请求如下,20230306131618c29cfd0287fe7e65b1f4268abfb71378be2f2b944,获取成功之后可以去访问资源了。,客户端模式已经不太属于​​oauth2​​的范畴了,用户直接在客户端进行注册,然后客户端去认证服务器获取令牌时不需要携带用户信息,完全脱离了用户,也就不存在授权问题了。,20230306131619c6c16ca46f120ff9359153611492859ef71812200,发送请求如下,20230306131619762327d1958713467fd96138cccf54b7001e98426,获取成功之后可以去访问资源了。,20230306131713c2f12da02410181124f782af19b6d135e87e14258,除了我们在数据库中为客户端配置资源服务外,我们还可以动态的给用户分配接口的权限。,①开启Security内置的动态配置,在开启资源服务时给ResourceServerConfig​类增加注解@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled = true),②给接口增加权限,③在用户登录时设置用户权限,然后测试会发现可以正常访问。,当我在创建项目的时候,给product​和server两个模块设置了不同的包名,导致发送请求获取资源时报错。,经过分析得知,在登录账号时会将用户的信息存储到oauth_access_token​表的authentication​中,在进行token​校验时会根据token_id​取出该字段进行反序列化,如果此时发现包名不一致便会导致解析token失败,因此请求资源失败。,两个项目的包名改为一致;,可以将用户和权限的实体抽成单独的模块,供其它模块引用;,loadUserByUsername​方法中使用的用户实体类不需要继承UserDetailsService​类,每次返回时用user类包装一下即可;,当我在进行权限校验测试时,在设置权限时发现少打了一个单词,导致请求一直出错。修改完成之后继续请求,仍提示权限不足。,于是我将数据库中oauth_refresh_token​和oauth_access_token的数据清除,重新开始测试就可以了。,个人认为是生成token​时发现数据库中token​存在,故不刷新token​,但进行校验时却用带有权限标识的token前去校验导致失败。,至于其它的小坑在这不再赘述,如果遇到问题,建议按照流程对比我的源码仔细检查,回复“oauth2”获取源码。,本文从原理、应用场景、认证流程出发,对oauth2进行了基本的讲解,并且手把手带大家完成了项目的搭建。大家在对授权码模式、简化模式、密码模式、客户端模式进行测试的同时要将重点放到授权码模式上。,

© 版权声明

相关文章