Spring Security OAuth2 token权限隔离实例解析
这篇文章主要介绍了SpringSecurityOAuth2token权限隔离实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
由于项目OAuth2采用了多种模式,授权码模式为第三方系统接入,密码模式用于用户登录,Client模式用于服务间调用,
所有不同的模式下的token需要用@PreAuthorize("hasAuthority('client')")进行隔离,遇到问题一直验证不通过。
通过调试发现资源服务从授权服务拿到的authrities字段一直为空,StackOverFlow说低版本(项目中才2.0.15)的OAuth2实现权限隔离需要重写UserInfoTokenService
但是资源服务太多所以考虑重写授权服务的返回值,如何重写?在哪里重写?是下面要介绍的~
一、哪里重写?
资源服务器向授权服务服务器获取资源时候,返回的user信息重写,加入authorities
@RestController
@Slf4j
publicclassUserController{
@Autowired
HttpServletRequestrequest;
@GetMapping("/user")
publicPrincipaluser(Principalprincipal){
log.info("获取user信息:{}",JSON.toJSON(principal));returnprincipal;}
返回的具体用户信息:
{
"principal":{
"password":"$2a$10$OjTFAZEzS6qypY4nRZtnM.MzS6F3XsIlkAO/kIFCu30kAk8Yasowa",
"phone":"13918438965",
"credentialsNonExpired":true,
"accountNonExpired":true,
"enabled":true,
"accountNonLocked":true,
"username":"4738195728608789333"
},
"authenticated":true,
"oAuth2Request":{
"redirectUri":"http://www.baidu.com",
"responseTypes":["code"],
"approved":true,
"extensions":{},
"clientId":"external",
"scope":["auth_base"],
"requestParameters":{
"code":"ovzMSk",
"grant_type":"authorization_code",
"scope":"auth_base",
"response_type":"code",
"redirect_uri":"http://www.baidu.com",
"state":"123",
"client_secret":"D524C1A0811DA49592F841085CC0063EB62B3001252A9454",
"client_id":"external"
},
"refresh":false,
"grantType":"authorization_code",
"authorities":[{
"authority":"auth_base"
}],
"resourceIds":[]
},
"clientOnly":false,
"credentials":"",
"name":"4738195728608789333",
"userAuthentication":{
"principal":{
"password":"$2a$10$OjTFAZEzS6qypY4nRZtnM.MzS6F3XsIlkAO/kIFCu30kAk8Yasowa",
"phone":"13918438965",
"credentialsNonExpired":true,
"accountNonExpired":true,
"enabled":true,
"accountNonLocked":true,
"username":"4738195728608789333"
},
"authenticated":true,
"oAuth2Request":{
"responseTypes":[],
"approved":true,
"extensions":{},
"clientId":"gt",
"scope":["frontend"],
"requestParameters":{
"auth_type":"sms",
"device_id":"5c5d1d7b-50ae-4347-9aee-7a7686055f4d",
"grant_type":"password",
"client_id":"gt",
"username":"13918438965"
},
"refresh":false,
"grantType":"password",
"authorities":[{
"authority":"client"
}],
"resourceIds":[]
},
"clientOnly":false,
"credentials":"",
"name":"4738195728608789333",
"userAuthentication":{
"principal":{
"password":"$2a$10$OjTFAZEzS6qypY4nRZtnM.MzS6F3XsIlkAO/kIFCu30kAk8Yasowa",
"phone":"13918438965",
"credentialsNonExpired":true,
"accountNonExpired":true,
"enabled":true,
"accountNonLocked":true,
"username":"4738195728608789333"
},
"authenticated":true,
"name":"4738195728608789333",
"details":{
"auth_type":"sms",
"device_id":"5c5d1d7b-50ae-4347-9aee-7a7686055f4d",
"grant_type":"password",
"client_secret":"D524C1A0811DA49592F841085CC0063EB62B3001252A94542795D1CA9824A941",
"client_id":"gt",
"username":"13918438965"
},
"authorities":[]
},
"details":{
"tokenType":"Bearer",
"tokenValue":"f7870e71-7b0f-4a4a-9c6f-bb6d1f903ad9",
"remoteAddress":"0:0:0:0:0:0:0:1"
},
"authorities":[]
},
"details":{
"tokenType":"Bearer",
"tokenValue":"7829005c-5ebe-4428-b951-89477b24316e",
"remoteAddress":"0:0:0:0:0:0:0:1"
},
"authorities":[]
}
二、如何重写?
principal是OAuth2Authentication实例,OAuth2Authentication主要包括OAuth2RequeststoredRequest、AuthenticationuserAuthentication,
重写目的是将storedRequestauthorities复制到authoritie中,但问题是authoritie不让修改的,没办法只能重写这个OAuth2Authentication了。
为了改变authoritie重写:
@GetMapping("/user")
publicPrincipaluser(Principalprincipal){
log.info("获取user信息:{}",JSON.toJSON(principal));
OAuth2AuthenticationoAuth2Authentication=(OAuth2Authentication)principal;
OAuth2RequeststoredRequest=oAuth2Authentication.getOAuth2Request();
AuthenticationuserAuthentication=oAuth2Authentication.getUserAuthentication();
//为了服务端进行token权限隔离定制OAuth2Authentication
CustomOAuth2AuthenticationcustomOAuth2Authentication=newCustomOAuth2Authentication(storedRequest,userAuthentication,storedRequest.getAuthorities());
customOAuth2Authentication.setDetails(oAuth2Authentication.getDetails());
log.info("返回用户信息:{}",JSON.toJSON(customOAuth2Authentication));
returncustomOAuth2Authentication;
}
CustomOAuth2Authentication:
packagecom.brightcns.wuxi.citizencard.auth.domain;
importorg.springframework.security.authentication.AbstractAuthenticationToken;
importorg.springframework.security.core.Authentication;
importorg.springframework.security.core.CredentialsContainer;
importorg.springframework.security.core.GrantedAuthority;
importorg.springframework.security.oauth2.provider.OAuth2Request;
importjava.util.Collection;
/**
*@authormaxianming
*@date2018/10/2913:53
*/
publicclassCustomOAuth2AuthenticationextendsAbstractAuthenticationToken{
privatestaticfinallongserialVersionUID=-4809832298438307309L;
privatefinalOAuth2RequeststoredRequest;
privatefinalAuthenticationuserAuthentication;
/**
*ConstructanOAuth2authentication.Sincesomegranttypesdon'trequireuserauthentication,theuser
*authenticationmaybenull.
*@paramstoredRequestTheauthorizationrequest(mustnotbenull).
*@paramuserAuthenticationTheuserauthentication(possiblynull).
*/
publicCustomOAuth2Authentication(OAuth2RequeststoredRequest,AuthenticationuserAuthentication,Collectionauthorities){
/**
*为了服务端进行token权限隔离{@link@PreAuthorize("hasAuthority('server')")},自定义OAuth2Authentication使得支持改变authorities
*/
super(authorities!=null?authorities:userAuthentication==null?storedRequest.getAuthorities():userAuthentication.getAuthorities());
this.storedRequest=storedRequest;
this.userAuthentication=userAuthentication;
}
publicObjectgetCredentials(){
return"";
}
publicObjectgetPrincipal(){
returnthis.userAuthentication==null?this.storedRequest.getClientId():this.userAuthentication
.getPrincipal();
}
/**
*Conveniencemethodtocheckifthereisauserassociatedwiththistoken,orjustaclientapplication.
*
*@returntrueifthistokenrepresentsaclientappnotactingonbehalfofauser
*/
publicbooleanisClientOnly(){
returnuserAuthentication==null;
}
/**
*Theauthorizationrequestcontainingdetailsoftheclientapplication.
*
*@returnTheclientauthentication.
*/
publicOAuth2RequestgetOAuth2Request(){
returnstoredRequest;
}
/**
*Theuserauthentication.
*
*@returnTheuserauthentication.
*/
publicAuthenticationgetUserAuthentication(){
returnuserAuthentication;
}
@Override
publicbooleanisAuthenticated(){
returnthis.storedRequest.isApproved()
&&(this.userAuthentication==null||this.userAuthentication.isAuthenticated());
}
@Override
publicvoideraseCredentials(){
super.eraseCredentials();
if(this.userAuthentication!=null&&CredentialsContainer.class.isAssignableFrom(this.userAuthentication.getClass())){
CredentialsContainer.class.cast(this.userAuthentication).eraseCredentials();
}
}
@Override
publicbooleanequals(Objecto){
if(this==o){
returntrue;
}
if(!(oinstanceofCustomOAuth2Authentication)){
returnfalse;
}
if(!super.equals(o)){
returnfalse;
}
CustomOAuth2Authenticationthat=(CustomOAuth2Authentication)o;
if(!storedRequest.equals(that.storedRequest)){
returnfalse;
}
if(userAuthentication!=null?!userAuthentication.equals(that.userAuthentication)
:that.userAuthentication!=null){
returnfalse;
}
if(getDetails()!=null?!getDetails().equals(that.getDetails()):that.getDetails()!=null){
//returnfalse;
}
returntrue;
}
@Override
publicinthashCode(){
intresult=super.hashCode();
result=31*result+storedRequest.hashCode();
result=31*result+(userAuthentication!=null?userAuthentication.hashCode():0);
returnresult;
}
}
主要在OAuth2Authentication基础上修改了30-35行代码
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。