spring security oauth2 github 用户权限(OAuth2UserService)
应用:使用自定义的OAuth2UserService设置用户权限
**********************
相关类及接口
OAuth2UserService
@FunctionalInterface
public interface OAuth2UserService<R extends OAuth2UserRequest, U extends OAuth2User> {
U loadUser(R var1) throws OAuth2AuthenticationException;
}
DefaultOAuth2UserService
public class DefaultOAuth2UserService implements OAuth2UserService<OAuth2UserRequest, OAuth2User> {
private static final String MISSING_USER_INFO_URI_ERROR_CODE = "missing_user_info_uri";
private static final String MISSING_USER_NAME_ATTRIBUTE_ERROR_CODE = "missing_user_name_attribute";
private static final String INVALID_USER_INFO_RESPONSE_ERROR_CODE = "invalid_user_info_response";
private static final ParameterizedTypeReference<Map<String, Object>> PARAMETERIZED_RESPONSE_TYPE = new ParameterizedTypeReference<Map<String, Object>>() {
};
private Converter<OAuth2UserRequest, RequestEntity<?>> requestEntityConverter = new OAuth2UserRequestEntityConverter();
private RestOperations restOperations;
public DefaultOAuth2UserService() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
this.restOperations = restTemplate;
}
public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException {
Assert.notNull(userRequest, "userRequest cannot be null");
if (!StringUtils.hasText(userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri())) {
OAuth2Error oauth2Error = new OAuth2Error("missing_user_info_uri", "Missing required UserInfo Uri in UserInfoEndpoint for Client Registration: " + userRequest.getClientRegistration().getRegistrationId(), (String)null);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
} else {
String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName();
if (!StringUtils.hasText(userNameAttributeName)) {
OAuth2Error oauth2Error = new OAuth2Error("missing_user_name_attribute", "Missing required \"user name\" attribute name in UserInfoEndpoint for Client Registration: " + userRequest.getClientRegistration().getRegistrationId(), (String)null);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
} else {
RequestEntity request = (RequestEntity)this.requestEntityConverter.convert(userRequest);
ResponseEntity response;
OAuth2Error oauth2Error;
try {
response = this.restOperations.exchange(request, PARAMETERIZED_RESPONSE_TYPE);
} catch (OAuth2AuthorizationException var10) {
oauth2Error = var10.getError();
StringBuilder errorDetails = new StringBuilder();
errorDetails.append("Error details: [");
errorDetails.append("UserInfo Uri: ").append(userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri());
errorDetails.append(", Error Code: ").append(oauth2Error.getErrorCode());
if (oauth2Error.getDescription() != null) {
errorDetails.append(", Error Description: ").append(oauth2Error.getDescription());
}
errorDetails.append("]");
oauth2Error = new OAuth2Error("invalid_user_info_response", "An error occurred while attempting to retrieve the UserInfo Resource: " + errorDetails.toString(), (String)null);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), var10);
} catch (RestClientException var11) {
oauth2Error = new OAuth2Error("invalid_user_info_response", "An error occurred while attempting to retrieve the UserInfo Resource: " + var11.getMessage(), (String)null);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), var11);
}
Map<String, Object> userAttributes = (Map)response.getBody();
Set<GrantedAuthority> authorities = new LinkedHashSet();
authorities.add(new OAuth2UserAuthority(userAttributes));
OAuth2AccessToken token = userRequest.getAccessToken();
Iterator var8 = token.getScopes().iterator();
while(var8.hasNext()) {
String authority = (String)var8.next();
authorities.add(new SimpleGrantedAuthority("SCOPE_" + authority));
}
return new DefaultOAuth2User(authorities, userAttributes, userNameAttributeName);
}
}
}
public final void setRequestEntityConverter(Converter<OAuth2UserRequest, RequestEntity<?>> requestEntityConverter) {
Assert.notNull(requestEntityConverter, "requestEntityConverter cannot be null");
this.requestEntityConverter = requestEntityConverter;
}
public final void setRestOperations(RestOperations restOperations) {
Assert.notNull(restOperations, "restOperations cannot be null");
this.restOperations = restOperations;
}
}
OAuth2User
public interface OAuth2User extends OAuth2AuthenticatedPrincipal {
}
DefaultOAuth2User
public class DefaultOAuth2User implements OAuth2User, Serializable {
private static final long serialVersionUID = 520L;
private final Set<GrantedAuthority> authorities;
private final Map<String, Object> attributes;
private final String nameAttributeKey;
public DefaultOAuth2User(Collection<? extends GrantedAuthority> authorities, Map<String, Object> attributes, String nameAttributeKey) {
Assert.notEmpty(authorities, "authorities cannot be empty");
Assert.notEmpty(attributes, "attributes cannot be empty");
Assert.hasText(nameAttributeKey, "nameAttributeKey cannot be empty");
if (!attributes.containsKey(nameAttributeKey)) {
throw new IllegalArgumentException("Missing attribute '" + nameAttributeKey + "' in attributes");
} else {
this.authorities = Collections.unmodifiableSet(new LinkedHashSet(this.sortAuthorities(authorities)));
this.attributes = Collections.unmodifiableMap(new LinkedHashMap(attributes));
this.nameAttributeKey = nameAttributeKey;
}
}
public String getName() {
return this.getAttribute(this.nameAttributeKey).toString();
}
public Collection<? extends GrantedAuthority> getAuthorities() {
public Map<String, Object> getAttributes() {
private Set<GrantedAuthority> sortAuthorities(Collection<? extends GrantedAuthority> authorities) {
public boolean equals(Object obj) {
public int hashCode() {
public String toString() {
OAuth2AuthenticatedPricipal
public interface OAuth2AuthenticatedPrincipal extends AuthenticatedPrincipal {
@Nullable
default <A> A getAttribute(String name) {
return this.getAttributes().get(name);
}
Map<String, Object> getAttributes();
Collection<? extends GrantedAuthority> getAuthorities();
}
AuthenticatedPricipal
public interface AuthenticatedPrincipal {
String getName();
}
**********************
示例
***********************
自定义UserService
WebSecurityConfig
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private UserService userService;
@Bean
public PasswordEncoder initPasswordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin().loginPage("/login/github").loginProcessingUrl("/login/form")
.and()
.authorizeRequests()
.antMatchers("/hello").hasAnyAuthority("ROLE_USER")
.antMatchers("/**").permitAll()
.and()
.logout().deleteCookies("JSESSIONID")
.logoutSuccessUrl("/").permitAll();
http.oauth2Login().loginPage("/login/github")
.userInfoEndpoint().userService(this.initOAuth2UserService());
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(initPasswordEncoder());
}
private OAuth2UserService<OAuth2UserRequest, OAuth2User> initOAuth2UserService(){
OAuth2UserService<OAuth2UserRequest,OAuth2User> oAuth2UserService=new DefaultOAuth2UserService();
return oAuth2UserRequest -> {
OAuth2User oAuth2User=oAuth2UserService.loadUser(oAuth2UserRequest);
Map<String,Object> attributes=oAuth2User.getAttributes();
String attributeNameKey=oAuth2UserRequest.getClientRegistration()
.getProviderDetails().getUserInfoEndpoint().getUserNameAttributeName();
Set<GrantedAuthority> authorities=new HashSet<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
return new DefaultOAuth2User(authorities,attributes,attributeNameKey);
};
}
}
通过认证后控制台输出
org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken@f2e7c93c:
Principal: Name: [41827785], Granted Authorities: [[ROLE_ADMIN, ROLE_USER]], User Attributes: [{login=lihu12344, id=41827785, node_id=MDQ6VXNlcjQxODI3Nzg1, avatar_url=https://avatars3.githubusercontent.com/u/41827785?v=4, gravatar_id=, url=https://api.github.com/users/lihu12344, html_url=https://github.com/lihu12344, followers_url=https://api.github.com/users/lihu12344/followers, following_url=https://api.github.com/users/lihu12344/following{/other_user}, gists_url=https://api.github.com/users/lihu12344/gists{/gist_id}, starred_url=https://api.github.com/users/lihu12344/starred{/owner}{/repo}, subscriptions_url=https://api.github.com/users/lihu12344/subscriptions, organizations_url=https://api.github.com/users/lihu12344/orgs, repos_url=https://api.github.com/users/lihu12344/repos, events_url=https://api.github.com/users/lihu12344/events{/privacy}, received_events_url=https://api.github.com/users/lihu12344/received_events, type=User, site_admin=false, name=null, company=null, blog=, location=null, email=null, hireable=null, bio=null, public_repos=84, public_gists=0, followers=0, following=0, created_at=2018-07-28T11:56:10Z, updated_at=2020-05-15T03:36:41Z, private_gists=0, total_private_repos=0, owned_private_repos=0, disk_usage=4355, collaborators=0, two_factor_authentication=false, plan={name=free, space=976562499, collaborators=0, private_repos=10000}}];
Credentials: [PROTECTED];
Authenticated: true;
Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff4c9c: RemoteIpAddress: 0:0:0:0:0:0:0:1;
SessionId: D285092FC82C5F852A3926C82CC91976;
Granted Authorities: ROLE_ADMIN, ROLE_USER
用户权限设置为ROLE_ADMIN、ROLE_USER