当前位置:   article > 正文

oauth2 授权码模式 流程说明和接口整理

oauth2 授权码模式 流程说明和接口整理

一、说明

oauth2 授权模式一共有四种,即隐式授权模式、授权码授权模式、密码授权模式和客户端授权模式。
这里仅对授权码授权模式所包含的流程和接口做说明和整理。
具体的概念和源码解读,资料有很多,可以自行去搜索学习。

二、流程说明

假设有这样一个场景:现有A系统和B系统,A系统想要使用B系统的账号来做三方登录,那么A系统就必须要获取B系统的授权,以便拿到B系统的用户信息。(可以参考微信账号的三方登录场景)
想要实现以上场景就可以使用oauth2的授权码模式,具体流程参考下图:

oauth2-授权码授权模式

其中clientId、clientSecret、redirectUri等信息涉及到的表是:oauth_client_details

三、所涉及到的接口以及代码整理

以下会对接口做简要说明,最重要的是整理涉及到的自定义配置
想要了解具体代码逻辑实现,可以重点看一下 AuthorizationEndpoint 这个类的源码

① /oauth/authorize 接口 GET请求

该接口对应上图的第一步,即传递参数,获取B系统的登录界面。

authorize-get
oauth2的登录界面很丑,很难满足实际使用场景,可以通过在认证服务器配置中使用自定义的登录页面替换。

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .csrf().disable()
        .requestMatchers().antMatchers("/login*","/oauth/authorize").and()
        .authorizeRequests()
        .anyRequest().permitAll()
        .and()
        .formLogin()
         //使用自定义的登录页面
        .loginPage("/login.html")
        .loginProcessingUrl("/login");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

注:如果同时存在认证服务器配置和资源服务牌配置的话,需要设置认证服务器配置的优先级高于资源服务器配置。

/**
 * 认证服务器配置
 */
@Configuration
@Order(1) //设置该配置的优先级
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
		...
		...
}


/**
 * 资源服务器配置
 */
@Configuration
@EnableResourceServer
public class UnifiedResourceServerConfig extends ResourceServerConfigurerAdapter {
		...
		...
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

② /oauth/confirm_access 接口

该接口会重定向到授权页面,同样,oauth2的授权界面很难满足实际使用场景,可以通过配置替换为自定义的授权页面。

//替换为自定义的授权页面
endpoints.pathMapping("/oauth/confirm_access", "/custom/confirm_access");
  • 1
  • 2
//自定义授权页面
@Controller
@SessionAttributes("authorizationRequest")
public class GrantController {
    @RequestMapping("/custom/confirm_access")
    public ModelAndView getAccessConfirmation(Map<String, Object> model, HttpServletRequest request) {
        AuthorizationRequest authorizationRequest = (AuthorizationRequest) model.get("authorizationRequest");
        ModelAndView view = new ModelAndView();
        view.setViewName("grant");
        view.addObject("clientId", authorizationRequest.getClientId());
        view.addObject("scopes",authorizationRequest.getScope());
        return view;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
<!-- 自定义授权页面 -->
<form method="post" action="/oauth/authorize">
    <input type="hidden" name="user_oauth_approval" value="true">
    <div th:each="item:${scopes}">
        <input type="radio" th:name="'scope.'+${item}" value="true" hidden="hidden" checked="checked"/>
    </div>
    <button class="btn" type="submit"> 同意/授权</button>
</form>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

授权后的信息存放在 oauth_approvals 表中。
具体源码可以查看 JdbcApprovalStore 类,该类中的sql默认是使用 Mysql 语法,同样可以通过自定义替换成别的数据库语法。

③ /oauth/authorize 接口 POST请求

该接口会生成code码,最终会重定向到A系统的redirectUrl地址,并将生成的code码以参数的形式传递到A系统。

生成的code码保存在 oauth_code 表中。
具体源码可以查看 JdbcAuthorizationCodeServices 类。

可以在代码中自定义code码生成规则

public class UnifiedAuthorizationCodeServices extends JdbcAuthorizationCodeServices {
    public UnifiedAuthorizationCodeServices(DataSource dataSource) {
        super(dataSource);
    }

    private RandomValueStringGenerator generator = new RandomValueStringGenerator(13);

    @Override
    public String createAuthorizationCode(OAuth2Authentication authentication) {
        String code = generator.generate();
        store(code, authentication);
        return code;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

配置代码

@Bean
public AuthorizationCodeServices authorizationCodeServices() {
    return new UnifiedAuthorizationCodeServices(dataSource);
}

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    // token 携带额外信息
    TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
    tokenEnhancerChain.setTokenEnhancers(Arrays.asList(tokenEnhancer()));
    endpoints
            .userDetailsService(userDetailsService)
            .tokenStore(tokenStore())
            .tokenServices(defaultAuthorizationServerTokenServices())
            .authenticationManager(authenticationManager)
            .accessTokenConverter(getAccessTokenConverter())
            .exceptionTranslator(oauth2ResponseExceptionTranslator)
             //自定义sql查询语句
            .approvalStore(jdbcApprovalStore())
             //自定义授权码生成规则
            .authorizationCodeServices(authorizationCodeServices());

	//替换为自定义的授权页面
    endpoints.pathMapping("/oauth/confirm_access", "/custom/confirm_access");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

④ /oauth/token 接口 authorization_code模式

该接口对应图中,A系统访问B系统,传递clientId,clientSecret,code,redirectUri等参数换取B系统的accessToken和refreshToken。

使用code换取token
有了B系统token,就可以通过token调用B系统的接口获取B系统的用户信息了。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/390155
推荐阅读
  

闽ICP备14008679号