当前位置: 首页 >Java技术 > Spring Security OAuth2 授权码模式

Spring Security OAuth2 授权码模式

 背景:

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

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

 介绍:

      Spring Security OAuth2 授权码模式 _ JavaClub全栈架构师技术笔记

  • 第三方系统调用我方提供的授权接口(步骤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 from30 // 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 have40 // 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 for44 // 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 retu getImplicitGrantResponse(authorizationRequest);55 }56 if (responseTypes.contains("code")) {57 retu new ModelAndView(getAuthorizationCodeResponse(authorizationRequest,58 (Authentication) principal));59 }60 }61 62 // Place auth request into the model so that it is stored in the session63 // 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 retu 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 2public 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第三方配置的回调地址
     stateString第三方自定义使用


  请求示例:

curl -X POST http://localhost:8421/oauth/authorize -H 'Authorization: Bearer b7c2d63f-edff-4790-add9-0b69df7321b5' -d 'response_type=code&client_id=exteal&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=exteal&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/exteal/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

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。





本文链接:https://www.javaclub.cn/java/112562.html

标签:OAuth2
分享给朋友:

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