spring security oauth2 github 用户权限(GrantedAuthoritiesMapper)
应用:为三方授权用户设置自定义的权限
*****************************
相关类及接口
*********************
默认权限设置
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));
} //遍历用户scope,添加前缀为SCOPE_的权限
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;
}
}
OAuth2UserAuthority:用户权限类
public class OAuth2UserAuthority implements GrantedAuthority {
private static final long serialVersionUID = 520L;
private final String authority;
private final Map<String, Object> attributes;
public OAuth2UserAuthority(Map<String, Object> attributes) {
this("ROLE_USER", attributes);
} //authority的值默认为ROLE_USER
public OAuth2UserAuthority(String authority, Map<String, Object> attributes) {
Assert.hasText(authority, "authority cannot be empty");
Assert.notEmpty(attributes, "attributes cannot be empty");
this.authority = authority;
this.attributes = Collections.unmodifiableMap(new LinkedHashMap(attributes));
}
public String getAuthority() {
public Map<String, Object> getAttributes() {
public boolean equals(Object obj) {
public int hashCode() {
public String toString() {
return this.getAuthority();
}
}
*********************
自定义用户权限
GrantedAuthoritiesMapper:自定义权限类接口
public interface GrantedAuthoritiesMapper {
Collection<? extends GrantedAuthority> mapAuthorities(Collection<? extends GrantedAuthority> var1);
}
*****************************
示例
*********************
controller 层
HelloController
@RestController
public class HelloController {
@RequestMapping("/hello")
public String hello(Principal principal){
System.out.println(principal.toString());
return "hello "+principal.getName();
}
@RequestMapping("/")
public String redirect(){
return "redirect";
}
}
*********************
默认权限
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");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(initPasswordEncoder());
}
}
通过权限认证后控制台输出
org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken@c8e5585:
Principal: Name: [41827785], Granted Authorities: [[ROLE_USER, SCOPE_read: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=83, public_gists=0, followers=0, following=0, created_at=2018-07-28T11:56:10Z, updated_at=2020-05-15T00:53:27Z, private_gists=0, total_private_repos=0, owned_private_repos=0, disk_usage=4269, 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@fffd3270: RemoteIpAddress: 0:0:0:0:0:0:0:1;
SessionId: D4C6C91511D3A2717BC5EE8CBB539BFB;
Granted Authorities: ROLE_USER, SCOPE_read:user
*********************
自定义OAuth2User权限
GithubOAuth2User
public class GithubOAuth2User implements OAuth2User {
private String id;
private String login;
private String email;
private List<GrantedAuthority> authorities= AuthorityUtils.createAuthorityList("ROLE_USER");
private Map<String,Object> attributes;
@Override
public List<GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public Map<String, Object> getAttributes() {
if (attributes==null){
attributes=new HashMap<>();
attributes.put("id",this.getId());
attributes.put("name",this.getName());
attributes.put("login",this.getLogin());
attributes.put("email",this.getEmail());
}
return attributes;
}
public String getId() {
public void setId(String id) {
@Override
public String getName() {
return this.id;
}
public String getLogin() {
public void setLogin(String login) {
public String getEmail() {
public void setEmail(String email) {
@Override
public boolean equals(Object o) {
@Override
public int hashCode() {
@Override
public String toString() {
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().customUserType(GithubOAuth2User.class,"github");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(initPasswordEncoder());
}
}
通过认证后控制台输出
org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken@e402384d:
Principal: GithubOAuth2User{id='41827785', login='lihu12344', email='null', authorities=[ROLE_USER], attributes={name=41827785, id=41827785, login=lihu12344, email=null}};
Credentials: [PROTECTED];
Authenticated: true;
Details: org.springframework.security.web.authentication.WebAuthenticationDetails@fffc7f0c: RemoteIpAddress: 0:0:0:0:0:0:0:1;
SessionId: 6C7A7C9AD0275652B4B8286F7BCEE53F;
Granted Authorities: ROLE_USER
说明:默认权限为自定义的用户权限ROLE_USER
*********************
自定义权限
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().customUserType(GithubOAuth2User.class,"github");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService).passwordEncoder(initPasswordEncoder());
}
@Bean
public GrantedAuthoritiesMapper initGrantedAuthoritiesMapper(){
return collection -> {
Set<GrantedAuthority> authorities=new HashSet<>();
authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
return authorities;
};
}
}
通过认证后控制台输出
org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken@5b5d3dfb:
Principal: GithubOAuth2User{id='41827785', login='lihu12344', email='null', authorities=[ROLE_USER], attributes={name=41827785, id=41827785, login=lihu12344, email=null}};
Credentials: [PROTECTED];
Authenticated: true;
Details: org.springframework.security.web.authentication.WebAuthenticationDetails@ffff4c9c: RemoteIpAddress: 0:0:0:0:0:0:0:1;
SessionId: 8CF27F8FB80EBC68844C00764E0ECD4E;
Granted Authorities: ROLE_USER, ROLE_ADMIN
说明:使用自定义的权限ROLE_USER、ROLE_ADMIN