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

发布:admin2025-11-04 08:19:12 6984条浏览分类:新游前瞻

一、说明

oauth2 授权模式一共有四种,即隐式授权模式、授权码授权模式、密码授权模式和客户端授权模式。

这里仅对授权码授权模式所包含的流程和接口做说明和整理。

具体的概念和源码解读,资料有很多,可以自行去搜索学习。

二、流程说明

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

想要实现以上场景就可以使用oauth2的授权码模式,具体流程参考下图:

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

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

以下会对接口做简要说明,最重要的是整理涉及到的自定义配置

想要了解具体代码逻辑实现,可以重点看一下 AuthorizationEndpoint 这个类的源码

① /oauth/authorize 接口 GET请求

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

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");

}

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

/**

* 认证服务器配置

*/

@Configuration

@Order(1) //设置该配置的优先级

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

...

...

}

/**

* 资源服务器配置

*/

@Configuration

@EnableResourceServer

public class UnifiedResourceServerConfig extends ResourceServerConfigurerAdapter {

...

...

}

② /oauth/confirm_access 接口

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

//替换为自定义的授权页面

endpoints.pathMapping("/oauth/confirm_access", "/custom/confirm_access");

//自定义授权页面

@Controller

@SessionAttributes("authorizationRequest")

public class GrantController {

@RequestMapping("/custom/confirm_access")

public ModelAndView getAccessConfirmation(Map 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;

}

}

授权后的信息存放在 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;

}

}

配置代码

@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");

}

④ /oauth/token 接口 authorization_code模式

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

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