Skip to content

Commit c329649

Browse files
feat: Authority
1 parent e96b272 commit c329649

7 files changed

Lines changed: 107 additions & 77 deletions

File tree

src/main/java/com/spring/security/authentication/handler/auth/UserLoginInfo.java

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,9 @@
33
import com.fasterxml.jackson.annotation.JsonIgnore;
44
import java.io.Serial;
55
import java.io.Serializable;
6-
import java.util.Collection;
7-
import java.util.Comparator;
8-
import java.util.List;
9-
import java.util.SortedSet;
10-
import java.util.TreeSet;
6+
import java.util.*;
117
import lombok.*;
12-
import org.jspecify.annotations.NonNull;
8+
import org.jspecify.annotations.Nullable;
139
import org.springframework.security.core.GrantedAuthority;
1410
import org.springframework.security.core.userdetails.UserDetails;
1511
import org.springframework.util.Assert;
@@ -33,37 +29,41 @@ public class UserLoginInfo implements UserDetails {
3329

3430
private String phone;
3531
private String email;
36-
private Boolean accountNonLocked;
37-
private Boolean accountNonExpired;
38-
private Boolean credentialsNonExpired;
39-
private Boolean enabled;
40-
private String twoFactorSecret;
41-
private Boolean twoFactorEnabled;
32+
private Set<GrantedAuthority> authorities;
33+
private boolean accountNonLocked;
34+
private boolean accountNonExpired;
35+
private boolean credentialsNonExpired;
36+
private boolean enabled;
37+
private String mfaSecret;
38+
private Boolean mfaEnabled;
4239

43-
@Override
44-
public @NonNull Collection<? extends GrantedAuthority> getAuthorities() {
45-
// TODO 权限
46-
return List.of();
47-
}
48-
49-
@Override
50-
public boolean isAccountNonExpired() {
51-
return accountNonExpired;
52-
}
53-
54-
@Override
55-
public boolean isAccountNonLocked() {
56-
return accountNonLocked;
57-
}
58-
59-
@Override
60-
public boolean isCredentialsNonExpired() {
61-
return credentialsNonExpired;
62-
}
63-
64-
@Override
65-
public boolean isEnabled() {
66-
return enabled;
40+
public UserLoginInfo(
41+
String sessionId,
42+
Long id,
43+
String username,
44+
@Nullable String password,
45+
String phone,
46+
String email,
47+
boolean accountNonLocked,
48+
boolean accountNonExpired,
49+
boolean credentialsNonExpired,
50+
boolean enabled,
51+
String mfaSecret,
52+
Boolean mfaEnabled,
53+
Collection<? extends GrantedAuthority> authorities) {
54+
this.sessionId = sessionId;
55+
this.id = id;
56+
this.username = username;
57+
this.password = password;
58+
this.phone = phone;
59+
this.email = email;
60+
this.accountNonLocked = accountNonLocked;
61+
this.accountNonExpired = accountNonExpired;
62+
this.credentialsNonExpired = credentialsNonExpired;
63+
this.enabled = enabled;
64+
this.mfaSecret = mfaSecret;
65+
this.mfaEnabled = mfaEnabled;
66+
this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
6767
}
6868

6969
private static SortedSet<GrantedAuthority> sortAuthorities(Collection<? extends GrantedAuthority> authorities) {

src/main/java/com/spring/security/authentication/handler/auth/email/EmailAuthenticationProvider.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package com.spring.security.authentication.handler.auth.email;
22

33
import com.spring.security.authentication.handler.auth.UserLoginInfo;
4+
import com.spring.security.authentication.handler.authorization.Authority;
45
import com.spring.security.common.web.enums.BaseCode;
56
import com.spring.security.common.web.exception.BaseException;
67
import com.spring.security.domain.model.entity.User;
78
import com.spring.security.domain.repository.UserRepository;
9+
import java.util.Collection;
10+
import java.util.LinkedHashSet;
811
import java.util.List;
912
import java.util.UUID;
1013
import lombok.RequiredArgsConstructor;
@@ -15,7 +18,9 @@
1518
import org.springframework.security.authentication.BadCredentialsException;
1619
import org.springframework.security.core.Authentication;
1720
import org.springframework.security.core.AuthenticationException;
21+
import org.springframework.security.core.GrantedAuthority;
1822
import org.springframework.security.core.SpringSecurityMessageSource;
23+
import org.springframework.security.core.authority.FactorGrantedAuthority;
1924
import org.springframework.security.crypto.password.PasswordEncoder;
2025
import org.springframework.stereotype.Component;
2126
import org.springframework.util.Assert;
@@ -30,6 +35,7 @@ public class EmailAuthenticationProvider implements AuthenticationProvider {
3035
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
3136
private final UserRepository userRepository;
3237
private final PasswordEncoder passwordEncoder;
38+
private static final String AUTHORITY = Authority.EMAIL_AUTHORITY;
3339

3440
@Override
3541
public Authentication authenticate(@NonNull Authentication authentication) throws AuthenticationException {
@@ -67,6 +73,8 @@ protected UserLoginInfo retrieveUser(String email, EmailAuthenticationToken auth
6773
throws AuthenticationException {
6874
User loadedUser =
6975
userRepository.findByEmail(email).orElseThrow(() -> new BaseException(BaseCode.USER_EMAIL_NOT_FOUND));
76+
Collection<GrantedAuthority> authorities = new LinkedHashSet<>();
77+
authorities.add(FactorGrantedAuthority.fromAuthority(AUTHORITY));
7078
log.debug("用户信息查询成功,用户: {}", loadedUser.getUsername());
7179
return new UserLoginInfo(
7280
UUID.randomUUID().toString(),
@@ -80,7 +88,8 @@ protected UserLoginInfo retrieveUser(String email, EmailAuthenticationToken auth
8088
loadedUser.getCredentialsNonExpired(),
8189
loadedUser.getEnabled(),
8290
loadedUser.getMfaSecret(),
83-
loadedUser.getMfaEnabled());
91+
loadedUser.getMfaEnabled(),
92+
authorities);
8493
}
8594

8695
protected void additionalAuthenticationChecks(UserLoginInfo userLoginInfo, EmailAuthenticationToken authentication)

src/main/java/com/spring/security/authentication/handler/auth/github/login/GitHubOAuth2LoginAuthenticationProvider.java

Lines changed: 25 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import com.spring.security.authentication.handler.auth.github.authentication.GitHubOAuth2AuthorizationCodeAuthenticationToken;
66
import com.spring.security.authentication.handler.auth.github.dto.GitHubOAuth2Meta;
77
import com.spring.security.authentication.handler.auth.github.service.GitHubOAuth2UserService;
8+
import com.spring.security.authentication.handler.authorization.Authority;
89
import com.spring.security.domain.model.entity.User;
910
import com.spring.security.domain.model.entity.UserIdentity;
1011
import com.spring.security.domain.repository.UserIdentityRepository;
@@ -33,13 +34,13 @@
3334
@Getter
3435
@Component
3536
public class GitHubOAuth2LoginAuthenticationProvider implements AuthenticationProvider {
36-
private static final String AUTHORITY = FactorGrantedAuthority.AUTHORIZATION_CODE_AUTHORITY;
3737
private final GitHubOAuth2AuthorizationCodeAuthenticationProvider authorizationCodeAuthenticationProvider;
3838
private final OAuth2UserService<OAuth2UserRequest, OAuth2User> gitHubOAuth2UserService;
3939
private final UserIdentityRepository userIdentityRepository;
4040
private final UserRepository userRepository;
4141
private GrantedAuthoritiesMapper authoritiesMapper = (authorities) -> authorities;
4242
private final JsonMapper jsonMapper;
43+
private static final String AUTHORITY = Authority.AUTHORIZATION_CODE_AUTHORITY;
4344

4445
public GitHubOAuth2LoginAuthenticationProvider(
4546
GitHubOAuth2AuthorizationCodeAuthenticationProvider authorizationCodeAuthenticationProvider,
@@ -93,37 +94,6 @@ public Authentication authenticate(@NonNull Authentication authentication) throw
9394

9495
// 查询用户信息
9596
User user = retrieveUser(providerUserId, oauth2User, authorizationCodeAuthenticationToken);
96-
// 验证用户信息
97-
// 构造成功结果
98-
return createSuccessAuthentication(authorizationCodeAuthenticationToken, user, oauth2User, mappedAuthorities);
99-
}
100-
101-
private Long extractProviderUserId(OAuth2User oauth2User) {
102-
Object id = oauth2User.getAttribute("id");
103-
Assert.notNull(id, "GitHub user id cannot be null");
104-
if (id instanceof Number number) {
105-
return number.longValue();
106-
}
107-
return Long.parseLong(String.valueOf(id));
108-
}
109-
110-
public final void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
111-
Assert.notNull(authoritiesMapper, "authoritiesMapper cannot be null");
112-
this.authoritiesMapper = authoritiesMapper;
113-
}
114-
115-
@Override
116-
public boolean supports(@NonNull Class<?> authentication) {
117-
return GitHubOAuth2LoginAuthenticationToken.class.isAssignableFrom(authentication);
118-
}
119-
120-
protected Authentication createSuccessAuthentication(
121-
Authentication authentication,
122-
User user,
123-
OAuth2User oauth2User,
124-
Collection<GrantedAuthority> mappedAuthorities) {
125-
GitHubOAuth2AuthorizationCodeAuthenticationToken loginAuthenticationToken =
126-
(GitHubOAuth2AuthorizationCodeAuthenticationToken) authentication;
12797
UserLoginInfo userLoginInfo = new UserLoginInfo(
12898
UUID.randomUUID().toString(),
12999
user != null ? user.getId() : null,
@@ -136,7 +106,8 @@ protected Authentication createSuccessAuthentication(
136106
user != null ? user.getCredentialsNonExpired() : null,
137107
user != null ? user.getEnabled() : null,
138108
user != null ? user.getMfaSecret() : null,
139-
user != null ? user.getMfaEnabled() : null);
109+
user != null ? user.getMfaEnabled() : null,
110+
user != null ? mappedAuthorities : null);
140111

141112
// 认证通过,使用 Authenticated 为 true 的构造函数
142113
GitHubOAuth2LoginAuthenticationToken result = new GitHubOAuth2LoginAuthenticationToken(
@@ -149,9 +120,30 @@ protected Authentication createSuccessAuthentication(
149120
// 必须转化成Map
150121
result.setDetails(jsonMapper.convertValue(authentication.getDetails(), Map.class));
151122
log.debug("用户名认证成功,用户: {}", userLoginInfo.getUsername());
123+
// 验证用户信息
124+
// 构造成功结果
152125
return result;
153126
}
154127

128+
private Long extractProviderUserId(OAuth2User oauth2User) {
129+
Object id = oauth2User.getAttribute("id");
130+
Assert.notNull(id, "GitHub user id cannot be null");
131+
if (id instanceof Number number) {
132+
return number.longValue();
133+
}
134+
return Long.parseLong(String.valueOf(id));
135+
}
136+
137+
public final void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
138+
Assert.notNull(authoritiesMapper, "authoritiesMapper cannot be null");
139+
this.authoritiesMapper = authoritiesMapper;
140+
}
141+
142+
@Override
143+
public boolean supports(@NonNull Class<?> authentication) {
144+
return GitHubOAuth2LoginAuthenticationToken.class.isAssignableFrom(authentication);
145+
}
146+
155147
protected User retrieveUser(
156148
Long providerUserId, OAuth2User oauth2User, GitHubOAuth2AuthorizationCodeAuthenticationToken authentication)
157149
throws AuthenticationException {

src/main/java/com/spring/security/authentication/handler/auth/message/SmsAuthenticationProvider.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package com.spring.security.authentication.handler.auth.message;
22

33
import com.spring.security.authentication.handler.auth.UserLoginInfo;
4+
import com.spring.security.authentication.handler.authorization.Authority;
45
import com.spring.security.common.web.enums.BaseCode;
56
import com.spring.security.common.web.exception.BaseException;
67
import com.spring.security.common.web.service.RedisVerificationCodeService;
78
import com.spring.security.common.web.service.RedisVerificationCodeService.VerificationChannel;
89
import com.spring.security.common.web.service.RedisVerificationCodeService.VerificationPurpose;
910
import com.spring.security.domain.model.entity.User;
1011
import com.spring.security.domain.repository.UserRepository;
12+
import java.util.Collection;
13+
import java.util.LinkedHashSet;
1114
import java.util.List;
1215
import java.util.UUID;
1316
import lombok.RequiredArgsConstructor;
@@ -18,7 +21,9 @@
1821
import org.springframework.security.authentication.BadCredentialsException;
1922
import org.springframework.security.core.Authentication;
2023
import org.springframework.security.core.AuthenticationException;
24+
import org.springframework.security.core.GrantedAuthority;
2125
import org.springframework.security.core.SpringSecurityMessageSource;
26+
import org.springframework.security.core.authority.FactorGrantedAuthority;
2227
import org.springframework.stereotype.Component;
2328
import org.springframework.util.Assert;
2429

@@ -32,6 +37,7 @@ public class SmsAuthenticationProvider implements AuthenticationProvider {
3237
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
3338
private final UserRepository userRepository;
3439
private final RedisVerificationCodeService redisVerificationCodeService;
40+
private static final String AUTHORITY = Authority.SMS_AUTHORITY;
3541

3642
@Override
3743
public Authentication authenticate(@NonNull Authentication authentication) throws AuthenticationException {
@@ -69,6 +75,8 @@ protected UserLoginInfo retrieveUser(String phone, SmsAuthenticationToken authen
6975
throws AuthenticationException {
7076
User loadedUser =
7177
userRepository.findByPhone(phone).orElseThrow(() -> new BaseException(BaseCode.USER_PHONE_NOT_FOUND));
78+
Collection<GrantedAuthority> authorities = new LinkedHashSet<>();
79+
authorities.add(FactorGrantedAuthority.fromAuthority(AUTHORITY));
7280
log.debug("用户信息查询成功,用户: {}", loadedUser.getUsername());
7381
return new UserLoginInfo(
7482
UUID.randomUUID().toString(),
@@ -82,7 +90,8 @@ protected UserLoginInfo retrieveUser(String phone, SmsAuthenticationToken authen
8290
loadedUser.getCredentialsNonExpired(),
8391
loadedUser.getEnabled(),
8492
loadedUser.getMfaSecret(),
85-
loadedUser.getMfaEnabled());
93+
loadedUser.getMfaEnabled(),
94+
authorities);
8695
}
8796

8897
protected void additionalAuthenticationChecks(UserLoginInfo userLoginInfo, SmsAuthenticationToken authentication)

src/main/java/com/spring/security/authentication/handler/auth/oneTimeToken/OneTimeTokenAuthenticationProvider.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.spring.security.authentication.handler.auth.UserLoginInfo;
44
import com.spring.security.authentication.handler.auth.oneTimeToken.service.RedisOneTimeTokenService;
5+
import com.spring.security.authentication.handler.authorization.Authority;
56
import com.spring.security.common.web.enums.BaseCode;
67
import com.spring.security.common.web.exception.BaseException;
78
import com.spring.security.domain.model.entity.User;
@@ -27,7 +28,7 @@
2728
@RequiredArgsConstructor
2829
public class OneTimeTokenAuthenticationProvider implements AuthenticationProvider {
2930
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
30-
private static final String AUTHORITY = FactorGrantedAuthority.OTT_AUTHORITY;
31+
private static final String AUTHORITY = Authority.OTT_AUTHORITY;
3132
private final UserRepository userRepository;
3233
private final RedisOneTimeTokenService redisOneTimeTokenService;
3334

@@ -70,6 +71,8 @@ protected UserLoginInfo additionalAuthenticationChecks(
7071
String username, OneTimeTokenAuthenticationToken authentication) throws AuthenticationException {
7172
User loadedUser =
7273
userRepository.findByUsername(username).orElseThrow(() -> new BaseException(BaseCode.USER_NOT_FOUND));
74+
Collection<GrantedAuthority> authorities = new LinkedHashSet<>();
75+
authorities.add(FactorGrantedAuthority.fromAuthority(AUTHORITY));
7376
log.debug("用户信息查询成功,用户: {}", loadedUser.getUsername());
7477
return new UserLoginInfo(
7578
UUID.randomUUID().toString(),
@@ -83,7 +86,8 @@ protected UserLoginInfo additionalAuthenticationChecks(
8386
loadedUser.getCredentialsNonExpired(),
8487
loadedUser.getEnabled(),
8588
loadedUser.getMfaSecret(),
86-
loadedUser.getMfaEnabled());
89+
loadedUser.getMfaEnabled(),
90+
authorities);
8791
}
8892

8993
protected OneTimeToken retrieveUser(String token, OneTimeTokenAuthenticationToken authentication)

src/main/java/com/spring/security/authentication/handler/auth/user/UsernameAuthenticationProvider.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package com.spring.security.authentication.handler.auth.user;
22

33
import com.spring.security.authentication.handler.auth.UserLoginInfo;
4+
import com.spring.security.authentication.handler.authorization.Authority;
45
import com.spring.security.common.web.enums.BaseCode;
56
import com.spring.security.common.web.exception.BaseException;
67
import com.spring.security.domain.model.entity.User;
78
import com.spring.security.domain.repository.UserRepository;
9+
import java.util.Collection;
10+
import java.util.LinkedHashSet;
811
import java.util.List;
912
import java.util.UUID;
1013
import lombok.RequiredArgsConstructor;
@@ -15,7 +18,9 @@
1518
import org.springframework.security.authentication.BadCredentialsException;
1619
import org.springframework.security.core.Authentication;
1720
import org.springframework.security.core.AuthenticationException;
21+
import org.springframework.security.core.GrantedAuthority;
1822
import org.springframework.security.core.SpringSecurityMessageSource;
23+
import org.springframework.security.core.authority.FactorGrantedAuthority;
1924
import org.springframework.security.crypto.password.PasswordEncoder;
2025
import org.springframework.stereotype.Component;
2126
import org.springframework.util.Assert;
@@ -30,6 +35,7 @@ public class UsernameAuthenticationProvider implements AuthenticationProvider {
3035
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
3136
private final UserRepository userRepository;
3237
private final PasswordEncoder passwordEncoder;
38+
private static final String AUTHORITY = Authority.PASSWORD_AUTHORITY;
3339

3440
@Override
3541
public Authentication authenticate(@NonNull Authentication authentication) throws AuthenticationException {
@@ -39,9 +45,7 @@ public Authentication authenticate(@NonNull Authentication authentication) throw
3945
() -> this.messages.getMessage("UsernameAuthenticationProvider.onlySupports", "仅支持用户名身份验证提供程序"));
4046
UsernameAuthenticationToken usernameAuthenticationToken = (UsernameAuthenticationToken) authentication;
4147
// 获取用户提交的用户名
42-
String username = (usernameAuthenticationToken.getUsername() == null
43-
? "NONE_PROVIDED"
44-
: usernameAuthenticationToken.getUsername());
48+
String username = usernameAuthenticationToken.getUsername();
4549
// 查询用户信息
4650
UserLoginInfo userLoginInfo = retrieveUser(username, usernameAuthenticationToken);
4751
// 验证用户信息
@@ -68,6 +72,8 @@ protected UserLoginInfo retrieveUser(String username, UsernameAuthenticationToke
6872
throws AuthenticationException {
6973
User loadedUser =
7074
userRepository.findByUsername(username).orElseThrow(() -> new BaseException(BaseCode.USER_NOT_FOUND));
75+
Collection<GrantedAuthority> authorities = new LinkedHashSet<>();
76+
authorities.add(FactorGrantedAuthority.fromAuthority(AUTHORITY));
7177
log.debug("用户信息查询成功,用户: {}", loadedUser.getUsername());
7278
return new UserLoginInfo(
7379
UUID.randomUUID().toString(),
@@ -81,7 +87,8 @@ protected UserLoginInfo retrieveUser(String username, UsernameAuthenticationToke
8187
loadedUser.getCredentialsNonExpired(),
8288
loadedUser.getEnabled(),
8389
loadedUser.getMfaSecret(),
84-
loadedUser.getMfaEnabled());
90+
loadedUser.getMfaEnabled(),
91+
authorities);
8592
}
8693

8794
protected void additionalAuthenticationChecks(

0 commit comments

Comments
 (0)