Skip to content

Commit 648f178

Browse files
committed
GitHub 授权码登录
1 parent 0fbadad commit 648f178

File tree

9 files changed

+305
-13
lines changed

9 files changed

+305
-13
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package com.tang.admin.controller;
2+
3+
import java.io.IOException;
4+
import java.net.URISyntaxException;
5+
import java.util.Map;
6+
7+
import org.springframework.web.bind.annotation.RequestMapping;
8+
import org.springframework.web.bind.annotation.RestController;
9+
10+
import com.tang.commons.enumeration.LoginType;
11+
import com.tang.commons.model.LoginModel;
12+
import com.tang.commons.utils.AjaxResult;
13+
import com.tang.framework.web.service.LoginService;
14+
import com.tang.system.service.SysMenuService;
15+
16+
/**
17+
* 登陆验证逻辑控制层
18+
*
19+
* @author Tang
20+
*/
21+
@RestController
22+
@RequestMapping("/third-party/oauth")
23+
public class ThirdPartyLoginController {
24+
25+
private final LoginService loginService;
26+
27+
public ThirdPartyLoginController(LoginService loginService, SysMenuService menuService) {
28+
this.loginService = loginService;
29+
}
30+
31+
@RequestMapping("/github/redirect")
32+
public AjaxResult oauthRedirect(String code) throws URISyntaxException, IOException, InterruptedException {
33+
var loginModel = new LoginModel();
34+
loginModel.setCode(code);
35+
loginModel.setLoginType(LoginType.GITHUB.getName());
36+
loginModel.setCaptchaEnable(false);
37+
var token = loginService.login(loginModel);
38+
return AjaxResult.success(Map.of("token", token));
39+
}
40+
41+
}

tang-admin/src/main/resources/application.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,11 @@ token:
7878
time-unit: hours
7979
# 令牌有效期
8080
expire-time: 2
81+
82+
# 第三方登录
83+
oauth:
84+
github:
85+
# 客户端ID
86+
client-id: xxxxxxxxxxxxxxxxxxxx
87+
# 客户端密钥
88+
client-secret: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.tang.commons.autoconfigure.oauth;
2+
3+
import org.springframework.boot.context.properties.ConfigurationProperties;
4+
import org.springframework.context.annotation.Configuration;
5+
6+
/**
7+
* GitHub 配置
8+
*
9+
* @author Tang
10+
*/
11+
@Configuration
12+
@ConfigurationProperties(prefix = GitHubProperties.GITHUB_PREFIX)
13+
public class GitHubProperties {
14+
15+
public static final String GITHUB_PREFIX = "oauth.github";
16+
17+
/**
18+
* 客户端 ID
19+
*/
20+
private String clientId;
21+
22+
/**
23+
* 客户端密钥
24+
*/
25+
private String clientSecret;
26+
27+
28+
public String getClientId() {
29+
return clientId;
30+
}
31+
32+
public void setClientId(String clientId) {
33+
this.clientId = clientId;
34+
}
35+
36+
public String getClientSecret() {
37+
return clientSecret;
38+
}
39+
40+
public void setClientSecret(String clientSecret) {
41+
this.clientSecret = clientSecret;
42+
}
43+
44+
}

tang-commons/src/main/java/com/tang/commons/enumeration/LoginType.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@ public enum LoginType {
1919
*/
2020
EMAIL("email", "邮箱密码"),
2121

22+
/**
23+
* GitHub 授权码
24+
*/
25+
GITHUB("github", "GitHub 授权码"),
26+
2227
/**
2328
* 未知
2429
*/

tang-commons/src/main/java/com/tang/commons/model/LoginModel.java

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
public class LoginModel implements Serializable {
1616

1717
@java.io.Serial
18-
private static final long serialVersionUID = -5942371013228306925L;
18+
private static final long serialVersionUID = 364320618765413665L;
1919

2020
/**
2121
* 用户名
@@ -36,12 +36,22 @@ public class LoginModel implements Serializable {
3636
@Length(min = 4, max = 64, message = "密码长度应在 4 到 64 之间")
3737
private String password;
3838

39+
/**
40+
* GitHub 授权码
41+
*/
42+
private String code;
43+
3944
/**
4045
* 登陆方式
4146
*/
4247
@NotBlank(message = "登陆方式不能为空")
4348
private String loginType;
4449

50+
/**
51+
* 验证码开关
52+
*/
53+
private boolean captchaEnable = true;
54+
4555
/**
4656
* 验证码
4757
*/
@@ -72,6 +82,14 @@ public void setPassword(String password) {
7282
this.password = password;
7383
}
7484

85+
public String getCode() {
86+
return code;
87+
}
88+
89+
public void setCode(String code) {
90+
this.code = code;
91+
}
92+
7593
public String getLoginType() {
7694
return loginType;
7795
}
@@ -80,6 +98,14 @@ public void setLoginType(String loginType) {
8098
this.loginType = loginType;
8199
}
82100

101+
public boolean getCaptchaEnable() {
102+
return captchaEnable;
103+
}
104+
105+
public void setCaptchaEnable(boolean captchaEnable) {
106+
this.captchaEnable = captchaEnable;
107+
}
108+
83109
public CaptchaModel getCaptcha() {
84110
return captcha;
85111
}

tang-framework/src/main/java/com/tang/framework/config/SecurityConfig.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity, Authen
4747
// 设置未登陆过滤器
4848
.exceptionHandling(handling -> handling.authenticationEntryPoint(authenticationEntryPoint))
4949
.authorizeHttpRequests(authorize -> authorize
50-
.requestMatchers("/login").permitAll()
50+
.requestMatchers("/login", "/third-party/oauth/**").permitAll()
5151
.requestMatchers("/v3/api-docs/**", "/swagger-ui/**", "/swagger-ui.html").permitAll()
5252
.requestMatchers("/websocket/**").permitAll()
5353
.requestMatchers("/uploads/**").permitAll()
@@ -60,8 +60,9 @@ public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity, Authen
6060
}
6161

6262
@Bean
63-
public AuthenticationManager authenticationManager(AuthenticationProvider usernameAuthenticationProvider, AuthenticationProvider emailAuthenticationProvider) {
64-
var providers = List.of(usernameAuthenticationProvider, emailAuthenticationProvider);
63+
public AuthenticationManager authenticationManager(AuthenticationProvider usernameAuthenticationProvider, AuthenticationProvider emailAuthenticationProvider,
64+
AuthenticationProvider gitHubAuthenticationProvider) {
65+
var providers = List.of(usernameAuthenticationProvider, emailAuthenticationProvider, gitHubAuthenticationProvider);
6566
return new ProviderManager(providers);
6667
}
6768

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package com.tang.framework.security.authentication.github;
2+
3+
import java.net.URI;
4+
import java.net.http.HttpClient;
5+
import java.net.http.HttpRequest;
6+
import java.net.http.HttpResponse;
7+
import java.util.Collections;
8+
import java.util.Map;
9+
10+
import org.springframework.security.authentication.AuthenticationProvider;
11+
import org.springframework.security.core.Authentication;
12+
import org.springframework.security.core.AuthenticationException;
13+
import org.springframework.stereotype.Component;
14+
15+
import com.fasterxml.jackson.core.type.TypeReference;
16+
import com.fasterxml.jackson.databind.ObjectMapper;
17+
import com.tang.commons.autoconfigure.oauth.GitHubProperties;
18+
import com.tang.commons.enumeration.LoginType;
19+
import com.tang.commons.utils.StringUtils;
20+
import com.tang.framework.web.service.authentication.AuthenticationService;
21+
import com.tang.system.service.SysUserService;
22+
23+
/**
24+
* 用户名密码身份验证
25+
*
26+
* @author Tang
27+
*/
28+
@Component
29+
public class GitHubAuthenticationProvider implements AuthenticationProvider {
30+
31+
private final HttpClient httpClient = HttpClient.newBuilder().build();
32+
33+
private final ObjectMapper objectMapper = new ObjectMapper();
34+
35+
private final TypeReference<Map<String, Object>> typeReference = new TypeReference<>() {};
36+
37+
private final GitHubProperties githubProperties;
38+
39+
private final SysUserService userService;
40+
41+
private final AuthenticationService authenticationService;
42+
43+
public GitHubAuthenticationProvider(GitHubProperties githubProperties, SysUserService userService, AuthenticationService authenticationService) {
44+
this.githubProperties = githubProperties;
45+
this.userService = userService;
46+
this.authenticationService = authenticationService;
47+
}
48+
49+
@Override
50+
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
51+
if (!supports(authentication.getClass())) {
52+
return null;
53+
}
54+
var authenticationToken = (GitHubAuthenticationToken) authentication;
55+
var code = authenticationToken.getPrincipal().toString();
56+
57+
var url = "https://github.com/login/oauth/access_token?client_id={}&client_secret={}&code={}";
58+
url = StringUtils.format(url, githubProperties.getClientId(), githubProperties.getClientSecret(), code);
59+
60+
// TODO GitHub OAuth2.0 登录逻辑
61+
62+
// var request = HttpRequest.newBuilder()
63+
// .uri(new URI(url))
64+
// .header("accept", "application/json")
65+
// .POST(HttpRequest.BodyPublishers.noBody())
66+
// .build();
67+
68+
// var response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
69+
70+
// var map = objectMapper.readValue(response.body(), typeReference);
71+
72+
// var urlResult = "https://api.github.com/user";
73+
74+
// var requestResult = HttpRequest.newBuilder()
75+
// .uri(new URI(urlResult))
76+
// .header("accept", "application/json")
77+
// .header("Authorization", "token " + map.get("access_token"))
78+
// .GET()
79+
// .build();
80+
81+
// var responseResult = httpClient.send(requestResult, HttpResponse.BodyHandlers.ofString());
82+
83+
// var result = objectMapper.readValue(responseResult.body(), typeReference);
84+
85+
// var user = userService.selectUserByUsername(username);
86+
87+
// var userModel = authenticationService.createUserModel(user, password, username, LoginType.USERNAME.getName());
88+
89+
// authenticationToken = new GitHubAuthenticationToken(userModel, Collections.emptyList());
90+
91+
return authenticationToken;
92+
}
93+
94+
@Override
95+
public boolean supports(Class<?> authentication) {
96+
return GitHubAuthenticationToken.class.isAssignableFrom(authentication);
97+
}
98+
99+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.tang.framework.security.authentication.github;
2+
3+
import java.util.Collection;
4+
5+
import org.springframework.security.authentication.AbstractAuthenticationToken;
6+
import org.springframework.security.core.GrantedAuthority;
7+
8+
/**
9+
* GitHub 身份验证令牌
10+
*
11+
* @author Tang
12+
*/
13+
public class GitHubAuthenticationToken extends AbstractAuthenticationToken {
14+
15+
@java.io.Serial
16+
private static final long serialVersionUID = 6183503186676400429L;
17+
18+
private final transient Object principal;
19+
20+
private final transient Object credentials;
21+
22+
public GitHubAuthenticationToken(Object principal) {
23+
super(null);
24+
this.principal = principal;
25+
this.credentials = null;
26+
setAuthenticated(false);
27+
}
28+
29+
public GitHubAuthenticationToken(Object principal, Object credentials) {
30+
super(null);
31+
this.principal = principal;
32+
this.credentials = credentials;
33+
setAuthenticated(false);
34+
}
35+
36+
public GitHubAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {
37+
super(authorities);
38+
this.principal = principal;
39+
this.credentials = null;
40+
super.setAuthenticated(true);
41+
}
42+
43+
@Override
44+
public Object getCredentials() {
45+
return this.credentials;
46+
}
47+
48+
@Override
49+
public Object getPrincipal() {
50+
return this.principal;
51+
}
52+
53+
}

0 commit comments

Comments
 (0)