springboot之oauth2

一薄翅、OAuth2.0是OAuth協(xié)議的延續(xù)版本吗垮,但不向后兼容OAuth 1.0即完全廢止了OAuth1.0秽梅。 OAuth 2.0關(guān)注客戶端開發(fā)者的簡(jiǎn)易性。要么通過組織在資源擁有者和HTTP服務(wù)商之間的被批準(zhǔn)的交互動(dòng)作代表用戶,要么允許第三方應(yīng)用代表用戶獲得訪問的權(quán)限涧至。同時(shí)為Web應(yīng)用,桌面應(yīng)用和手機(jī),和起居室設(shè)備提供專門的認(rèn)證流程提澎。

二、使用場(chǎng)景:

  1念链、自己開發(fā)應(yīng)用時(shí)盼忌,需要獲取其他應(yīng)用的資源。比如:使用QQ登錄掂墓,然后獲取QQ頭像等信息

  2谦纱、SSO認(rèn)證服務(wù)器,在自己開發(fā)應(yīng)用時(shí)使用統(tǒng)一的認(rèn)證過程君编,不需要單獨(dú)重寫重寫認(rèn)證體系

三跨嘉、概念 

  (1)?Third-party application:第三方應(yīng)用程序吃嘿,本文中又稱"客戶端"(client)祠乃。

 ∶沃亍(2)HTTP service:HTTP服務(wù)提供商,本文中簡(jiǎn)稱"服務(wù)提供商"亮瓷。

 ∏倥 (3)Resource Owner:資源所有者,本文中又稱"用戶"(user)嘱支。

 “丁(4)User Agent:用戶代理,本文中就是指瀏覽器斗塘。

 ∮(5)Authorization server:認(rèn)證服務(wù)器,即服務(wù)提供商專門用來處理認(rèn)證的服務(wù)器馍盟。

 ∮谥谩(6)Resource server:資源服務(wù)器,即服務(wù)提供商存放用戶生成的資源的服務(wù)器贞岭。它與認(rèn)證服務(wù)器八毯,可以是同一臺(tái)服務(wù)器,也可以是不同的服務(wù)器瞄桨。

  OAuth在"客戶端"與"服務(wù)提供商"之間话速,設(shè)置了一個(gè)授權(quán)層(authorization layer)。"客戶端"不能直接登錄"服務(wù)提供商"芯侥,只能登錄授權(quán)層泊交,以此將用戶與客戶端區(qū)分開來。"客戶端"登錄授權(quán)層所用的令牌(token)柱查,與用戶的密碼不同廓俭。用戶可以在登錄的時(shí)候,指定授權(quán)層令牌的權(quán)限范圍和有效期唉工。

  "客戶端"登錄授權(quán)層以后研乒,"服務(wù)提供商"根據(jù)令牌的權(quán)限范圍和有效期,向"客戶端"開放用戶儲(chǔ)存的資料淋硝。

四雹熬、模式運(yùn)行流程

(A)用戶打開客戶端以后,客戶端要求用戶給予授權(quán)谣膳。

(B)用戶同意給予客戶端授權(quán)竿报。

(C)客戶端使用上一步獲得的授權(quán),向認(rèn)證服務(wù)器申請(qǐng)令牌参歹。

(D)認(rèn)證服務(wù)器對(duì)客戶端進(jìn)行認(rèn)證以后仰楚,確認(rèn)無誤,同意發(fā)放令牌。

(E)客戶端使用令牌僧界,向資源服務(wù)器申請(qǐng)獲取資源侨嘀。

(F)資源服務(wù)器確認(rèn)令牌無誤,同意向客戶端開放資源捂襟。

五咬腕、授權(quán)模式

授權(quán)碼模式(authorization code)

簡(jiǎn)化模式(implicit)

密碼模式(resource owner password credentials)

客戶端模式(client credentials)

1)授權(quán)碼模式


(A)用戶訪問客戶端,后者將前者導(dǎo)向認(rèn)證服務(wù)器葬荷。

 ≌枪病(B)用戶選擇是否給予客戶端授權(quán)。

 〕桎觥(C)假設(shè)用戶給予授權(quán)举反,認(rèn)證服務(wù)器將用戶導(dǎo)向客戶端事先指定的"重定向URI"(redirection URI),同時(shí)附上一個(gè)授權(quán)碼扒吁。

 』鸨恰(D)客戶端收到授權(quán)碼,附上早先的"重定向URI"雕崩,向認(rèn)證服務(wù)器申請(qǐng)令牌魁索。這一步是在客戶端的后臺(tái)的服務(wù)器上完成的,對(duì)用戶不可見盼铁。

 〈治怠(E)認(rèn)證服務(wù)器核對(duì)了授權(quán)碼和重定向URI,確認(rèn)無誤后饶火,向客戶端發(fā)送訪問令牌(access token)和更新令牌(refresh token)鹏控。

  2)簡(jiǎn)化模式

 (B)用戶決定是否給于客戶端授權(quán)趁窃。

∧琳酢(C)假設(shè)用戶給予授權(quán),認(rèn)證服務(wù)器將用戶導(dǎo)向客戶端指定的"重定向URI"醒陆,并在URI的Hash部分包含了訪問令牌。

●烧搿(D)瀏覽器向資源服務(wù)器發(fā)出請(qǐng)求刨摩,其中不包括上一步收到的Hash值。

∈蓝帧(E)資源服務(wù)器返回一個(gè)網(wǎng)頁澡刹,其中包含的代碼可以獲取Hash值中的令牌。

≡呕椤(F)瀏覽器執(zhí)行上一步獲得的腳本罢浇,提取出令牌。

 (G)瀏覽器將令牌發(fā)給客戶端嚷闭。

 3)密碼模式

 ≡艿骸(A)用戶向客戶端提供用戶名和密碼。

 “獭(B)客戶端將用戶名和密碼發(fā)給認(rèn)證服務(wù)器灾锯,向后者請(qǐng)求令牌。

 ⌒衢拧(C)認(rèn)證服務(wù)器確認(rèn)無誤后顺饮,向客戶端提供訪問令牌。

4)客戶端模式


(A)客戶端向認(rèn)證服務(wù)器進(jìn)行身份認(rèn)證凌那,并要求一個(gè)訪問令牌兼雄。

  (B)認(rèn)證服務(wù)器確認(rèn)無誤后帽蝶,向客戶端提供訪問令牌君旦。

  六、授權(quán)碼模式例子

  這里說明一下這里主要只通過授權(quán)碼模式來講解oauth2的使用過程嘲碱。

  授權(quán)碼模式(authorization code)是功能最完整金砍、流程最嚴(yán)密的授權(quán)模式。它的特點(diǎn)就是通過客戶端的后臺(tái)服務(wù)器麦锯,與"服務(wù)提供商"的認(rèn)證服務(wù)器進(jìn)行互動(dòng)恕稠。

  簡(jiǎn)化模式(implicit grant type)不通過第三方應(yīng)用程序的服務(wù)器,直接在瀏覽器中向認(rèn)證服務(wù)器申請(qǐng)令牌扶欣,跳過了"授權(quán)碼"這個(gè)步驟鹅巍,因此得名。所有步驟在瀏覽器中完成料祠,令牌對(duì)訪問者是可見的骆捧,且客戶端不需要認(rèn)證。

  密碼模式(Resource Owner Password Credentials Grant)中髓绽,用戶向客戶端提供自己的用戶名和密碼敛苇。客戶端使用這些信息顺呕,向"服務(wù)商提供商"索要授權(quán)枫攀。

  客戶端模式(Client Credentials Grant)指客戶端以自己的名義,而不是以用戶的名義株茶,向"服務(wù)提供商"進(jìn)行認(rèn)證来涨。嚴(yán)格地說,客戶端模式并不屬于OAuth框架所要解決的問題启盛。在這種模式中蹦掐,用戶直接向客戶端注冊(cè)技羔,客戶端以自己的名義要求"服務(wù)提供商"提供服務(wù),其實(shí)不存在授權(quán)問題卧抗。

  相對(duì)來說授權(quán)碼的方式使用上面藤滥,是非常嚴(yán)謹(jǐn)?shù)摹2淮嬖诳盼叮渌J降南鄬?duì)弊病超陆。

7、代碼部分

  1)需要的依賴

<parent>

? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? <artifactId>spring-boot-starter-parent</artifactId>

? ? ? ? <version>2.0.0.RELEASE</version>

? ? </parent>

? ? <dependencies>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? ? ? <artifactId>spring-boot-starter-web</artifactId>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.boot</groupId>

? ? ? ? ? ? <artifactId>spring-boot-starter-security</artifactId>

? ? ? ? </dependency>

? ? ? ? <dependency>

? ? ? ? ? ? <groupId>org.springframework.security.oauth.boot</groupId>

? ? ? ? ? ? <artifactId>spring-security-oauth2-autoconfigure</artifactId>

? ? ? ? ? ? <version>2.1.2.RELEASE</version>

? ? ? ? </dependency>

? ? </dependencies>

2)認(rèn)證服務(wù)器


主要配置:SecurityConfiguration浦马、AuthServerConfiguration

@Configuration

@EnableWebSecurity

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

? ? @Autowired

? ? private BCryptPasswordEncoder passwordEncoder;

? ? @Override

? ? protected void configure(HttpSecurity http) throws Exception {

? ? ? ? http

? ? ? ? ? ? .csrf().disable()

? ? ? ? ? ? .exceptionHandling()

? ? ? ? .and()

? ? ? ? ? ? .authorizeRequests()

? ? ? ? ? ? .anyRequest().authenticated()

? ? ? ? .and()

? ? ? ? ? ? .formLogin();

? ? }

? ? @Override

? ? protected void configure(AuthenticationManagerBuilder builder) throws Exception {

? ? ? ? //內(nèi)存用戶不多解釋

? ? ? ? builder.inMemoryAuthentication()

? ? ? ? ? ? ? ? .withUser("admin")

? ? ? ? ? ? ? ? .password(passwordEncoder.encode("admin"))

? ? ? ? ? ? ? ? .roles("ADMIN");

? ? }

? ? @Override

? ? @Bean

? ? public AuthenticationManager authenticationManagerBean() throws Exception {

? ? ? ? return super.authenticationManagerBean();

? ? }

   @Bean   @Override   protected UserDetailsService userDetailsService() {? ?   return super.userDetailsService();   }

}

@Configuration

@EnableAuthorizationServer

public class AuthServerConfiguration extends AuthorizationServerConfigurerAdapter {

? ? @Autowired

? ? private BCryptPasswordEncoder passwordEncoder;

? ? @Autowired

? ? private AuthenticationManager authenticationManager;

? ? @Override

? ? public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

? ? ? ? //這里client使用存在模式时呀,可以實(shí)際過程調(diào)整為jdbc的方式

? ? ? ? //這里說明一下,redirectUris的連接可以是多個(gè)晶默,這里通過access_token都可以訪問的

? ? ? ? //簡(jiǎn)單點(diǎn)谨娜,就是授權(quán)的過程

? ? ? ? clients.inMemory()

? ? ? ? ? ? ? ? .withClient("client")

? ? ? ? ? ? ? ? .secret(passwordEncoder.encode("secret"))

? ? ? ? ? ? ? ? .authorizedGrantTypes("authorization_code", "refresh_token")

? ? ? ? ? ? ? ? .scopes("All")

? ? ? ? ? ? ? ? .autoApprove(true)

? ? ? ? ? ? ? ? .redirectUris("http://localhost:9001/login", "http://localhost:9002/login", "http://localhost:9003/authorize/login");

? ? }

? ? @Override

? ? public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {

? ? ? ? //權(quán)限控制

? ? ? ? security.tokenKeyAccess("permitAll()")

? ? ? ? ? ? ? ? .checkTokenAccess("isAuthenticated()")

? ? ? ? ? ? ? ? .allowFormAuthenticationForClients();

? ? }

? ? @Override

? ? public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

? ? ? ? //認(rèn)證體系使用security的方式

? ? ? ? endpoints.authenticationManager(authenticationManager);

      //允許調(diào)用方式

     endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);     endpoints.userDetailsService(userDetailsService);

? ? }

說明:這里我為了更好的區(qū)分,把認(rèn)證服務(wù)器和資源服務(wù)器分開的磺陡,實(shí)際上可以使用認(rèn)證服務(wù)器作為資源服務(wù)器

server:

? port: 9000

? servlet:

? ? context-path: /auth #這里一定要加上contextPath趴梢,這個(gè)坑自己體會(huì)吧

  yaml配置

3)資源服務(wù)器


主要配置:ResourceServerConfiguration、application.yaml

/**

* 資源服務(wù)器的配置也很簡(jiǎn)單

* 主要是EnableResourceServer币他,以及資源的控制

*/

@Configuration

@EnableResourceServer

public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

? ? @Override

? ? public void configure(HttpSecurity http) throws Exception {

? ? ? ? http

? ? ? ? ? ? .csrf().disable()

? ? ? ? ? ? .exceptionHandling()

? ? ? ? .and()

? ? ? ? ? ? .authorizeRequests()

? ? ? ? ? ? .anyRequest().authenticated();

? ? }

}

server:

? port: 9002

security:

? oauth2:

? ? client:

? ? ? client-id: client

? ? ? client-secret: secret

? ? ? access-token-uri: http://localhost:9000/auth/oauth/token

? ? ? user-authorization-uri: http://localhost:9000/auth/oauth/authorize

? ? resource:

? ? ? token-info-uri: http://localhost:9000/auth/oauth/check_token

說明:資源服務(wù)器主要用于資源攔截坞靶,需要獲取授權(quán)碼才能訪問

4)sso客戶端


 主要配置:SecurityConfiguration、application.yaml

/**

* 這里使用的是sso的方式蝴悉,可以用于單點(diǎn)登錄

* 構(gòu)造方式也很簡(jiǎn)單彰阴,主要是sso的配置

*/

@Configuration

@EnableOAuth2Sso

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

? ? @Override

? ? protected void configure(HttpSecurity http) throws Exception {

? ? ? ? http

? ? ? ? ? ? .csrf().disable()

? ? ? ? ? ? .authorizeRequests()

? ? ? ? ? ? .anyRequest().authenticated();

? ? }

}

server:

? port: 9001

security:

? oauth2:

? ? client:

? ? ? client-id: client

? ? ? client-secret: secret

? ? ? access-token-uri: http://localhost:9000/auth/oauth/token

? ? ? user-authorization-uri: http://localhost:9000/auth/oauth/authorize

? ? resource:

? ? ? token-info-uri: http://localhost:9000/auth/oauth/check_token

? ? ? #user-info-uri: http://localhost:9002/user/me

? ? ? #這里兩種獲取用戶的方式,都可以拍冠。但是只能存在一種

5)客戶端:當(dāng)然瀏覽器可以為一種客戶端尿这,自己開發(fā)的應(yīng)用也可以為客戶端

  瀏覽器:

  a、獲取授權(quán)碼

oauth/authorize?response_type=code&client_id=&redirect_uri=

本文中:

http://localhost:9000/auth/oauth/authorize?response_type=code&client_id=client&redirect_uri=http://localhost:9002/loginresponse_type=code&client_id=client&redirect_uri=http://localhost:9002/login

b庆杜、通過code獲取令牌

oauth/token?client_id=&client_secret=&grant_type=authorization_code&redirect_uri=&code=

本文中:

http://localhost:9000/auth/oauth/token?client_id=client&client_secret=secret&grant_type=authorization_code&redirect_uri=http://localhost:9002/login&code=jrbBZS

獲取的對(duì)應(yīng)值

{

? ? "access_token": "06c1db9b-aac3-4a9a-acaf-56f5a5d0ea21",

? ? "token_type": "bearer",

? ? "refresh_token": "046d3fe7-52c4-43e5-902a-673ab2b0d3d4",

? ? "expires_in": 42981,

? ? "scope": "All"

}

access_token:表示訪問令牌射众,必選項(xiàng)。

token_type:表示令牌類型晃财,該值大小寫不敏感叨橱,必選項(xiàng),可以是bearer類型或mac類型拓劝。

expires_in:表示過期時(shí)間雏逾,單位為秒。如果省略該參數(shù)郑临,必須其他方式設(shè)置過期時(shí)間。

refresh_token:表示更新令牌屑宠,用來獲取下一次的訪問令牌厢洞,可選項(xiàng)。

scope:表示權(quán)限范圍,如果與客戶端申請(qǐng)的范圍一致躺翻,此項(xiàng)可省略丧叽。

c、更新令牌

oauth/token?grant_type=refresh_token&refresh_token=

http://localhost:9000/auth/oauth/token?grant_type=refresh_token&refresh_token=046d3fe7-52c4-43e5-902a-673ab2b0d3d4

注意:在使用refresh_token刷新令牌的時(shí)候公你,需要在認(rèn)證服務(wù)器上面設(shè)置


SecurityConfiguration加入U(xiǎn)serDetailsService?

@Bean

? ? @Override

? ? protected UserDetailsService userDetailsService() {

? ? ? ? returnsuper.userDetailsService();

? ? }

AuthServerConfiguration也加入U(xiǎn)serDetailsService?

@Autowired

? ? private UserDetailsService userDetailsService;

? ? @Override

? ? public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

? ? ? ? //認(rèn)證體系使用security的方式

? ? ? ? endpoints.authenticationManager(authenticationManager);

? ? ? ? endpoints.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);

? ? ? ? endpoints.userDetailsService(userDetailsService);

? ? }

單點(diǎn)登陸

//獲取用戶信息踊淳,說明這里主要目的就是通過資源服務(wù)器去獲取用戶信息

? ? ? ? ? ? Map principal = HttpUtils.doGet(resourceServerProperties.getUserInfoUri() + "?access_token=" + map.get("access_token"), Map.class);

? ? ? ? ? ? //這里通過本地登錄單點(diǎn)登錄

? ? ? ? ? ? String username = principal.get("name").toString();

? ? ? ? ? ? //如果用戶存在則不添加,這里如果生產(chǎn)應(yīng)用中陕靠,可以更具規(guī)則修改

? ? ? ? ? ? if (userRepository.findByUsername(username) == null) {

? ? ? ? ? ? ? ? Role role = roleRepository.findByRoleType(Role.RoleType.USER);

? ? ? ? ? ? ? ? User newUser = new User();

? ? ? ? ? ? ? ? newUser.setUsername(username);

? ? ? ? ? ? ? ? newUser.setPassword(passwordEncoder.encode(username));

? ? ? ? ? ? ? ? newUser.getRoles().add(role);

? ? ? ? ? ? ? ? userRepository.save(newUser);

? ? ? ? ? ? }

? ? ? ? ? ? //這里通過本地登錄的方式來獲取會(huì)話

? ? ? ? ? ? HttpHeaders httpHeaders = new HttpHeaders();

? ? ? ? ? ? httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

? ? ? ? ? ? LinkedMultiValueMap<String, Object> params = new LinkedMultiValueMap<>();

? ? ? ? ? ? params.add("username", username);

? ? ? ? ? ? params.add("password", username);

? ? ? ? ? ? HttpEntity<LinkedMultiValueMap<String, ? extends Object>> httpEntity = new HttpEntity(params, httpHeaders);

? ? ? ? ? ? String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/login";

? ? ? ? ? ? ResponseEntity<Object> exchange = restTemplate.exchange(url, HttpMethod.POST, httpEntity, Object.class);

? ? ? ? ? ? //將登錄后的header原本的給瀏覽器迂尝,這就是當(dāng)前瀏覽器的會(huì)話

? ? ? ? ? ? HttpHeaders headers = exchange.getHeaders();

? ? ? ? ? ? for (Map.Entry<String, List<String>> entry : headers.entrySet()) {

? ? ? ? ? ? ? ? entry.getValue().stream().forEach(value -> response.addHeader(entry.getKey(), value));

? ? ? ? ? ? }

? ? ? ? ? ? //這個(gè)狀態(tài)是根據(jù)security的返回?cái)?shù)據(jù)設(shè)定的

? ? ? ? ? ? response.setStatus(exchange.getStatusCode().value());

登錄的實(shí)現(xiàn)過程

@RestController

@RequestMapping("/authorize")

public class AuthorizedResource {

? ? @Autowired

? ? private AuthorizationCodeResourceDetails authorizationCodeResourceDetails;

? ? @Autowired

? ? private ResourceServerProperties resourceServerProperties;

? ? @Autowired

? ? private RestTemplate restTemplate;

? ? @Autowired

? ? private BCryptPasswordEncoder passwordEncoder;

? ? @Autowired

? ? private UserRepository userRepository;

? ? @Autowired

? ? private RoleRepository roleRepository;

? ? @RequestMapping("/login")

? ? public void login(String code, HttpServletRequest request, HttpServletResponse response) throws Exception {

? ? ? ? if (!StringUtils.isEmpty(code)) {

? ? ? ? ? ? LinkedMultiValueMap<String, Object> valueMap = new LinkedMultiValueMap<>();

? ? ? ? ? ? valueMap.add("client_id", authorizationCodeResourceDetails.getClientId());

? ? ? ? ? ? valueMap.add("client_secret", authorizationCodeResourceDetails.getClientSecret());

? ? ? ? ? ? valueMap.add("grant_type", authorizationCodeResourceDetails.getGrantType());

? ? ? ? ? ? valueMap.add("redirect_uri", authorizationCodeResourceDetails.getPreEstablishedRedirectUri());

? ? ? ? ? ? valueMap.add("code", code);

? ? ? ? ? ? Map<String, String> map = HttpUtils.doFrom(authorizationCodeResourceDetails.getAccessTokenUri(), valueMap, Map.class);

? ? ? ? ? ? System.out.println(map);

? ? ? ? ? ? //獲取用戶信息,說明這里主要目的就是通過資源服務(wù)器去獲取用戶信息

? ? ? ? ? ? Map principal = HttpUtils.doGet(resourceServerProperties.getUserInfoUri() + "?access_token=" + map.get("access_token"), Map.class);

? ? ? ? ? ? //這里通過本地登錄單點(diǎn)登錄

? ? ? ? ? ? String username = principal.get("name").toString();

? ? ? ? ? ? //如果用戶存在則不添加剪芥,這里如果生產(chǎn)應(yīng)用中垄开,可以更具規(guī)則修改

? ? ? ? ? ? if (userRepository.findByUsername(username) == null) {

? ? ? ? ? ? ? ? Role role = roleRepository.findByRoleType(Role.RoleType.USER);

? ? ? ? ? ? ? ? User newUser = new User();

? ? ? ? ? ? ? ? newUser.setUsername(username);

? ? ? ? ? ? ? ? newUser.setPassword(passwordEncoder.encode(username));

? ? ? ? ? ? ? ? newUser.getRoles().add(role);

? ? ? ? ? ? ? ? userRepository.save(newUser);

? ? ? ? ? ? }

? ? ? ? ? ? //這里通過本地登錄的方式來獲取會(huì)話

? ? ? ? ? ? HttpHeaders httpHeaders = new HttpHeaders();

? ? ? ? ? ? httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

? ? ? ? ? ? LinkedMultiValueMap<String, Object> params = new LinkedMultiValueMap<>();

? ? ? ? ? ? params.add("username", username);

? ? ? ? ? ? params.add("password", username);

? ? ? ? ? ? HttpEntity<LinkedMultiValueMap<String, ? extends Object>> httpEntity = new HttpEntity(params, httpHeaders);

? ? ? ? ? ? String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/login";

? ? ? ? ? ? ResponseEntity<Object> exchange = restTemplate.exchange(url, HttpMethod.POST, httpEntity, Object.class);

? ? ? ? ? ? //將登錄后的header原本的給瀏覽器,這就是當(dāng)前瀏覽器的會(huì)話

? ? ? ? ? ? HttpHeaders headers = exchange.getHeaders();

? ? ? ? ? ? for (Map.Entry<String, List<String>> entry : headers.entrySet()) {

? ? ? ? ? ? ? ? entry.getValue().stream().forEach(value -> response.addHeader(entry.getKey(), value));

? ? ? ? ? ? }

? ? ? ? ? ? //這個(gè)狀態(tài)是根據(jù)security的返回?cái)?shù)據(jù)設(shè)定的

? ? ? ? ? ? response.setStatus(exchange.getStatusCode().value());

? ? ? ? }

? ? }

}

工程文件配置


application.yaml

server:

? port: 9003

? servlet:

? ? session:

? ? ? cookie:

? ? ? ? name: ACCESS_SESSION

security:

? oauth2:

? ? client:

? ? ? client-id: client

? ? ? client-secret: secret

? ? ? grant-type: authorization_code

? ? ? access-token-uri: http://localhost:9000/auth/oauth/token

? ? ? user-authorization-uri: http://localhost:9000/auth/oauth/authorize

? ? ? pre-established-redirect-uri: http://localhost:9003/authorize/login

? ? resource:

? ? ? user-info-uri: http://localhost:9002/user/me

? ? sso:

? ? ? login-path: /authorize/login

spring:

? datasource:

? ? driver-class-name: com.mysql.jdbc.Driver

? ? url: jdbc:mysql://127.0.0.1:3306/model?useUnicode=true&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true

? ? username: root

? ? password:

? jpa:

? ? hibernate:

? ? ? ddl-auto: update

? ? ? naming:

? ? ? ? physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy

? ? ? ? implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy

? ? show-sql: true

? ? database-platform: org.hibernate.dialect.MySQL5InnoDBDialect

? ? database: mysql

github:?https://github.com/lilin409546297/security-oauth2-sso

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末税肪,一起剝皮案震驚了整個(gè)濱河市溉躲,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌益兄,老刑警劉巖锻梳,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異净捅,居然都是意外死亡疑枯,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門灸叼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來神汹,“玉大人,你說我怎么就攤上這事古今∑ㄎ海” “怎么了?”我有些...
    開封第一講書人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵捉腥,是天一觀的道長(zhǎng)氓拼。 經(jīng)常有香客問我,道長(zhǎng)抵碟,這世上最難降的妖魔是什么桃漾? 我笑而不...
    開封第一講書人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮拟逮,結(jié)果婚禮上撬统,老公的妹妹穿的比我還像新娘。我一直安慰自己敦迄,他們只是感情好恋追,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開白布凭迹。 她就那樣靜靜地躺著,像睡著了一般苦囱。 火紅的嫁衣襯著肌膚如雪嗅绸。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,698評(píng)論 1 305
  • 那天撕彤,我揣著相機(jī)與錄音鱼鸠,去河邊找鬼。 笑死羹铅,一個(gè)胖子當(dāng)著我的面吹牛蚀狰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播睦裳,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼造锅,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了廉邑?” 一聲冷哼從身側(cè)響起哥蔚,我...
    開封第一講書人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蛛蒙,沒想到半個(gè)月后糙箍,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡牵祟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年深夯,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诺苹。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡咕晋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出收奔,到底是詐尸還是另有隱情掌呜,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布坪哄,位于F島的核電站质蕉,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏翩肌。R本人自食惡果不足惜模暗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望念祭。 院中可真熱鬧兑宇,春花似錦、人聲如沸粱坤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽比规。三九已至若厚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蜒什,已是汗流浹背测秸。 一陣腳步聲響...
    開封第一講書人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留灾常,地道東北人霎冯。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像钞瀑,于是被迫代替她去往敵國和親沈撞。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容