上一篇跑通了springsecurity oauth2的授权中心授权流程,这篇来将内置的登录页和授权确认页自定义一下

引入Thymeleaf

在模块authorization-server下的pom.xml里引入模板引擎

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

修改配置

AuthorizationServerConfig 类里的 authorizationServerSecurityFilterChain() 中的授权页修改

// 之前
http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
                .oidc(Customizer.withDefaults());
//修改后
http.exceptionHandling(exceptions ->
                        exceptions.authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login")))
                .oauth2ResourceServer(oauth2 -> oauth2.jwt(Customizer.withDefaults()));

defaultSecurityFilterChain() 方法修改

//之前
http
                .authorizeHttpRequests(authorize -> authorize
                        .anyRequest().authenticated()
                )
                .formLogin(Customizer.withDefaults());
//修改后
http
                .authorizeHttpRequests(authorize -> authorize
                        .requestMatchers("/login", "/static/**", "/css/**").permitAll()
                        .anyRequest().authenticated()
                )
                .formLogin(form -> form
                        .loginPage("/login")
                        .permitAll()
                );

添加页面

resources/templates里添加 login.html, consent.html

login.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>自定义登录页</title>
    <link rel="stylesheet" href="/css/auth.css"/>
</head>
<body>
<h1>请登录</h1>
<form th:action="@{/login}" method="post">
    <input type="text" name="username" placeholder="用户名" required/>
    <input type="password" name="password" placeholder="密码" required/>
    <button type="submit">登录</button>
</form>
</body>
</html>

consent.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>授权请求</title>
    <link rel="stylesheet" href="/css/auth.css"/>
</head>
<body>
<h1>授权申请</h1>
<p>应用 <strong th:text="${clientId}">客户端ID</strong> 请求以下权限:</p>
<ul>
    <li th:each="scope : ${scopes}">
        <span th:text="${scopeNames?.get(scope) ?: scope}">权限范围</span>
    </li>
</ul>
<form th:action="@{/oauth2/authorize}" method="post">
    <input type="hidden" name="client_id" th:value="${clientId}"/>
    <input type="hidden" name="state" th:value="${state}"/>
    <input type="hidden" name="scope" th:value="${#strings.arrayJoin(scopes, ' ')}"/>
    <button type="submit" name="user_oauth_approval" value="true">同意</button>
    <button type="submit" name="user_oauth_approval" value="false">拒绝</button>
</form>
</body>
</html>

创建一个css resources/static/css/auth.css auth.css

/* static/css/auth.css */
body {
    font-family: Arial, serif;
    background-color: aliceblue;
}

.auth-form {
    max-width: 400px;
    margin: 0 auto;
}

添加controller

import org.springframework.security.oauth2.server.authorization.client.RegisteredClientRepository;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.HashMap;
import java.util.Map;

@Controller
public class AuthorizationController {
    private final RegisteredClientRepository registeredClientRepository;

    public AuthorizationController(RegisteredClientRepository registeredClientRepository) {
        this.registeredClientRepository = registeredClientRepository;
    }

    @GetMapping("/login")
    public String login() {
        return "login";
    }

    @GetMapping("/oauth2/consent")
    public String consentPage(
            @RequestParam("client_id") String clientId,
            @RequestParam("scope") String scope,
            @RequestParam("state") String state,
            Model model) {

        // 创建 scope 到友好名称的映射
        Map<String, String> scopeNames = new HashMap<>();
        scopeNames.put("user", "读取用户信息");

        model.addAttribute("clientId", clientId);
        model.addAttribute("scopes", scope.split(" "));
        model.addAttribute("scopeNames", scopeNames);
        model.addAttribute("state", state);

        return "consent";
    }
}

测试

启动授权中心和客户端应用两个服务

打开浏览器访问:http://localhost:9000/oauth2/authorize?response_type=code&client_id=client&redirect_uri=http://localhost:8081/login/oauth2/code/client&scope=user

跳转到登录页

输入用户名和密码登录成功跳转到授权确认页

点击同意,带着code回调到客户端应用提供的回调地址上