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(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。