foxmail设置oauth2
方法如下:
1、打开Foxmail客户端软件,点击“工具”菜单中的“帐号管理”;
2、进入帐号管理页面后,点击左下角的“新建“。
3、进入Foxmail新建帐号向导后输入您的“电子邮件地址”后点击“下一步”;
4、在此页面选择您新建邮箱的类型(即接收服务器类型),输入“密码”和“帐号描述”后点“下一步”;
5、系统会根据您上步所选的邮箱类型自动匹配对应的接收和发送服务器地址,您只需确认“服务器类型”及“端口号”无误后点击“完成”即可;
6、此时您可在帐号管理弹窗左上角看到新建的邮箱帐号,点击“确定”后即可自由收发邮件了。
一、打开 Foxmail,点击“邮箱”菜单中的“新建邮箱帐户”;
二、进入 Foxmail 向导,输入“电子邮件地址”、“密码”、“帐户名称”、“邮箱中采用的名称”以及路径选择 ,点击“下一步”;
三、接收服务器类型您可以选择POP3或IMAP。
OAuth2 spring cloud spring security
一个原则: 使用前一定先看官方文档,看不懂再来搜寻第三方资料。
一个Spring框架的应用,需要一种能够保护 API 接口的实现,尝试过 OAuth10 ,发现更多的是有关 OAuth20 的讨论,且Spring Security 也有队 OAuth2 的支持,于是转而使用 OAuth2 。
其中核心依赖仅有
其中 Spring Security 已经包含在 Starter 中,无需再次声明,以保持 pom 简洁。
要使用OAuth2 服务器,仅需要使用 @EnableAuthorizationServer 注解。
此外OAuth2 Server还依赖于Spring Security,还需要加上 @EnableWebSecurity 注解。
当然,这还不够,根据Spring Security官方文档,你还需要继承 WebSecurityConfigurerAdapter 类以使Security配置生效。
你可以继承但不做任何改动,以使用默认配置。
OAuthServerConfigclass
启动程序,可以看到 OAuth2 的相关接口已经实现了,Spring 的自动配置已经为我们做了许多工作了,以致于我们可以开箱即用。
值得注意的是,自动配置类为我们生成了一个用户名为: user 的 "user" 和一个 "client" :
尝试携带上面的信息进行 GET 请求:
http://127001:8080/oauth/authorizeclient_id=64b5dabe-a97c-4f60-8492-acd24fc7599d&response_type=code&scope=user&redirect_uri=http://wwwbaiducom
会跳转到 /login 页面进行登录验证,填入 user 和 log 中的密码 d457f3b2-a3d7-4ace-bfaf-44ab7bfd8ccc 即可验证通过。
重新跳转回授权页面,选择 Approve 同意并进行授权后,页面跳转至 redirect_url 并携带 code 信息。
取得 code 之后,就可以向服务器继续请求 access-token 了,使用 POST 方法继续请求。
http://127001:8080/oauth/tokengrant_type=authorization_code&code=bPVWmn&redirect_uri=http://wwwbaiducom&scope=user
不出意外,你将会看到以下信息:
至此,我们已经完成了一整个 authorization_code 类型的OAuth2授权了。
同样的,你只需要一个依赖:
//todo: 未完成
在默认的情况下,spring security oauth2 在发生异常情况下,返回的格式并不符合现实需要,其格式是:
我们一般需要是这种格式
对于oauth2的异常,其类主要是 OAuth2Exception ,默认处理这些异常的是DefaultWebResponseExceptionTranslator,其错误主要是包含oauth2相关的错误,就类似以下的。
DefaultWebResponseExceptionTranslator处理的OAuth2Exception,其类可见的序列化器如下,可以得出默认的返回格式:
所以我们需要重新定义自己的WebResponseExceptionTranslator,以及自己的oauth2异常以及其序列化器(也可以不定义,重写handleOauth2Exception即可)
自定义oauth2异常处理类,CustomWebResponseExceptionTranslator,模仿DefaultWebResponseExceptionTranslator即可,下面给出关键部分,注意result是自己定义返回格式的bean,含有msg和code。最后在认证服务器配置一下就可。
这里说的是oauth2的异常处理,其中还有认证的异常,我们这里使用basic的认证方式,如果发生异常,是不会走这个自定义的异常处理器的,所以在securityConfig中配置,在httpBasic后面配置的那里处理了。
这里加上 httpaddFilterBefore(customBasicAuthenticationFilter, BasicAuthenticationFilterclass);
这个filter其实就是验证一些必要参数有无缺失,并且返回自定义的格式,
还有需要注意是:因为是授权码模式,在获取token的时候,需要传clientId和clientSecret,这是获取token的验证我们需要先于一步再到后面,所以我们会定义个过滤器处理,因为在测试过程,如果不先于验证clientId和clientSecret,返回的错误可能不是预期之中的,这里还不清楚为啥会出现那些特殊情况,所以还是先于一步先校验了、
认证服务器配置上自定义的filter,这个filter会先执行再到后面/oauth2/token链接,还有这里不开启allowFormAuthenticationForClients,还是只限于basic,如果开启了,有可能返回不正确的异常格式,具体原因不明,但后续肯定是不走basicFilter的,自定义的filter还是验证参数完整性和认证clientId和clientSecret身份是否正确。
例示参考:
https://blogcsdnnet/qq_31063463/article/details/83752459
OAuth 是一个开放标准的授权框架,它为第三方应用获取资源所有者在资源所在系统或应用上的部分资源提供了一种解决方案。
也就是说,假如你在腾讯云存了一些,现在你想在美图秀秀上编辑这些;此时的 "你" 就是资源所有者,第三方应用就是美图秀秀,而资源服务器就是腾讯云;
这种情况下美图秀秀直接访问腾讯云是获取不到你的的,所以美图秀秀为了能获取到这些照片就需要授权服务器授权(当然,资源服务器和授权服务器有可能是同一个,也有可能是两个不同的服务)
OAuth 就是为这种类似的场景定义的一套标准,目前已经发展到了 OAuth20 。 OAuth20 在 RFC 的文档地址: https://datatrackerietforg/doc/html/rfc6749
下面可以通过一个场景来解释一下, OAuth20 的原理:一个快递员的问题
假设你住在一个大型的小区中,你经常点外卖,而小区有门禁系统,进入的时候需要输密码
为了能让快递员进入,你就需要为他提供一组密码
如果你直接把你的密码给了快递员,那么他就有了和你一样的权限,如果你想取消他的权限,那只能改密码了,这样你还要通知使用该密码的其他人
所以你打算设计一套授权机制,既能让快递员进来,又能限制他的操作并且能随时回收这个密码
于是,你想出了一套办法,完善门禁系统:
此处为什么要给他生成一个令牌,而不是直接给他开门呢?
因为从小区大门到目的地可能会有多个门禁,所以就不用一直等着给快递员开门了;同样的,如果第二天快递员再来时就不需要再获取权限了
密码和令牌都让获取第三方获取用户数据,但是相较于密码,令牌有如下的有点:
令牌能够有效的控制第三方应用的访问权限和访问时长;当然,令牌也是必须要保密的,因为泄露令牌和泄露密码一样,也会造成安全问题,因此一般令牌的有效时间都会设置的比较短
OAuth20 提供了四种授权方式来应对不同的应用场景,
授权码(authorization code)方式,指的是第三方应用先申请一个授权码,然后再用该码获取令牌。
这种方式是最常用的流程,安全性也最高,它适用于那些有后端的 Web 应用。授权码通过前端传送,令牌则是储存在后端,而且所有与资源服务器的通信都在后端完成。这样的前后端分离,可以避免令牌泄漏。
第一步,A 网站提供一个链接,用户点击后就会跳转到 B 网站,授权用户数据给 A 网站使用。下面就是 A 网站跳转 B 网站的一个示意链接。
上面 URL 中, response_type 参数表示要求返回授权码( code ), client_id 参数让 B 知道是谁在请求, redirect_uri 参数是 B 接受或拒绝请求后的跳转网址, scope 参数表示要求的授权范围(这里是只读)。
第二步,用户跳转后,B 网站会要求用户登录(如果是未登录的情况下),然后询问是否同意给予 A 网站授权;如果用户同意授权,这时 B 网站就会跳回 redirect_uri 参数指定的网址。跳转时,会传回一个授权码,就像下面这样。
上面 URL 中, code 参数就是授权码。注:这个授权码与客户端一一对应,通常只有10分钟的有效期,并且只能使用一次
第三步,A 网站拿到授权码以后,就可以在后端,向 B 网站请求令牌。
上面 URL 中, client_id 参数和 client_secret 参数用来让 B 确认 A 的身份( client_secret 参数是保密的,因此只能在后端发请求), grant_type 参数的值是 AUTHORIZATION_CODE ,表示采用的授权方式是授权码, code 参数是上一步拿到的授权码, redirect_uri 参数是令牌颁发后的回调网址。
第四步,B 网站收到请求以后,就会颁发令牌。具体做法是向 redirect_uri 指定的网址,发送一段 JSON 数据。
上面 JSON 数据中, access_token 字段就是令牌,A 网站在后端拿到了。
有些 Web 应用是纯前端应用,没有后端。这时就不能用上面的方式了,必须将令牌储存在前端。 RFC 6749 就规定了第二种方式,允许直接向前端颁发令牌。这种方式没有授权码这个中间步骤,所以称为(授权码)"隐藏式"(implicit)。
第一步,A 网站提供一个链接,要求用户跳转到 B 网站,授权用户数据给 A 网站使用。
上面 URL 中, response_type 参数为 token ,表示要求直接返回令牌。
第二步,用户跳转到 B 网站,登录后同意给予 A 网站授权。这时,B 网站就会跳回 redirect_uri 参数指定的跳转网址,并且把令牌作为 URL 参数,传给 A 网站。
上面 URL 中, token 参数就是令牌,A 网站因此直接在前端拿到令牌。
注意,令牌的位置是 URL 锚点(fragment),而不是查询字符串(querystring),这是因为 OAuth 20 允许跳转网址是 HTTP 协议,因此存在"中间人攻击"的风险,而浏览器跳转时,锚点不会发到服务器,就减少了泄漏令牌的风险。
如果你高度信任某个应用,RFC 6749 也允许用户把用户名和密码,直接告诉该应用。该应用就使用你的密码,申请令牌,这种方式称为"密码式"(password)。
第一步,A 网站要求用户提供 B 网站的用户名和密码。拿到以后,A 就直接向 B 请求令牌。
上面 URL 中, grant_type 参数是授权方式,这里的 password 表示"密码式", username 和 password 是 B 的用户名和密码。
第二步,B 网站验证身份通过后,直接给出令牌。注意,这时不需要跳转,而是把令牌放在 JSON 数据里面,作为 HTTP 回应,A 因此拿到令牌。
这种方式需要用户给出自己的用户名/密码,显然风险很大,因此只适用于其他授权方式都无法采用的情况,而且必须是用户高度信任的应用。
最后一种方式是凭证式(client credentials),适用于没有前端的命令行应用,即在命令行下请求令牌。
第一步,A 应用在命令行向 B 发出请求。
上面 URL 中, grant_type 参数等于 client_credentials 表示采用凭证式, client_id 和 client_secret 用来让 B 确认 A 的身份。
第二步,B 网站验证通过以后,直接返回令牌。
这种方式给出的令牌,是针对第三方应用的,而不是针对用户的,即有可能多个用户共享同一个令牌。
A 网站拿到令牌以后,就可以向 B 网站的 API 请求数据了。
此时,每个发到 API 的请求,都必须带有令牌。具体做法是在请求的头信息,加上一个 Authorization 字段,令牌就放在这个字段里面。
上面命令中, ACCESS_TOKEN 就是拿到的令牌。
令牌的有效期到了,如果让用户重新走一遍上面的流程,再申请一个新的令牌,很可能体验不好,而且也没有必要。OAuth 20 允许用户自动更新令牌。
具体方法是,B 网站颁发令牌的时候,一次性颁发两个令牌,一个用于获取数据,另一个用于获取新的令牌(refresh token 字段)。令牌到期前,用户使用 refresh token 发一个请求,去更新令牌。
上面 URL 中, grant_type 参数为 refresh_token 表示要求更新令牌, client_id 参数和 client_secret 参数用于确认身份, refresh_token 参数就是用于更新令牌的令牌
OAuth20 描述了授权 (Authorization) 的各种方式,但是这些方式中却没有定义如何进行认证 (Authentication)
认证 (Authentication) 和授权 (Autherization 这两个表示的是不同的动作:
OpeID Connect (OIDC)对 OAuth20 进行了扩展,添加了用户认证的功能,并且它和 OAuth20 的流程是相同的。有区别的地方就是它的认证请求的字段中包含 scope=openid 如下所示:
在返回的响应中包含 ID Token ,用于获取用户身份,如下所示:
这里面有几个问题:
首先,
首先需要保证你的 OAuth20 请求是在 HTTPS 协议下发送的,这样可以防止暴露用户的信息。
其次就是一些钓鱼网站;比如,有一个 A 网站需要获取你在 B 网站上的资源或者数据,所以当你进入 A 网站的某个功能时,它会让你跳转到 B 网站,但是很有可能 B 网站是由 A 网站伪造跳转过来的,此时需要你的授权,当你输入账密的时候,你的账密就泄露了;这些钓鱼网站就是用来收集用户的账密信息的,所以当跳到第二个网站的时候一定要证实该网站是不是你注册过的合法的网站
参考连接:
https://datatrackerietforg/doc/html/rfc6749
https://auth0com/intro-to-iam/what-is-oauth-2/
https://wwwcsoonlinecom/article/3216404/what-is-oauth-how-the-open-authorization-framework-workshtml
https://wwwruanyifengcom/blog/2019/04/oauth_designhtml
https://developeroktacom/blog/2019/10/21/illustrated-guide-to-oauth-and-oidc
https://blogrunscopecom/posts/understanding-oauth-2-and-openid-connect
SSO是Single Sign On的缩写,OAuth是Open Authority的缩写,这两者都是使用令牌的方式来代替用户密码访问应用。流程上来说他们非常相似,但概念上又十分不同。
以上两者,你在业务系统中都没有账号和密码,账号密码是存放在登录中心或微信服务器中的,这就是所谓的使用令牌代替账号密码访问应用。
两者有很多相似之处,下面我们来解释一下这个过程。先来讲解SSO,通过SSO对比OAuth20,才比较好理解OAuth20的原理。SSO的实现有很多框架,比如CAS框架,以下是CAS框架的官方流程图。
上面的流程大概为:
OAuth20有多种模式,这里讲的是OAuth20授权码模式,OAuth20的流程跟SSO差不多
以上,就是我的SSO和OAuth20的理解。
在原先dubbo+zookeeper项目中,web模块只暴露Restful接口,各服务模块只暴露duboo接口,此时用户登录后由web项目进行token的鉴权和验证,并通过dubbo的隐式传参将sessionID传递给dubbo服务模块, 拦截器再根据sessionID从Redis中获取用户信息设置到当前线程
然鹅,在springcloud中,各个微服务直接暴露的是restful接口,此时如何让各个微服务获取到当前用户信息呢?最佳的方式就是token了,token作为BS之间的会话标识(一般是原生随机token),同时也可以作为信息的载体传递一些自定义信息(jwt, 即Json web token)。
为了能更清楚的了解本文,需要对spring-security-oauth 及 jwt有一定了解,本文只关注用户信息传递这一块
认证服务器配置 AuthorizationServerConfigurerAdapter
自定义token转换器
CustomJwtAccessTokenConverter
此时按照固定格式访问授权服务器token接口获取token,如图,可以获取到jwt格式的token,并且额外信息nick_name也已经添加
直接解析jwt字符串可以获取到以下信息,即用户名和授权信息
只需要指定和授权服务器一模一样的token store 和token converter
在securiy的过滤器中 OAuth2AuthenticationProcessingFilter 会从token中获取相关信息进行鉴权
源码:
注意,资源服务器主要配置在
ResourceServerConfigurerAdapter
微服务获取jwttoken中的用户信息,两种方式,使用security上下文可以直接获取当前用户名和权限,另一种自定义拦截器获取额外信息。
这个就简单了,获取header头解析验证token
然后获取之前从授权服务器中的添加的 nick_name的额外信息放入线程变量
其中用户上下文类
启动拦截器注册webmvc配置类
在controller中获取用户信息如图
在默认的认证异常如图
假设我们做了全局异常处理,前端希望在token过期时做统一的登录跳转如何做?
实现 AuthenticationEntryPoint 接口重写 commence 方法即可
注意,直接抛出异常并不会走 @RestControllerAdvice , 因为在这里是response直接返回,并没有使用到Controller处理
此时返回我自定义的Response对象,如图
0条评论