自定义OAuth2授权同意页面

编程入门 行业动态 更新时间:2024-10-23 17:28:43

<a href=https://www.elefans.com/category/jswz/34/1771438.html style=自定义OAuth2授权同意页面"/>

自定义OAuth2授权同意页面

自定义OAuth2授权同意页面

前文我们已经简单的介绍了如何搭建授权服务器,下面将继续介绍如何自定义OAuth2授权同意页面。

如果你已经无法容忍Spring Authorization Server 默认丑陋的授权同意页面,那么你可以继续阅读本文,逐步创建一个令自己满意的授权同意页面。

OAuth2授权服务器实现

从创建一个授权服务器开始。

maven依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId><version>2.6.7</version>
</dependency><dependency><groupId>org.springframework.security</groupId><artifactId>spring-security-oauth2-authorization-server</artifactId><version>0.3.1</version>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.6.7</version>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId><version>2.6.7</version>
</dependency>
配置

首先我们为授权服务器配置端口8080:

server:port: 8080

之后我们创建一个AuthorizationServerConfig配置类,在此类中我们将创建OAuth2授权服务器所需特定的Bean。首先指定我们授权同意页面/oauth2/consent uri替换原有默认实现。

@Configuration(proxyBeanMethods = false)
public class AuthorizationServerConfig {private static final String CUSTOM_CONSENT_PAGE_URI = "/oauth2/consent";@Bean@Order(Ordered.HIGHEST_PRECEDENCE)public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception {OAuth2AuthorizationServerConfigurer<HttpSecurity> authorizationServerConfigurer = new OAuth2AuthorizationServerConfigurer<>();//定义授权同意页面authorizationServerConfigurer.authorizationEndpoint(authorizationEndpoint ->authorizationEndpoint.consentPage(CUSTOM_CONSENT_PAGE_URI));RequestMatcher endpointsMatcher = authorizationServerConfigurer.getEndpointsMatcher();http.requestMatcher(endpointsMatcher).authorizeRequests(authorizeRequests ->authorizeRequests.anyRequest().authenticated()).csrf(csrf -> csrf.ignoringRequestMatchers(endpointsMatcher)).apply(authorizationServerConfigurer);return http.exceptionHandling(exceptions -> exceptions.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))).build();}//...
}

接下来我们使用RegisteredClient构建器类型创建一个OAuth2客户端,并将它存储在缓存中。

 @Beanpublic RegisteredClientRepository registeredClientRepository() {RegisteredClient registeredClient = RegisteredClient.withId(UUID.randomUUID().toString()).clientId("relive-client").clientSecret("{noop}relive-client").clientName("ReLive27").clientAuthenticationMethods(s -> {s.add(ClientAuthenticationMethod.CLIENT_SECRET_POST);s.add(ClientAuthenticationMethod.CLIENT_SECRET_BASIC);}).authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE).authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN).authorizationGrantType(AuthorizationGrantType.CLIENT_CREDENTIALS).authorizationGrantType(AuthorizationGrantType.PASSWORD).redirectUri("http://127.0.0.1:8070/login/oauth2/code/messaging-client-authorization-code").scope(OidcScopes.PROFILE).scope("message.read").scope("message.write").clientSettings(ClientSettings.builder().requireAuthorizationConsent(true).requireProofKey(false).build()).tokenSettings(TokenSettings.builder().accessTokenFormat(OAuth2TokenFormat.SELF_CONTAINED).idTokenSignatureAlgorithm(SignatureAlgorithm.RS256).accessTokenTimeToLive(Duration.ofSeconds(30 * 60)).refreshTokenTimeToLive(Duration.ofSeconds(60 * 60)).reuseRefreshTokens(true).build()).build();return new InMemoryRegisteredClientRepository(registeredClient);}

其余配置将不再赘述,可以参考之前将JWT与Spring Security OAuth2结合使用文章。


接下来将创建一个授权页面控制器,并将所需参数传递给Model

@Controller
@RequiredArgsConstructor
public class AuthorizationConsentController {private final RegisteredClientRepository registeredClientRepository;@GetMapping(value = "/oauth2/consent")public String consent(Principal principal, Model model,@RequestParam(OAuth2ParameterNames.CLIENT_ID) String clientId,@RequestParam(OAuth2ParameterNames.SCOPE) String scope,@RequestParam(OAuth2ParameterNames.STATE) String state) {Set<String> scopesToApprove = new LinkedHashSet<>();RegisteredClient registeredClient = this.registeredClientRepository.findByClientId(clientId);Set<String> scopes = registeredClient.getScopes();for (String requestedScope : StringUtils.delimitedListToStringArray(scope, " ")) {if (scopes.contains(requestedScope)) {scopesToApprove.add(requestedScope);}}model.addAttribute("clientId", clientId);model.addAttribute("clientName", registeredClient.getClientName());model.addAttribute("state", state);model.addAttribute("scopes", withDescription(scopesToApprove));model.addAttribute("principalName", principal.getName());model.addAttribute("redirectUri", registeredClient.getRedirectUris().iterator().next());return "consent";}private static Set<ScopeWithDescription> withDescription(Set<String> scopes) {Set<ScopeWithDescription> scopeWithDescriptions = new LinkedHashSet<>();for (String scope : scopes) {scopeWithDescriptions.add(new ScopeWithDescription(scope));}return scopeWithDescriptions;}public static class ScopeWithDescription {private static final String DEFAULT_DESCRIPTION = "我们无法提供有关此权限的信息";private static final Map<String, String> scopeDescriptions = new HashMap<>();static {scopeDescriptions.put("profile","验证您的身份");scopeDescriptions.put("message.read","了解您可以访问哪些权限");scopeDescriptions.put("message.write","代表您行事");}public final String scope;public final String description;ScopeWithDescription(String scope) {this.scope = scope;this.description = scopeDescriptions.getOrDefault(scope, DEFAULT_DESCRIPTION);}}
}

之后让我们定义html页面,这里使用thymeleaf模版引擎:

<!DOCTYPE html>
<html lang="en">
<head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"><link rel="stylesheet" href=".5.2/css/bootstrap.min.css"integrity="sha384-JcKb8q3iqJ61gNV9KGb8thSsNjpSL0n8PARn9HuZOnIxN0hoP+VmmDGMN5t9UJ0Z" crossorigin="anonymous"><title>Custom consent page - Consent required</title><style>body {background-color: #f6f8fa;}#submit-consent {width: 45%;float: right;height: 40px;font-size: 18px;border-color: #cccccc;margin-right: 3%;}#cancel-consent {width: 45%;height: 40px;font-size: 18px;color: black;background-color: #cccccc;border-color: #cccccc;float: left;margin-left: 3%;}</style><script>function cancelConsent() {document.consent_form.reset();document.consent_form.submit();}</script>
</head>
<body>
<div style="width: 500px;height: 600px;margin: 100px auto"><h5 style="text-align: center"><b th:text="${clientName}"></b>希望获得以下许可:</h5><div style="width: 100%;height: 500px;border: #cccccc 1px solid;border-radius: 10px"><form name="consent_form" method="post" action="/oauth2/authorize"><input type="hidden" name="client_id" th:value="${clientId}"><input type="hidden" name="state" th:value="${state}"><div th:each="scope: ${scopes}" class="form-group form-check py-1" style="margin-left: 5%"><input class="form-check-input"type="checkbox"name="scope"th:value="${scope.scope}"th:id="${scope.scope}"checked><label class="form-check-label font-weight-bold" th:for="${scope.scope}"th:text="${scope.scope}=='profile'?(${scope.description}+'('+${principalName}+')'):${scope.description}"></label></div><hr style="width: 90%"><p style="margin-left: 5%"><b th:text="${clientName}"></b>尚未安装在您有权访问的任何账户上。</p><hr style="width: 90%"><div class="form-group pt-3" style="width: 100%;height: 80px;"><button class="btn btn-primary btn-lg" type="submit" id="submit-consent">授权同意</button><button class="btn btn-primary btn-lg" type="button" id="cancel-consent" onclick="cancelConsent();">取消</button></div><div style="margin-top: 5px;width: 100%;height: 50px"><p style="text-align: center;font-size: 14px">授权将重定向到</p><p style="text-align: center;font-size: 14px"><b th:text="${redirectUri}"></b></p></div></form></div>
</div>
</body>
</html>
访问授权页面

启动服务后,我们将发起一个授权请求,http://localhost:8080/oauth2/authorize?response_type=code&client_id=relive-client&scope=message.write%20message.read%20profile&state=some-state&redirect_uri=http://127.0.0.1:8070/login/oauth2/code/messaging-client-authorization-code,在认证成功后,我们可以看到以下我们定义的授权同意页面:

结论

与往常一样,本文中使用的源代码可在 GitHub 上获得。

更多推荐

自定义OAuth2授权同意页面

本文发布于:2024-02-25 09:17:09,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1698490.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:自定义   页面

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!