Spring Cloud OAuth2和JWT保護微服務(wù)_第1頁
Spring Cloud OAuth2和JWT保護微服務(wù)_第2頁
Spring Cloud OAuth2和JWT保護微服務(wù)_第3頁
Spring Cloud OAuth2和JWT保護微服務(wù)_第4頁
Spring Cloud OAuth2和JWT保護微服務(wù)_第5頁
已閱讀5頁,還剩36頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、采用Spring Security AOuth2和JWT的方式,避免每次請求都需要遠程調(diào)度 Uaa服務(wù)。采用Spring Security OAuth2和JWT的方式,Uaa服務(wù)只驗證一 次,返回JWT。返回的JWT包含了用戶的所有信息,包括權(quán)限信息。什么是JWT?JSON Web Token(JWT)是一種開放的標(biāo)準(zhǔn)(RFC 7519),JWT 定義了一種 緊湊且自包含的標(biāo)準(zhǔn),該標(biāo)準(zhǔn)旨在將各個主體的信息包裝為JSON對象。主體 信息是通過數(shù)字簽名進行加密和驗證的。常使用HMAC算法或RSA (公鑰/ 私鑰的非對稱性加密)算法對JWT進行簽名,安全性很高。JWT特點:緊湊型:數(shù)據(jù)體積小,可通過

2、POST請求參數(shù)或HTTP請求頭發(fā)送。自包含:JWT包含了主體的所有信息,避免了每個請求都需要向Uaa服務(wù)驗 證身份,降低了服務(wù)器的負載。2.JWT的結(jié)構(gòu)JWT結(jié)構(gòu):Header (頭)Payload (有效載荷)Signature (簽名)因此,JWT的通常格式是:xxxxx.yyyyy.zzzzz(1)HeaderHeader通常是由兩部分組成:令牌的類型(即JWT)和使用的算法類型,如HMAC、SHA256 和 RSA。例如:將Header用Base64編碼作為JWT的第一部分。Payload這是JWT的第二部分,包含了用戶的一些信息和Claim (聲明、權(quán)利)。有3 類型的Claim:

3、保留、公開和私人?!?,name: John Doe,5將Payload用Base64編碼作為JWT的第一部分。Signature要創(chuàng)建簽名部分,需要將Base64編碼后的Header、Payload和秘鑰進行簽 名,一個典型的格式如下:HMACSHA256(base64UrlEncode(header) + . +base64UrlEncode(payload),L3.如何使用JWT認證流程圖如下,客戶端獲取JWT后,以后每次請求都不需要再通過Uaa服務(wù) 來判斷該請求的用戶以及該用戶的權(quán)限。在微服務(wù)中,可以利用JWT實現(xiàn)單點 登錄。4.案例工程架構(gòu)三個工程:. eureka-server:注冊

4、服務(wù)中心,端口 8761。這里不再演示搭建。. auth-service:負責(zé)授權(quán),授權(quán)需要用戶提供客戶端的clientId和password, 以及授權(quán)用戶的username和password。這些信息準(zhǔn)備無誤之后, auth-service返回JWT,該JWT包含了用戶的基本信息和權(quán)限點信息,并 通過RSA加密。.user-service:作為資源服務(wù),它的資源以及被保護起來了,需要相應(yīng)的權(quán)限 才能訪問。user-service服務(wù)得到用戶請求的JWT后,先通過公鑰解密JWT, 得到該JWT對應(yīng)的用戶的信息和用戶的權(quán)限信息,再判斷該用戶是否有權(quán)限 訪問該資源。工程架構(gòu)圖: 3 瀏覽器L登錄

5、4返回用戶信息+tohr&nEu rekaServer2.信息確認無誤返回TokenAuth-Service-W.荻取丁口足。User-service5.構(gòu)建 auth-service 工程1.新建Spring Boot工程,取名為auth-service,其完整pom.xml文件為.4.0.0org.springframework.bootspring-boot-starter-parent1.5.3.RELEASE com.exampleauth-service0.0.1-SNAPSHOTauth-serviceDemo project for Spring Boot1.8Dalston.

6、SR1org.springframework.cloudspring-cloud-starter-eurekaorg.springframework.bootspring-boot-starter-weborg.springframework.securityspring-security-jwtorg.springframework.security.oauthspring-security-oauth2org.springframework.bootspring-boot-starter-data-jpamysqlmysql-connector-javaorg.springframewor

7、k.bootspring-boot-starter-testtestorg.springframework.cloudspring-cloud-dependencies$spring-cloud.versionpomimportorg.springframework.bootspring-boot-maven-pluginorg.apache.maven.pluginsmaven-resources-pluginconfigurationcertjksspring:application:name: auth-servicedatasource:driver-class-name: com.m

8、ysql.jdbc.Driverurl:jdbc:mysql:/localhost:3306/spring-cloud-auth?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8username: rootpassword: 123456jpa:hibernate:dd -auto: updateshow-sql: trueserver:port: 9999eureka:client:serviceUrl:defaultZon : HYPERLINK http:/localhost:8761/eureka/ http

9、:/localhost:8761/eureka/3.配置 Spring SecurityConfigurationEnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter OverrideBeanpublic AuthenticationManager authenticationManagerBean() throws Exception return super.authenticationManagerBean();Overrideprotected void configu

10、re(HttpSecurity http) throws Exception http.csrf().disable() /關(guān)閉 CSRF.exceptionHandling().authenticationEntryPoint(request, response,authException)-response sendError(HttpServletResponse.SC_UNAUTHORIZED).and().authorizeRequests().antMatchers(/*”).authenticated().and().httpBasic();AutowiredUserServic

11、eDetail userServiceDetai ;Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception aut.userDetailsService(userServiceDetail).passwordEncoder(new BCryptPasswordEncoder(); 密碼加密UserServiceDetail.javaServicepublic class UserServiceDetail implements UserDetailsService Autowire

12、dprivate UserDao userRepository;Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException return userRepository.findByUsername(username);UserDao.javaRepositorypublic interface UserDao extends JpaRepository User findByUsername(String username);User對象和上一篇文章的內(nèi)容一樣,需

13、要實現(xiàn)UserDetails接口,Role對象需 要實現(xiàn) GrantedAuthority 接口.Entitypublic class User implements UserDetails, Serializable IdGeneratedValue(strategy = GenerationType.IDENTITY)private Long id;Column(nullable = false, unique = true)private String username;Columnprivate String password;ManyToMany(cascade = CascadeT

14、ype.ALL, fetch = FetchType.EAGER)JoinTable(name = user_role, joinColumns = JoinColumn(name = user_id, referencedColumnName = id),inverseJoinColumns= JoinColumn(name = role_id, referencedColumnName = id)private List authorities;public User() public Long getId() return id;public void setId(Long id) th

15、is.id = id;Overridepublic Collection getAuthorities() return authorities;public void setAuthorities(List authorities) this.authorities = authorities;IOverridepublic String getUsername() 5public void setUsername(String username) this.username = username;Overridepublic String getPassword() return pass

16、word;public void setPassword(String password) this.password = password;Overridepublic boolean isAccountNonExpired() return true;IOverridepublic boolean isAccountNonLocked() 5 fOverridepublic boolean isCredentialsNonExpired() return true;Overridepublic boolean isEnabled() ,public class Role implement

17、s GrantedAuthority IdGeneratedValue(strategy = GenerationType.IDENTITY) private Long id;Column(nullable = false) private String name;public Long getId() public void setId(Long id) 廣 id=id;Overridepublic String getAuthority() I name;public void setName(String name) Overridepublic String toString() :m

18、4.配置 Authorization Server在OAuth2Config這個類中配置Authorizationserver,其代碼如下:ConfigurationEnableAuthorizationServerpublic class OAuth2Config extends AuthorizationServerConfigurerAdapter Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception client .inMemory() 將客戶端的信息存儲在內(nèi)存中.w

19、ithClient(user-service) /創(chuàng)建了一個 Client 為 user-service的客戶端.secret(123456).scopes(service) 客戶端的域.authorizedGrantTypes(refresh_token, password) /配置 類驗證類型為 refresh_token和password.accessTokenValiditySeconds(12*300); /5min 過期Overridepublic void configure(AuthorizationServerEndpointsConfigurer endpoints) th

20、rows Exception endpoints.tokenStore(tokenStore().tokenEnhancer(jwtTokenEnhancer().au thenticationManager(authenticationManager);AutowiredQualifier(authenticationManagerBean)private AuthenticationManager authenticationManager;Beanpublic TokenStore tokenStore() return new JwtTokenStore(jwtTokenEnhance

21、r();Beanprotected JwtAccessTokenConverter jwtTokenEnhancer() /注意此處需要相應(yīng)的jks文件KeyStoreKeyFactorykeyStoreKeyFactory = new KeyStoreKeyFactory(new ClassPathResource(fzp-jwt.jks), fzp123”.toCharArray();JwtAccessTokenConverterconverter = new JwtAccessTokenConverter。; converte.setKeyPair(keyStoreKeyFactory.

22、getKeyPair(fzp-jwt);return converter;5.生成jks文件配置JwtTokenStore時需要使用jks文件作為Token加密的秘鑰。jks文件需要Java keytool工具,保證Java環(huán)境變量沒問題,打開計算機終端, 輸入命令:keytool -genkeypair -alias fzp-jwt -validity 3650 -keyalg RSA -dname CN=jwt,OU=jtw,O=jwt,L=zurich,S=zurich,C=CH -keypass fzp123 -keystore fzp-jwt.jks -storepass fzp12

23、3解釋,-alias選項為別名,-keypass和-storepass為密碼選項,-validity為配 置jks文件過期時間(單位:天)。獲取的jks文件作為私鑰,只允許Uaa服務(wù)持有,并用作加密JWT。也就是 把生成的jks文件放到auth-service工程的resource目錄下。那么 user-service這樣的資源服務(wù),是如何解密JWT的呢?這時就需要使用jks 文件的公鑰。獲取jks文件的公鑰命令如下:keytool -list -rfc -keystore fzp-jwt.jks I openssl x509 -inform pem -pubkey這個命令要求你的計算機上安裝

24、了 openSSL (下載地址),然后手動把安裝的 openssl.exe所在目錄配置到環(huán)境變量。輸入密碼fzp123后,顯示的信息很多,我們只提取PUBLIC KEY,即如下所示:-BEGIN PUBLIC KEY-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlCFiWbZXIb5kwE aHjW+/7J4b+KzXZffRl5RJ9rAMgfRXHqGG8RM2Dlf95JwTXzerY6igUq7FVgFjnPbexVt3 vKKyjdy2gBuOaXqaYJEZSfuKCNN/WbOF8e7ny4fLMFilbhpzoqkSHiR+nAHLk

25、Y ctOnOKMPK1SwmvkNMn3aTEJHhxGh1RlWbMAAQ+QLI2D7zCzQ7Uh3F+Kw0pd 2gBYd8W+DKTn1Tprugdykirr6u0p66yK5f1T9O+LEaJa8FjtLF66siBdGRaNYMExNi21lJk i5dD3ViVBIVKi9ZaTsK9Sxa3dOX1aE5Zd5A9cPsBIZ12spYgemfj6DjOw6lk7jkG 9QIDAQAB END PUBLIC KEY新建一個public.cert文件,將上面的公鑰信息復(fù)制到public.cert文件中并保 存。并將文件放到user-service等資源服務(wù)的resour

26、ces目錄下。到目前為止, Uaa服務(wù)已經(jīng)搭建完畢。需要注意的是,Maven在項目編譯時,可能會將jks文件編譯,導(dǎo)致jks文件 亂碼,最后不可用。需要在工程的pom文件中添加以下內(nèi)容:org.apache.maven.pluginsmaven-resources-pluginconfigurationcertjks/configuration最后,別忘了在啟動類注解EnableEurekaClient開啟服務(wù)注冊.SpringBootApplicationEnableEurekaClientpublic class AuthServiceApplication public static v

27、oid main(String args) SpringApplicatio.run(AuthServiceApplication.class, args);6.構(gòu)建user-service資源服務(wù)1.新建Spring Boot工程,取名為user-service,其完整pom.xml文件:4.0.0org.springframework.boot spring-boot-starter-parent1.5.3.RELEASE com.exampleuser-service0.0.1-SNAPSHOTuser-serviceDemo project for Spring Boot1.8Dals

28、ton.SR1org.springframework.cloudspring-cloud-starter-eurekaorg.springframework.bootspring-boot-starter-weborg.springframework.security.oauthspring-security-oauth2org.springframework.bootspring-boot-starter-data-jpamysqlmysql-connector-javaorg.springframework.cloudspring-cloud-starter-hystrixorg.spri

29、ngframework.cloudspring-cloud-starter-feignorg.springframework.bootspring-boot-starter-testtestorg.springframework.cloudspring-cloud-dependencies$spring-cloud.versionpom importorg.springframework.bootspring-boot-maven-plugin配置文件 application.yml在工程的配置文件application.yml中,配置程序名為user-service,端口號為 9090,另外

30、,需要配置 feign.hystrix.enable 為 true,即開啟 Feign 的 Hystrix功能。完整的配置代碼如下:server:port: 9090eureka:client:service-url:defaultZon : HYPERLINK http:/localhost:8761/eureka/ http:/localhost:8761/eureka/spring:application:name: user-servicedatasource:driver-class-name: com.mysql.jdbc.Driverurl:jdbc:mysql:/localho

31、st:3306/spring-cloud-auth?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8username: rootpassword: 123456jpa:hibernate:dd -auto: updateshow-sql: truefeign:hystrix:enabled: true配置 Resource Server在配置Resource Server之前,需要注入JwtTokenStore類型的Bean。Configurationpublic class JwtConfig AutowiredJ

32、wtAccessTokenConverter jwtAccessTokenConverte ;BeanQualifier(tokenStore)public TokenStore tokenStore() return new JwtTokenStore(jwtAccessTokenConverter);Beanprotected JwtAccessTokenConverter jwtTokenEnhancer() /用作JWT轉(zhuǎn)換器JwtAccessTokenConverter converter= new JwtAccessTokenConverter。;Resource resource

33、= new ClassPathResource(public.cert);String publicKey;try publicKey= newString(FileCopyUtils.copyToByteArray(resource.getInputStream(); catch (IOException e) throw new RuntimeException(e);555_設(shè)置公鑰然后配置 Resource ServerConfigurationEnableResourceServer /開啟 Resource Server 功能public class ResourceServerC

34、onfig extends ResourceServerConfigurerAdapterAutowiredTokenStore tokenStore;Overridepublic void configure(HttpSecurity http) throws Exception http.csrf().disable().authorizeRequests().antMatchers(/user/login”,”/user/register).permitAll().antMatchers(/*”).authenticated();Overridepublic void configure

35、(ResourceServerSecurityConfigurer resources) throws Exception resource.tokenStore(tokenStore);新建一個配置類GlobalMethodSecurityConfig,在此類中通過EnableGlobalMethodSecurity(prePostEnabled = true)注解開啟方法級別的安 全驗證。ConfigurationEnableGlobalMethodSecurity(prePostEnabled = true)public class GlobalMethodSecurityConfig

36、編寫用戶注冊接口拷貝 auth-service 工程的 User.java、Role.java 和 UserDao.java 到本工程。在Service層的UserService寫一個插入用戶的方法,代碼如下Servicepublic class UserServiceDetail Autowiredprivate UserDao userRepository;public User insertUser(String username,String password)User use=new User();use.setUsername(username);use.setPassword(B

37、PwdEncoderUtil.BCryptPassword(password);return userRepository.save(user);BPwdEncoderUtil 工具類public class BPwdEncoderUtil private static final BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();public static String BCryptPassword(String password) return encoder.encode(password);public static

38、 boolean matches(CharSequence rawPassword, String encodedPassword)在 Web層,在Controller中與一個注冊的API接口 “/user/regist代碼如 下RestControllerRequestMapping(/user)public class UserController AutowiredUserServiceDetail userServiceDetai ;伊ostMapping(/register)public User postUser(RequestParam(username) String user

39、name , RequestParam(password) String password)參數(shù)判斷,省略return userServiceDetail.insertUser(username,password);編寫用戶登錄接口在Service層,在UserServiceDetail中添加一個login (登錄)方法,代碼如 下:Servicepublic class UserServiceDetail Autowiredprivate AuthServiceClient client;public UserLoginDTO login(String username, String pa

40、ssword)User use=userRepository.findByUsername(username);if (null = user) throw new UserLoginException(error username);if(!BPwdEncoderUtil.matches(password,user.getPassword() throw new UserLoginException(error password);/ 獲取 tokenJWT jw=client.getToken(BasicdXNlci1zZXJ2aWNlOjEyMzQ1Ng=,password,userna

41、me,password);/獲得用戶菜單if(jwt=null)throw new UserLoginException(error internal);UserLoginDTO userLoginDT=new UserLoginDTO();userLoginDT.setJwt(jwt);userLoginDT.setUser(user);return userLoginDTO;AuthServiceClient 通過向 auth-service 服務(wù)遠程調(diào)用“/oauth/token” API接口, 獲取 JWT。在/oauth/token API 接口,獲取JWT。在“/oauth/tok

42、en”API 接口 中需要在請求頭傳入Authorization信息,并需要傳請求參數(shù)認證類型 grant_type、用戶名 username 和密碼 password,代碼如下:FeignClient(value = auth-service,fallback =AuthServiceHystrix.class )public interface AuthServiceClient 伊ostMapping(value = /oauth/token)JWT getToken(RequestHeader(value = Authorization) String authorization, R

43、equestParam(grant_type) String typeRequestParam(username) String username, RequestParam(password) String password);其中,AuthServiceHystrix 為 AuthServiceClient 的熔斷器,代碼如下:Componentpublic class AuthServiceHystrix implements AuthServiceClient Overridepublic JWT getToken(String authorization, String type,

44、String username,String password) return null;JWT 為一個 JavaBean,它包含了 access_token、token_type 和 refresh_token等信息,代碼如下: public class JWT private String access_token;private String token_type:private String refresh_token;private int expires_in;private String scope;private String jti;/getter setterUserLog

45、inDTO包含了一個User和一個JWT對象,用于返回數(shù)據(jù)的實體: public class UserLoginDTO private JWT jwt;private User user;/setter getter登錄異常類 UserLoginExceptionpublic class UserLoginException extends RuntimeExceptionpublic UserLoginException(String message) super(message);統(tǒng)一異常處理ControllerAdviceResponseBodypublic class Exceptio

46、nHandle ExceptionHandler(UserLoginException.class)public ResponseEntity handleException(Exception e) return new ResponseEntity(e.getMessage(), HttpStatus.OK);在 web 層的 UserController 類補充一個登錄的 API 接口 “/user/login”.PostMapping(/login) public UserLoginDTO login(RequestParam(username) String username , R

47、equestParam(password) String password)參數(shù)判斷,省略return userServiceDetail.login(username,password);為了測試權(quán)限,再補充一個/foo接口,該接口需要“ROLE_ADMIN”權(quán)限.RequestMapping(value = /foo, method = RequestMethod.GET)PreAuthorize(hasAuthority(ROLE_ADMIN)public String getFoo() return im foo, + UUID.randomUUID().toString();最后,在

48、啟動類注解開啟Feign:SpringBootApplicationEnableFeignClientsEnableEurekaClientpublic class UserServiceApplication public static void main(String args) SpringApplicatio.run(UserServiceApplication.class, args);7.啟動工程,開始測試經(jīng)過千辛萬苦,終于搭建了一個Demo工程,現(xiàn)在開始依次啟動eureka-server、auth-service和user-service工程。這里我們使用PostMan測試編寫的

49、接口。1.注冊用戶post | z-c31 ho r:9 ogo/use registe r+ Iqc 1 host; 9090/user regi 5te rPOSTloca I he st:9C ? 3/u ser/r eg i ste -SlaliJg: 200-OKAiJthi-oriatinn Headers Body Pre-request Seri pt TestsKEYVALUEusernamema rkpji Esward123456KeyValueraie farm-data x-www-ferm-ur encoded raw binaryDESCIDeacBody Coo

50、kies Headers ?) Test ResultsPretty Raw Preview JSON R,it1,: 19,usernane:marK,Jpa5 5WDrdr,:SZdSlCEztrzDXoUi0.u4Qi.t2S4eDt37hcbFslSqV5Oe3nwdFj5LiKNW,Jautharities:lljenabledt-,accauntNbnLocIced: zr JSj匚redentiDlsrnorExijired:二acciJiintNnExpired: t192.登錄獲取Tokenp(mt lacaIhost:9ogo/user/register poet Iaca

51、Ihoc:909Cvuser/lgin+ Iqc ml host; 9090/user/logiriPOST 、I c ca I h c st:9D5 0 /u ser/l ogi nParamsAlJth-arizationheadersBody Pre-request ScriptTestsroie farm-datax-www-fcrm-Li - encod edrawbinaryKEYVALUEuernmema-password123456KeyValueBody Cookies Headers Test ResultsPretty Raw Previ-ew JSON m:2- jwt

52、: tn*E“_zcikEn: eyJhbGziCiilSUzIlFliZiInft5L&ZpXVCJ9.eyj 1 eHA iOj E UBc 2WM)XJ/ Irfl/zZXJ -FbmFt Z 516 Mil cms i L C J qdG kdDil 1Hz J kZ j e3MCa2YTdi LTQ5I -vCAtk ICzv08 a2uh iarfrl6 XkLOwn JHRXLwS-vE4OTfm r6iCu cna_FK -ZSQrDll- ;5G;-ln 2 5 _E 5s Nft -QHn EIECIC i sC SO 3 uE匚 uyX_ dytJtif二郭 RH S-jiiDjElNTAyMErHCiDY5l:nVEZXbinFtZSIbImltiLnsiLtlqsGkiCi: jYniQKinlzliNK22TE7L_Ql 叫h心Fk陽J? ,

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論