Spring Security OAuth2 Demo —— 隐式授权模式(Implicit)
本文可以轉(zhuǎn)載,但請(qǐng)注明出處https://www.cnblogs.com/hellxz/p/oauth2_impilit_pattern.html
寫(xiě)在前面
在文章OAuth 2.0 概念及授權(quán)流程梳理 中我們談到OAuth 2.0的概念與流程,上一篇文章Spring Security OAuth2 Demo —— 授權(quán)碼模式簡(jiǎn)單演示了OAuth2的授權(quán)碼模式流程,本文繼續(xù)整理隱式授權(quán)模式相關(guān)內(nèi)容
寫(xiě)文不易,如有錯(cuò)誤,請(qǐng)?jiān)谠u(píng)論區(qū)指出,謝謝合作
本文目標(biāo)
使用相對(duì)簡(jiǎn)易的代碼演示隱式授權(quán)模式的流程,讓其流程更加清晰易懂
隱式授權(quán)模式流程回顧
隱式授權(quán)模式要求:用戶登錄并對(duì)第三方應(yīng)用進(jìn)行授權(quán),直接返回訪問(wèn)token,通過(guò)token訪問(wèn)資源
相比授權(quán)碼模式,它少了一次授權(quán)碼的頒發(fā)與客戶端使用授權(quán)碼換取token的過(guò)程
隱式授權(quán)模式適用場(chǎng)景
適用場(chǎng)景有以下幾個(gè)條件:
用戶參與:使用隱式授權(quán)需要與用戶交互,用戶對(duì)授權(quán)服務(wù)器進(jìn)行登錄與授權(quán)
單頁(yè)應(yīng)用:SPA前端,沒(méi)有后端或者后端屬于授權(quán)方
客戶端密碼:訪問(wèn)授權(quán)時(shí),不需要帶第三方應(yīng)用secret,前提是資源服務(wù)校驗(yàn)token使用的client信息與客戶端(第三方應(yīng)用)不同,且配置了secret
前端:必須要有前端,否則無(wú)法使用授權(quán)功能
客戶端后端:Options,僅當(dāng)應(yīng)用前后端不分離MVC場(chǎng)景
資源所屬方:授權(quán)方
Demo結(jié)構(gòu)
主要還是兩個(gè)角色,授權(quán)服務(wù)器與資源服務(wù)器兩個(gè)模塊,另外與其他幾個(gè)demo一樣,在父項(xiàng)目中包含一個(gè)說(shuō)明文檔
本文以及后續(xù)文章的demo均放在GitHub上,歡迎大家Star & Fork,源碼地址:https://github.com/hellxz/spring-security-oauth2-learn
Maven依賴
<!--Spring Security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--Spring Boot Starter Web 所有demo均使用web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Spring Security OAuth2 -->
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>${spring-security-oauth2.version}</version>
</dependency>
搭建授權(quán)服務(wù)器
項(xiàng)目啟動(dòng)類不多說(shuō),直接貼代碼,講講主要內(nèi)容
先說(shuō)下SecurityConfig
package com.github.hellxz.oauth2.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.util.Collections;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// @formatter: off
auth.inMemoryAuthentication()
.withUser("hellxz")
.password(passwordEncoder().encode("xyz"))
.authorities(Collections.emptyList());
// @formatter: on
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().authenticated() //所有請(qǐng)求都需要通過(guò)認(rèn)證
.and()
.httpBasic() //Basic提交
.and()
.csrf().disable(); //關(guān)跨域保護(hù)
}
}
參考了上文的話,這里基本上沒(méi)有什么變化,除了開(kāi)啟web安全外,重寫(xiě)了認(rèn)證管理器的用戶提供部分、簡(jiǎn)單配置了所有資源都需要認(rèn)證
授權(quán)服務(wù)主要配置AuthorizationConfig
package com.github.hellxz.oauth2.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
//授權(quán)服務(wù)器配置
@Configuration
@EnableAuthorizationServer //開(kāi)啟授權(quán)服務(wù)
public class AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
//允許表單提交
security.allowFormAuthenticationForClients()
.checkTokenAccess("permitAll()"); //參數(shù)與security訪問(wèn)控制一致
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// @formatter: off
clients.inMemory()
.withClient("client-a") //client端唯一標(biāo)識(shí)
.authorizedGrantTypes("implicit") //授權(quán)模式標(biāo)識(shí)
.accessTokenValiditySeconds(120) //訪問(wèn)令牌的有效期,這里設(shè)置120s
.scopes("read_user_info") //作用域
.resourceIds("resource1") //資源id
.redirectUris("http://localhost:9001/callback") //回調(diào)地址
.and()
.withClient("resource-server") //資源服務(wù)器校驗(yàn)token時(shí)用的客戶端信息,僅需要client_id與密碼
.secret(passwordEncoder.encode("test"));
// @formatter: on
}
}
因?yàn)樽顝?fù)雜的授權(quán)碼已經(jīng)有講過(guò)了,這里簡(jiǎn)單說(shuō)下,授權(quán)配置除了開(kāi)啟授權(quán)服務(wù)器,并重寫(xiě)認(rèn)證服務(wù)器安全配置(接收客戶端提交請(qǐng)求部分)允許客戶端進(jìn)行表單提交;另外配置了一個(gè)客戶端的信息,包含其標(biāo)識(shí)id、授權(quán)模式標(biāo)識(shí)、令牌有效期、回調(diào)地址這幾個(gè)必要的配置;
為了更清晰地區(qū)分第三方應(yīng)用的客戶端與資源服務(wù)器的客戶端,這里額外配置了資源服務(wù)的客戶端信息
測(cè)試授權(quán)服務(wù)器
獲取token
瀏覽器訪問(wèn)地址:http://localhost:8080/oauth/authorize?client_id=client-a&redirect_uri=http://localhost:9001/callback&response_type=token&scope=read_user_info
請(qǐng)求參數(shù)列表:
client_id=客戶端id
redirect_uri=回調(diào)url 一定要與授權(quán)服務(wù)器配置保持一致,否則得不到授權(quán)碼
response_type=token 簡(jiǎn)化模式必須是token
scope=作用域 與授權(quán)服務(wù)器配置保持一致
state=自定義串(可選)
返回響應(yīng)會(huì)回調(diào)我們之前輸入的回調(diào)地址,包含access_token和token類型及過(guò)期時(shí)間
搭建資源服務(wù)器
資源服務(wù)器也不復(fù)雜,一個(gè)資源服務(wù)器配置類,一個(gè)controller、一個(gè)vo,還有啟動(dòng)類(這里就不貼了,詳見(jiàn)源碼)
ResourceController主要接收用戶傳來(lái)的用戶名,返回一個(gè)json串,這里用標(biāo)準(zhǔn)錯(cuò)誤輸出高亮了下登錄用戶信息
package com.github.hellxz.oauth2.web.controller;
import com.github.hellxz.oauth2.web.vo.UserVO;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ResourceController {
@GetMapping("/user/{username}")
public UserVO user(@PathVariable String username){
System.err.println(SecurityContextHolder.getContext().getAuthentication());
return new UserVO(username, username + "@foxmail.com");
}
}
UserVO
package com.github.hellxz.oauth2.web.vo;
public class UserVO {
private String username;
private String email;
public UserVO(String username, String email) {
this.username = username;
this.email = email;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
資源服務(wù)器配置類ResourceConfig
package com.github.hellxz.oauth2.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.RemoteTokenServices;
@Configuration
@EnableResourceServer
public class ResourceConfig extends ResourceServerConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Primary
@Bean
public RemoteTokenServices remoteTokenServices() {
final RemoteTokenServices tokenServices = new RemoteTokenServices();
tokenServices.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token");
//這里的clientId和secret對(duì)應(yīng)資源服務(wù)器信息,授權(quán)服務(wù)器處需要配置
tokenServices.setClientId("resource-server");
tokenServices.setClientSecret("test");
return tokenServices;
}
@Override
public void configure(HttpSecurity http) throws Exception {
//設(shè)置創(chuàng)建session策略
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
//@formatter:off
//所有請(qǐng)求必須授權(quán)
http.authorizeRequests()
.anyRequest().authenticated();
//@formatter:on
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId("resource1").stateless(true);
}
}
資源服務(wù)器相對(duì)授權(quán)服務(wù)器更簡(jiǎn)單,僅需要開(kāi)啟EnableResourceServer,實(shí)現(xiàn)HttpSecurity配置、ResourceServerSecurityConfigurer配置 和 校驗(yàn)token的配置,這里使用遠(yuǎn)程調(diào)用授權(quán)服務(wù)器的做法;
需要注意的是區(qū)分資源服務(wù)器client信息和第三方應(yīng)用客戶端信息,之前這里有些模糊,直到著此文時(shí)方才發(fā)現(xiàn)這兩者應(yīng)區(qū)分(隱式授權(quán)可以不用密碼啊,如果第三方應(yīng)用等于資源服務(wù)器client,在不設(shè)置client_secret情況下,會(huì)校驗(yàn)失敗,無(wú)法訪問(wèn)資源)
一般而言,校驗(yàn)token的配置如果是資源服務(wù)器自己校驗(yàn),則需要在
configure(ResourceServerSecurityConfigurer resources)這個(gè)方法中添加token存儲(chǔ)(tokenStore)的位置等信息
使用token訪問(wèn)資源
結(jié)束
最近比較忙,抽時(shí)間整理代碼時(shí)發(fā)現(xiàn):我對(duì)OAuth2的資源服務(wù)器與授權(quán)服務(wù)器的client配置有些模糊,現(xiàn)在已經(jīng)清晰多了,并且及時(shí)修改了demo。如果本文對(duì)你有幫助,歡迎點(diǎn)推薦,Github點(diǎn)Star :happy:
OAuth2系列demo倉(cāng)庫(kù)地址:https://github.com/hellxz/spring-security-oauth2-learn
紙上得來(lái)終覺(jué)淺,覺(jué)知此事要躬行。愿大家共勉
本文可以轉(zhuǎn)載,但請(qǐng)注明出處https://www.cnblogs.com/hellxz/p/oauth2_impilit_pattern.html
總結(jié)
以上是生活随笔為你收集整理的Spring Security OAuth2 Demo —— 隐式授权模式(Implicit)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: PREPARE
- 下一篇: SEO工具,站长必备