zoukankan      html  css  js  c++  java
  • 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}}

     

        

     

        

  • 相关阅读:
    Ubuntu 14.04 卸载通过源码安装的库
    Ubuntu 14.04 indigo 相关依赖
    Ubuntu 14.04 indigo 安装 cartographer 1.0.0
    Ubuntu 14.04 改变文件或者文件夹的拥有者
    安装cartographer遇到Unrecognized syntax identifier "proto3". This parser only recognizes "proto2"问题
    Unrecognized syntax identifier "proto3". This parser only recognizes "proto2". ”问题解决方法
    查看所有用户组,用户名
    1卸载ROS
    Ubuntu14.04 软件安装卸载
    Ubuntu14.04系统显示器不自动休眠修改
  • 原文地址:https://www.cnblogs.com/mxmbk/p/9882860.html
Copyright © 2011-2022 走看看