Spring Security OAuth2 授权码模式

 背景:

由于业务实现中涉及到接入第三方系统(app接入有赞商城等),所以涉及到第三方系统需要获取用户信息(用户手机号、姓名等),为了保证用户信息的安全和接入方式的统一,

采用Oauth2四种模式之一的授权码模式。

 介绍:

      

  • 第三方系统调用我方提供的授权接口(步骤1)
  • 用户同意授权,后跳转第三方系统(步骤2、3)
  • 第三方系统获得code,根据code到我方系统获取token(步骤5、6 )
  • 根据获取token访问受保护的资源(步骤8、9)

   实际应用中由于合作商户,所以需要直接返回code,不需要用户手动授权,即静默模式,所以需要扩展框架,使其支持自动授权

扩展:

     项目使用的是spring-security-oauth2-2.0.15 由于默认情况下,需要用户授权通过才能生成授权码。所以需简要对框架进行扩展

(1)spring-security-oauth2获取code的controller:

 1 RequestMapping(value = "/oauth/authorize")
 2     public ModelAndView authorize(Map<String, Object> model, @RequestParam Map<String, String> parameters,
 3             SessionStatus sessionStatus, Principal principal) {
 4
 5         // Pull out the authorization request first, using the OAuth2RequestFactory. All further logic should
 6         // query off of the authorization request instead of referring back to the parameters map. The contents of the
 7         // parameters map will be stored without change in the AuthorizationRequest object once it is created.
 8         AuthorizationRequest authorizationRequest = getOAuth2RequestFactory().createAuthorizationRequest(parameters);
 9
10         Set<String> responseTypes = authorizationRequest.getResponseTypes();
11
12         if (!responseTypes.contains("token") && !responseTypes.contains("code")) {
13             throw new UnsupportedResponseTypeException("Unsupported response types: " + responseTypes);
14         }
15
16         if (authorizationRequest.getClientId() == null) {
17             throw new InvalidClientException("A client id must be provided");
18         }
19
20         try {
21
22             if (!(principal instanceof Authentication) || !((Authentication) principal).isAuthenticated()) {
23                 throw new InsufficientAuthenticationException(
24                         "User must be authenticated with Spring Security before authorization can be completed.");
25             }
26
27             ClientDetails client = getClientDetailsService().loadClientByClientId(authorizationRequest.getClientId());
28
29             // The resolved redirect URI is either the redirect_uri from the parameters or the one from
30             // clientDetails. Either way we need to store it on the AuthorizationRequest.
31             String redirectUriParameter = authorizationRequest.getRequestParameters().get(OAuth2Utils.REDIRECT_URI);
32             String resolvedRedirect = redirectResolver.resolveRedirect(redirectUriParameter, client);
33             if (!StringUtils.hasText(resolvedRedirect)) {
34                 throw new RedirectMismatchException(
35                         "A redirectUri must be either supplied or preconfigured in the ClientDetails");
36             }
37             authorizationRequest.setRedirectUri(resolvedRedirect);
38
39             // We intentionally only validate the parameters requested by the client (ignoring any data that may have
40             // been added to the request by the manager).
41             oauth2RequestValidator.validateScope(authorizationRequest, client);
42
43             // Some systems may allow for approval decisions to be remembered or approved by default. Check for
44             // such logic here, and set the approved flag on the authorization request accordingly.
45             authorizationRequest = userApprovalHandler.checkForPreApproval(authorizationRequest,
46                     (Authentication) principal);
47             // TODO: is this call necessary?
48             boolean approved = userApprovalHandler.isApproved(authorizationRequest, (Authentication) principal);
49             authorizationRequest.setApproved(approved);
50
51             // Validation is all done, so we can check for auto approval...
52             if (authorizationRequest.isApproved()) {
53                 if (responseTypes.contains("token")) {
54                     return getImplicitGrantResponse(authorizationRequest);
55                 }
56                 if (responseTypes.contains("code")) {
57                     return new ModelAndView(getAuthorizationCodeResponse(authorizationRequest,
58                             (Authentication) principal));
59                 }
60             }
61
62             // Place auth request into the model so that it is stored in the session
63             // for approveOrDeny to use. That way we make sure that auth request comes from the session,
64             // so any auth request parameters passed to approveOrDeny will be ignored and retrieved from the session.
65             model.put("authorizationRequest", authorizationRequest);
66
67             return getUserApprovalPageResponse(model, authorizationRequest, (Authentication) principal);
68
69         }
70         catch (RuntimeException e) {
71             sessionStatus.setComplete();
72             throw e;
73         }
74
75     }

52行到59行可知, 当approved 为true的时候会直接返回code码,不会需要用户授权,所以问题变成了如何让扩展的userApprovalHandler生效

(2)扩展的userApprovalHandler生效

 1   @Override
 2   public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
 3     endpoints
 4         .tokenStore(tokenStore)
 5         .authenticationManager(authenticationManager)
 6         .userDetailsService(authUserDetailService)
 7         .authorizationCodeServices(new JdbcAuthorizationCodeServices(dataSource))
 8         .reuseRefreshTokens(false)
 9         .userApprovalHandler(new AuthApprovalHandler())
10         .exceptionTranslator(customWebResponseExceptionTranslator)
11     ;
12   }

9行:AuthotizationServer中增加配置自定义配置

应用:

(1)获取code值

需要APP端定制webview开发,根据/oauth/authrorize路径参数中增加token

  请求路径:

  参数说明:


参数名称

类型

是否必填

描述
response_type
String 固定值“code”
client_id
String 第三方配置的client_id
redirect_uri
String 第三方配置的回调地址
     state String 第三方自定义使用


  请求示例:

curl -X POST http://localhost:8421/oauth/authorize -H ‘Authorization: Bearer b7c2d63f-edff-4790-add9-0b69df7321b5‘ -d ‘response_type=code&client_id=external&redirect_uri=http://www.baidu.com&state=123‘

   返回结果:  重定向redirect_uri路径

(2)获取accessToken(有效期暂定72h

请求参数:


参数名称

类型

是否必填

描述
client_id
String 第三方配置的client_id
client_secret
String 第三方配置的密钥
    code String 申请的code
grant_type
String 固定值“authorization_code”
redirect_uri
String 第三方配置的回调地址,必须与生成code时的uri一样

  请求示例:

curl -X POST http://localhost:8421/oauth/token -d ‘grant_type=authorization_code&client_id=external&client_secret=D524C1A0811DA49592F841085CC0063EB62B3001252A94542795D1CA9824A941&redirect_uri=http://www.baidu.com&code=4TCYkV‘

  返回结果:

{"access_token":"95b5be18-49a3-44e1-a527-d5da036cfc3f","token_type":"bearer","refresh_token":"b4488c7d-1e8c-4317-a955-1f4bda013a35","expires_in":9891370,"scope":"auth_base"}

  (3) 获取refreshToken

暂时不支持

  (4) 访问资源(用户信息)

根据获取到的授权token访问用户资源信息

请求示例:

curl -X POST https://wuxi.test.brightcns.cn/api/v2/user/external/info -H ‘Authorization: Bearer e86d752e-8d72-4a33-aa98-8e158ac5b50b‘

 返回结果:

{"success":true,"msg":"success","code":"SUCCESS","data":{"userId":4738295200051366773,"phone":13916413714,"nickname":"13916413714","avatar":"http://wxcardoss.oss-cn-shanghai.aliyuncs.com/null","realName":null,"extendParam":null}}

 

    

原文地址:https://www.cnblogs.com/mxmbk/p/9882860.html

时间: 2024-09-29 02:15:47

Spring Security OAuth2 授权码模式的相关文章

Spring Security 解析(七) —— Spring Security Oauth2 源码解析

Spring Security 解析(七) -- Spring Security Oauth2 源码解析 ??在学习Spring Cloud 时,遇到了授权服务oauth 相关内容时,总是一知半解,因此决定先把Spring Security .Spring Security Oauth2 等权限.认证相关的内容.原理及设计学习并整理一遍.本系列文章就是在学习的过程中加强印象和理解所撰写的,如有侵权请告知. 项目环境: JDK1.8 Spring boot 2.x Spring Security

Spring Security OAuth2 授权失败(401 问题整理

Spring Cloud架构中采用Spring Security OAuth2作为权限控制,关于OAuth2详细介绍可以参考 http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html 项目中采用OAuth2四种模式中的两种,Password模式和Client模式, Password模式用于控制用户的登录,Client模式用于控制后端服务相互调用. 权限架构调整后在近期发现一些问题,由于网上资料不多,只能单步调试方式看源码 (其实带着问题看源码是最

Spring Security OAuth2 Demo —— 密码模式(Password)

前情回顾 前几节分享了OAuth2的流程与授权码模式和隐式授权模式两种的Demo,我们了解到授权码模式是OAuth2四种模式流程最复杂模式,复杂程度由大至小:授权码模式 > 隐式授权模式 > 密码模式 > 客户端模式 其中密码模式的流程是:让用户填写表单提交到授权服务器,表单中包含用户的用户名.密码.客户端的id和密钥的加密串,授权服务器先解析并校验客户端信息,然后校验用户信息,完全通过返回access_token,否则默认都是401 http状态码,提示未授权无法访问 本文目标 编写与

Spring Security OAuth2 Demo —— 客户端模式(ClientCredentials)

前情回顾 前几节分享了OAuth2的流程与其它三种授权模式,这几种授权模式复杂程度由大至小:授权码模式 > 隐式授权模式 > 密码模式 > 客户端模式 本文要讲的是最后一种也是最简单的模式:客户端模式 其中客户端模式的流程是:客户端使用授权服器给的标识与secret访问资源服务器获取token 本文目标 编写与说明密码模式的Spring Security Oauth2的demo实现,让未了解过相关知识的读者对客户端模式授权流程有个更直观的概念 以下分成授权服务器与资源服务器分别进行解释,

springboot+spring security +oauth2.0 demo搭建(password模式)(认证授权端与资源服务端分离的形式)

项目security_simple(认证授权项目) 1.新建springboot项目 这儿选择springboot版本我选择的是2.0.6 点击finish后完成项目的创建 2.引入maven依赖  下面是我引入的依赖 1 <?xml version="1.0" encoding="UTF-8"?> 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi=&q

Microsoft.Owin.Security 自定义AuthenticationHandler 实现oauth2 的授权码模式

三个网站: 1. www.cnblogs.com        用户直接面对和使用的web应用   以后简称w 2.passport.cnblogs.com   认证服务器,可以访问用户表的用户名和密码                             以后简称p 3.users.cnblogs.com        给其它应用程序提供服务,本例当中只是提供授权用户的个人信息,例如手机 邮箱等信息                            以后简称u 利用 Microsoft.

Springboot2.0 + OAuth2.0之授权码模式

综述:上两回讲了密码模式,应该是浅显易懂.如有补充,不足或者是有误之处还请多多指出.现在重头戏,授权码模式开始. 一.具体操作流程 - 用户访问客户端,后者将前者导向认证服务器,认证服务器返回认证页面(账号密码或者其他认证方式) - 用户选择是否给予客户端授权. - 假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个授权码. - 客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌.这

Oauth2.0认证---授权码模式

目录: 1.功能描述 2.客户端的授权模式 3.授权模式认证流程 4.代码实现 1.功能描述 OAuth在"客户端"与"服务提供商"之间,设置了一个授权层(authorization layer)."客户端"不能直接登录"服务提供商",只能登录授权层,以此将用户与客户端区分开来. "客户端"登录授权层所用的令牌(token),与用户的密码不同.用户可以在登录的时候,指定授权层令牌的权限范围和有效期. 2.客

Spring Security 入门(1-3)Spring Security oauth2.0 指南

入门 这是支持OAuth2.0的用户指南.对于OAuth1.0,一切都是不同的,所以看它的用户指南. 本用户指南分为两个部分,第一部分是OAuth2.0提供端(OAuth 2.0 Provider),第二部分是OAuth2.0的客户端(OAuth 2.0 Client) OAuth2.0提供端 OAuth2.0的提供端的用途是负责将受保护的资源暴露出去.建立一个可以访问受保护的资源的客户端列表. 提供端是通过管理和验证可用于访问受保护的资源的OAuth 2令牌来做的. 在适当的地方,提供端必须为