springsecurity第三方授權(quán)認證的項目實踐
由于博主在做一個校園項目的時候使用啦spring security安全框架,然后在整合第三方授權(quán)登錄的時候,被困擾了好幾天,就想著發(fā)一下這個文章,希望能給大家?guī)韼椭?/p>
第三方授權(quán)登錄的原理,我就不在這里過多闡述了(作者也是小白,怕給你們帶入歧途),大家不熟悉或者不了解的可以取嗶哩嗶哩看一下不良人的springsecurity教程,后面的課程就是講述的第三方授權(quán)登錄的知識。也可以看一下《深入淺出spring security》這本書。
單純的springboot項目的話可以直接使用justauth這個第三方框架,集成啦許多的第三方登錄的接口,只用自己調(diào)用一下api就能解決第三方授權(quán)登錄的問題。
問題描述
現(xiàn)在大多數(shù)軟件和web網(wǎng)站都會加入第三方授權(quán)登錄的功能,以方便提高用戶的體驗。此時就給我們后端開發(fā)的人帶來了極大的煩惱。
由于此項目加入了springsecurity框架,此時就不能使用justauth這個框架了,這個框架關(guān)于springsecurity的解決還沒完善。所以就要使用springsecurity自帶的oauth2認證過濾器(其實你會發(fā)現(xiàn)非常簡單就能解決了)。
詳細步驟(以gitee舉例)
1. 進入官網(wǎng)點擊設(shè)置

2. 向下翻轉(zhuǎn),點擊第三方應(yīng)用

3. 點擊創(chuàng)建應(yīng)用后就進入下面這個界面

4. 然后把標星的給填上

注意回調(diào)地址格式不要寫錯,否則springsecurity識別不出http://IP地址:端口號/login/oauth2/code/應(yīng)用名稱
5. 在springboot里加入配置
security:
oauth2:
client:
registration:
gitee:
client-id: #授權(quán)id
client-secret: #授權(quán)密鑰
authorization-grant-type: authorization_code
redirect-uri: #回調(diào)地址
client-name: gitee #應(yīng)用名稱
scope: user_info
provider:
gitee:
authorization-uri: https://gitee.com/oauth/authorize
token-uri: https://gitee.com/oauth/token
user-info-uri: https://gitee.com/api/v5/user
user-name-attribute: gitee6. 此時要創(chuàng)建一個實體類,這個實體類是接收第三方應(yīng)用傳輸?shù)氖跈?quán)信息的。每個應(yīng)用的授權(quán)信息都不同,大家可以在網(wǎng)上單獨看一下對應(yīng)的官網(wǎng)都會返回什么授權(quán)信息。
@NoArgsConstructor
@AllArgsConstructor
@Data
public class OAuth2UserDTO implements OAuth2User {
private String source;
private String id;
private String name;
private String email;
private String avatar;
@JsonIgnore
@JSONField(serialize = false)
private List<GrantedAuthority> authorities= AuthorityUtils.createAuthorityList("ROLE_USER");
@JsonIgnore
@JSONField(serialize = false)
private Map<String,Object> attributes;
@Override
public Map<String, Object> getAttributes() {
if (attributes==null){
attributes=new HashMap<>();
attributes.put("id",this.getId());
attributes.put("name",this.getName());
attributes.put("email",this.getEmail());
}
return attributes;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.authorities;
}
public OAuth2UserDTO(Map<String,Object> attributes,String source){
this.attributes = attributes;
this.source = source;
this.id = attributes.get("id").toString();
this.name = attributes.get("name").toString();
this.email = attributes.get("email")==null?null:attributes.get("email").toString();
this.avatar = attributes.get("avatar_url")==null?null:attributes.get("avatar_url").toString();
}
}7. 重寫oauth2認證方法
@Service
public class CustomOAuth2UserService implements OAuth2UserService {
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 CustomOAuth2UserService() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setErrorHandler(new OAuth2ErrorResponseErrorHandler());
this.restOperations = restTemplate;
}
@Override
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_ERROR_CODE,
"Missing required UserInfo Uri in UserInfoEndpoint for Client Registration: "
+ userRequest.getClientRegistration().getRegistrationId(),
null);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}
String userNameAttributeName = userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint()
.getUserNameAttributeName();
if (!StringUtils.hasText(userNameAttributeName)) {
OAuth2Error oauth2Error = new OAuth2Error(MISSING_USER_NAME_ATTRIBUTE_ERROR_CODE,
"Missing required \"user name\" attribute name in UserInfoEndpoint for Client Registration: "
+ userRequest.getClientRegistration().getRegistrationId(),
null);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString());
}
RequestEntity<?> request = this.requestEntityConverter.convert(userRequest);
ResponseEntity<Map<String, Object>> response = getResponse(userRequest, request);
Map<String, Object> userAttributes = response.getBody();
Set<GrantedAuthority> authorities = new LinkedHashSet<>();
authorities.add(new OAuth2UserAuthority(userAttributes));
OAuth2AccessToken token = userRequest.getAccessToken();
for (String authority : token.getScopes()) {
authorities.add(new SimpleGrantedAuthority("SCOPE_" + authority));
}
//更換為自定義的OAuth2User實現(xiàn)
return new OAuth2UserDTO(userAttributes, userNameAttributeName);
}
private ResponseEntity<Map<String, Object>> getResponse(OAuth2UserRequest userRequest, RequestEntity<?> request) {
OAuth2Error oauth2Error;
try {
return this.restOperations.exchange(request, PARAMETERIZED_RESPONSE_TYPE);
} catch (OAuth2AuthorizationException var6) {
oauth2Error = var6.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(), var6);
} catch (UnknownContentTypeException var7) {
String errorMessage = "An error occurred while attempting to retrieve the UserInfo Resource from '" + userRequest.getClientRegistration().getProviderDetails().getUserInfoEndpoint().getUri() + "': response contains invalid content type '" + var7.getContentType().toString() + "'. The UserInfo Response should return a JSON object (content type 'application/json') that contains a collection of name and value pairs of the claims about the authenticated End-User. Please ensure the UserInfo Uri in UserInfoEndpoint for Client Registration '" + userRequest.getClientRegistration().getRegistrationId() + "' conforms to the UserInfo Endpoint, as defined in OpenID Connect 1.0: 'https://openid.net/specs/openid-connect-core-1_0.html#UserInfo'";
OAuth2Error oAuth2Error = new OAuth2Error("invalid_user_info_response", errorMessage, (String)null);
throw new OAuth2AuthenticationException(oAuth2Error, oAuth2Error.toString(), var7);
} catch (RestClientException var8) {
oauth2Error = new OAuth2Error("invalid_user_info_response", "An error occurred while attempting to retrieve the UserInfo Resource: " + var8.getMessage(), (String)null);
throw new OAuth2AuthenticationException(oauth2Error, oauth2Error.toString(), var8);
}
}
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;
}
}loadUser是核心方法,只用在業(yè)務(wù)上對其修改成符合自己的業(yè)務(wù)需求就行。
8. 配置securityConfig
http.oauth2Login()
.userInfoEndpoint()
.userService(new CustomOAuth2UserService());9. 驗證是否配置成功
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
</head>
<body>
<form action="/oauth2/authorization/gitee" method="post" onsubmit="onsubmitFun()">
<input type="submit" value="Gitee授權(quán)登錄">
</form>
</body>
</html>
以上就配置成功了。更多相關(guān)springsecurity第三方授權(quán)認證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringSecurity實現(xiàn)權(quán)限認證與授權(quán)的使用示例
- SpringSecurity進行認證與授權(quán)的示例代碼
- springSecurity用戶認證和授權(quán)的實現(xiàn)
- SpringBoot整合SpringSecurity認證與授權(quán)
- 深入淺析springsecurity入門登錄授權(quán)
- SpringSecurityOAuth2實現(xiàn)微信授權(quán)登錄
- SpringBoot+SpringSecurity實現(xiàn)基于真實數(shù)據(jù)的授權(quán)認證
- SpringSecurity數(shù)據(jù)庫進行認證和授權(quán)的使用
- SpringSecurity授權(quán)機制的實現(xiàn)(AccessDecisionManager與投票決策)
相關(guān)文章
消息隊列 RabbitMQ 與 Spring 整合使用的實例代碼
本篇文章主要介紹了消息隊列 RabbitMQ 與 Spring 整合使用的實例代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08
nacos中的配置使用@Value注解獲取不到值的原因及解決方案
這篇文章主要介紹了nacos中的配置使用@Value注解獲取不到值的原因分析,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03

