最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot 如何使用 JWT 保護(hù) Rest Api 接口

 更新時(shí)間:2024年02月23日 14:55:21   作者:nihui123  
使用spring-boot開發(fā)RESTful API非常的方便,在生產(chǎn)環(huán)境中,對(duì)發(fā)布的 API 增加授權(quán)保護(hù)是非常必要的,現(xiàn)在我們來看如何利用JWT技術(shù)為API 增加授權(quán)保護(hù),保證只有獲得授權(quán)的用戶才能夠訪問 API,感興趣的朋友跟隨小編一起看看吧

用 spring-boot 開發(fā) RESTful API 非常的方便,在生產(chǎn)環(huán)境中,對(duì)發(fā)布的 API 增加授權(quán)保護(hù)是非常必要的?,F(xiàn)在我們來看如何利用 JWT 技術(shù)為 API 增加授權(quán)保護(hù),保證只有獲得授權(quán)的用戶才能夠訪問 API。

一、Jwt 介紹

  JSON Web Token (JWT)是一個(gè)開放標(biāo)準(zhǔn)(RFC 7519),它定義了一種緊湊的、自包含的方式,
用于作為 JSON 對(duì)象在各方之間安全地傳輸信息。該信息可以被驗(yàn)證和信任,因?yàn)樗菙?shù)字簽名的。
Jwt 主要應(yīng)用場(chǎng)景:授權(quán)
  Authorization (授權(quán)) : 這是使用 JWT 的最常見場(chǎng)景。一旦用戶登錄,后續(xù)每個(gè)請(qǐng)求都將包含 JWT,允許用戶訪問該令牌允許的路由、服務(wù)和資源。單點(diǎn)登錄是現(xiàn)在廣泛使用的 JWT 的
一個(gè)特性,因?yàn)樗拈_銷很小,并且可以輕松地跨域使用。
  在認(rèn)證的時(shí)候,當(dāng)用戶用他們的憑證成功登錄以后,一個(gè) JSON Web Token 將會(huì)被返回。此后,token 就是用戶憑證了。為什么不用 session:因?yàn)樽隽送耆那昂蠖朔蛛x,前段頁(yè)面每次發(fā)出 Ajax 請(qǐng)求都會(huì)建立一個(gè)新的回話請(qǐng)求,沒辦法通過 session 來記錄跟蹤用戶回話狀態(tài)。所以采用 JWT,來完成回話跟蹤、身份驗(yàn)證。Session 是在服務(wù)器端的,而 JWT 是在客戶端的。

JWT 使用流程:

  • 用戶攜帶用戶名和密碼請(qǐng)求訪問
  • 服務(wù)器校驗(yàn)用戶憑據(jù)
  • 應(yīng)用提供一個(gè) token 給客戶端
  • 客戶端存儲(chǔ) token,并且在隨后的每一次請(qǐng)求中都帶著它
  • 服務(wù)器校驗(yàn) token 并返回?cái)?shù)據(jù)

二、搭建基礎(chǔ) SpringBoot 工程

2.1、新建一個(gè) SpringBoot 工程,引入所需依賴包

<dependency> 
	<groupId>org.springframework.boot</groupId> 
	<artifactId>spring-boot-starter-web</artifactId> 
</dependency> 

2.2、編寫測(cè)試 Controller HelloController

package com.offcn.controller; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.RestController; 
@RestController 
public class HelloController { 
	@RequestMapping("/hello") 
	public String hello(){ 
		return "hello"; 
	} 
}

2.3、編寫應(yīng)用主啟動(dòng)類

package com.offcn; 
import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 
import org.springframework.context.annotation.Bean; 
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; 
@SpringBootApplication 
public class SpringbootSecurityJwtApplication {
public static void main(String[] args) { 
	SpringApplication.run(SpringbootSecurityJwtApplication.class, args); 
	} 
}

2.4、測(cè)試應(yīng)用

  訪問地址:http://localhost:8080/hello
  至此,我們的接口就開發(fā)完成了。但是這個(gè)接口沒有任何授權(quán)防護(hù),任何人都可以訪問,這
樣是不安全的,下面我們開始加入授權(quán)機(jī)制。

三、增加用戶注冊(cè)功能

3.1、導(dǎo)入數(shù)據(jù)庫(kù)所需依賴包

<!-- spring-data-jpa --> 
<dependency> 
	<groupId>org.springframework.boot</groupId> 
	<artifactId>spring-boot-starter-data-jpa</artifactId> 
</dependency> 
<!-- mysql --> 
<dependency> 
	<groupId>mysql</groupId> 
	<artifactId>mysql-connector-java</artifactId> 
<version>5.1.30</version> 
</dependency> 
<dependency> 
	<groupId>org.projectlombok</groupId> 
	<artifactId>lombok</artifactId> 
</dependency>

3.2、修改配置文件 application.yml 配置數(shù)據(jù)庫(kù)連接

spring: 
	datasource: 
	url: jdbc:mysql://localhost:3306/springboot-security?serverTimezone=GMT%2B8 
	username: root 
	password: 123 
	driver-class-name: com.mysql.jdbc.Driver 
	jpa:
		hibernate: 
		ddl-auto: update 
		show-sql: true 
	application: 
		name: demo1 
		#配置應(yīng)用名稱 

3.3、新建一個(gè)實(shí)體類 User

@Entity 
@Table(name = "tb_user") 
@Data 
@NoArgsConstructor 
@AllArgsConstructor 
public class User { 
@Id 
@GeneratedValue 
	private  Long id; 
	private String username; 
	private String password; 
}

3.4、新建一個(gè) dao 實(shí)現(xiàn) JpaRepository 接口

package com.offcn.dao; 
import com.offcn.po.User; 
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserDao extends JpaRepository<User,Long> { 
	User findByUsername(String username); 
}

3.5、新建 UserController 類中增加注冊(cè)方法,實(shí)現(xiàn)用戶注冊(cè)的接口

package com.offcn.controller; 
import com.offcn.dao.UserDao; 
import com.offcn.po.User; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.stereotype.Controller; 
import org.springframework.web.bind.annotation.PostMapping; 
import org.springframework.web.bind.annotation.RequestBody; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.ResponseBody; 
@Controller 
@RequestMapping("/users") 
public class UserController { 
	@Autowired 
	private UserDao userDao; 
	/**
	* 
	該方法是注冊(cè)用戶的方法,默認(rèn)放開訪問控制 
	* 
	@param user 
	*/
	@PostMapping("/signup") 
	@ResponseBody 
	public String signUp(@RequestBody User user) { 
		user.setPassword(user.getPassword()); 
		try {
			userDao.save(user); 
			return "success"; 
		} catch (Exception e) { 
			e.printStackTrace(); 
			return "error";
		} 
	} 
}

3.6 測(cè)試用戶注冊(cè)

  請(qǐng)求地址:http://localhost:8080/users/signup

四、添加 JWT 認(rèn)證

  用戶填入用戶名密碼后,與數(shù)據(jù)庫(kù)里存儲(chǔ)的用戶信息進(jìn)行比對(duì),如果通過,則認(rèn)證成功。傳統(tǒng)的方法是在認(rèn)證通過后,創(chuàng)建 sesstion,并給客戶端返回 cookie?,F(xiàn)在我們采用 JWT 來處理用戶名密碼的認(rèn)證。區(qū)別在于,認(rèn)證通過后,服務(wù)器生成一個(gè) token,將 token 返回給客戶端,客戶端以后的所有請(qǐng)求都需要在 http 頭中指定該 token。服務(wù)器接收的請(qǐng)求后,會(huì)對(duì)
token 的合法性進(jìn)行驗(yàn)證。驗(yàn)證的內(nèi)容包括:內(nèi)容是一個(gè)正確的 JWT 格式 、檢查簽名 、檢查 claims 、檢查權(quán)限。

4.1、導(dǎo)入 JWT 及 SpringSecurity 所需依賴包

<dependency> 
	<groupId>org.springframework.boot</groupId> 
	<artifactId>spring-boot-starter-security</artifactId> 
</dependency> 
<dependency> 
	<groupId>io.jsonwebtoken</groupId> 
	<artifactId>jjwt</artifactId> 
	<version>0.7.0</version> 
</dependency> 

4.2、編寫登錄處理過濾器類 JWTLoginFilter

核心功能是在驗(yàn)證用戶名密碼正確后,生成一個(gè) token,并將 token 返回給客戶端 該類繼承自 UsernamePasswordAuthenticationFilter,重寫了其中的 2 個(gè)方法:

  • attemptAuthentication :接收并解析用戶憑證。
  • successfulAuthentication :用戶成功登錄后,這個(gè)方法會(huì)被調(diào)用,我們?cè)谶@個(gè)方法里生成 token。
/**
* 驗(yàn)證用戶名密碼正確后,生成一個(gè) token,并將 token 返回給客戶端
* 
該類繼承自 UsernamePasswordAuthenticationFilter,重寫了其中的 2 個(gè)方法 
* 
attemptAuthentication :接收并解析用戶憑證。 
* successfulAuthentication :用戶成功登錄后,這個(gè)方法會(huì)被調(diào)用,我們?cè)谶@個(gè)方法里生成 
token。 
*
*/
public class JWTLoginFilter extends UsernamePasswordAuthenticationFilter 
{ 
	private AuthenticationManager authenticationManager; 
	public JWTLoginFilter(AuthenticationManager authenticationManager) { 
		this.authenticationManager = authenticationManager; 
	}
	// 接收并解析用戶憑證 
	@Override 
	public Authentication attemptAuthentication(HttpServletRequest req, HttpServletResponse res) throws AuthenticationException { 
	try {
		User user = new ObjectMapper() .readValue(req.getInputStream(), User.class); 
		return authenticationManager.authenticate( 
		new UsernamePasswordAuthenticationToken( 
			user.getUsername(), 
			user.getPassword(), 
			new ArrayList<>()) 
		); 
	} catch (IOException e) { 
		throw new RuntimeException(e); 
	} 
}
// 用戶成功登錄后,這個(gè)方法會(huì)被調(diào)用,我們?cè)谶@個(gè)方法里生成 token 
@Override 
protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain, Authentication auth) throws IOException, ServletException {
	String token = Jwts.builder() 
	.setSubject(((org.springframework.security.core.userdetails.User) 
	auth.getPrincipal()).getUsername()) 
	.setExpiration(new Date(System.currentTimeMillis() + 60 * 60 * 24 * 
	1000)) 
	.signWith(SignatureAlgorithm.HS512, "MyJwtSecret") 
	.compact(); 
	res.addHeader("Authorization", "Bearer " + token); 
	} 
}

4.3、編寫 Token 校驗(yàn)過濾器類 JWTAuthenticationFilter

用戶一旦登錄成功后,會(huì)拿到 token,后續(xù)的請(qǐng)求都會(huì)帶著這個(gè) token,服務(wù)端會(huì)驗(yàn)證 token的合法性。該類繼承自 BasicAuthenticationFilter,在 doFilterInternal 方法中,從 http 頭的 Authorization 項(xiàng)讀取 token 數(shù)據(jù),然后用 Jwts 包提供的方法校驗(yàn) token 的合法性。如果校驗(yàn)通過,就認(rèn)為這是一個(gè)取得授權(quán)的合法請(qǐng)求。

/**
* 
token 的校驗(yàn) 
* 
該類繼承自 BasicAuthenticationFilter,在 doFilterInternal 方法中, 
* 
從 http 頭的 Authorization 項(xiàng)讀取 token 數(shù)據(jù),然后用 Jwts 包提供的方法校驗(yàn) token 的合 
法性。
* 如果校驗(yàn)通過,就認(rèn)為這是一個(gè)取得授權(quán)的合法請(qǐng)求 
*
*/
public class JWTAuthenticationFilter extends BasicAuthenticationFilter { 
	public JWTAuthenticationFilter(AuthenticationManager authenticationManager) { 
		super(authenticationManager); 
	}
	@Override 
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain 
chain) throws IOException, ServletException { 
		String header = request.getHeader("Authorization");
		if (header == null || !header.startsWith("Bearer ")) { 
			chain.doFilter(request, response); 
		return; 
		}
		UsernamePasswordAuthenticationToken authentication = 
		getAuthentication(request); 
		SecurityContextHolder.getContext().setAuthentication(authentication); 
		chain.doFilter(request, response); 
	}
	private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
		String token = request.getHeader("Authorization"); 
		if (token != null) { 
		// parse 
			the token. 
			String user = Jwts.parser() 
			.setSigningKey("MyJwtSecret") 
			.parseClaimsJws(token.replace("Bearer ", "")) 
			.getBody() 
			.getSubject(); 
		if (user != null) { 
		return new UsernamePasswordAuthenticationToken(user, null, new 
			ArrayList<>()); 
			}
	return null; 
	}
	return null; 
	} 
}

五、SpringSecurity 配置集成 JWT 認(rèn)證

5.1、編寫 SpringSecurity 用戶及權(quán)限驗(yàn)證類UserDetailServiceImpl

@Service("userDetailServiceImpl") 
public class UserDetailServiceImpl implements UserDetailsService { 
@Autowired 
private UserDao userDao; 
@Override 
public UserDetails loadUserByUsername(String username) throws 
UsernameNotFoundException { 
//根據(jù)用戶名查詢用戶信息 
com.offcn.po.User user = userDao.findByUsername(username); 
//為用戶授權(quán)(暫時(shí)未驗(yàn)證權(quán)限) 
List<GrantedAuthority> grantedAuthorityList=new ArrayList<>(); 
grantedAuthorityList.add(new SimpleGrantedAuthority("ROLE_USER")); 
return new User(username,user.getPassword(),grantedAuthorityList); 
} 
}

5.2、修改程序主啟動(dòng)類,增加密碼加密生成器配置

@SpringBootApplication 
public class SpringbootSecurityJwtApplication { 
public static void main(String[] args) { 
SpringApplication.run(SpringbootSecurityJwtApplication.class, args); 
}
@Bean 
public BCryptPasswordEncoder bCryptPasswordEncoder() { 
return new BCryptPasswordEncoder(); 
} 
}

5.3、編寫 SpringSecurity 配置類 WebSecurityConfig

  通過 SpringSecurity 的配置,將上面的 JWT 過濾器類組合在一起。

/**
* 
SpringSecurity 的配置 
* 
通過 SpringSecurity 的配置,將 JWTLoginFilter,JWTAuthenticationFilter 組合在一起 
*
*/
@Configuration 
@Order(SecurityProperties.DEFAULT_FILTER_ORDER) 
public class WebSecurityConfig 
extends WebSecurityConfigurerAdapter { 
@Autowired 
private UserDetailsService 
userDetailServiceImpl; 
@Autowired 
private BCryptPasswordEncoder bCryptPasswordEncoder; 
@Override 
protected void configure(HttpSecurity http) throws Exception { 
http.cors().and().csrf().disable().authorizeRequests() 
.antMatchers(HttpMethod.POST, "/users/signup").permitAll() 
.anyRequest().authenticated() 
.and() 
.addFilter(new 
JWTLoginFilter(authenticationManager())) 
.addFilter(new 
JWTAuthenticationFilter(authenticationManager())); 
}
@Override 
public void configure(AuthenticationManagerBuilder auth) throws Exception { 
auth.userDetailsService(userDetailServiceImpl).passwordEncoder(bCryptPasswordEncod 
er);
} 
}

5.4、修改 UserController 類 增加注冊(cè)加密密碼

@Controller 
@RequestMapping("/users") 
public class UserController { 
@Autowired 
private BCryptPasswordEncoder bCryptPasswordEncoder; 
@Autowired 
private UserDao userDao; 
/**
* 
該方法是注冊(cè)用戶的方法,默認(rèn)放開訪問控制 
* 
@param user 
*/
@PostMapping("/signup") 
@ResponseBody 
public String signUp(@RequestBody User user) { 
user.setPassword(bCryptPasswordEncoder.encode(user.getPassword())); 
try {
userDao.save(user); 
return "success"; 
} catch (Exception e) { 
e.printStackTrace(); 
return "error"; 
} } }

六、測(cè)試 Token

6.1、測(cè)試請(qǐng)求 hello 接口

請(qǐng)求地址:http://localhost:8080/hello

6.2、重新注冊(cè)一個(gè)賬號(hào)

清空數(shù)據(jù)表
重新注冊(cè)一個(gè)賬號(hào):
請(qǐng)求地址:http://localhost:8080/users/signup

查看數(shù)據(jù)庫(kù)

6.3、測(cè)試登錄

請(qǐng)求地址:http://localhost:8080/login
發(fā) post 請(qǐng)求

響應(yīng)的請(qǐng)求頭 Authorization 的值就是 token
Bearer
eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ0ZXN0IiwiZXhwIjoxNTY1MjY0OTQxfQ.CW-QwtE1Q2
Z69NNUnH_wPIaJjJpTFnh8eR3z03ujw-hb3aMO61yuir6w-T0X0FdV9k2WQrj903J9VDz6ijPJt
Q

6.4、用登錄后的 token 再次請(qǐng)求 hello 接口

注意:在請(qǐng)求頭中攜帶 token
請(qǐng)求頭名稱:Authorization
攜帶對(duì)應(yīng)的 token 值。
可以看到正常響應(yīng)結(jié)果。

到此這篇關(guān)于SpringBoot 如何使用 JWT 保護(hù) Rest Api 接口的文章就介紹到這了,更多相關(guān)SpringBoot 使用 JWT 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解決hive啟動(dòng)時(shí)java.net.ConnectException:拒絕連接的問題

    解決hive啟動(dòng)時(shí)java.net.ConnectException:拒絕連接的問題

    Hadoop集群連接被拒,需檢查集群是否啟動(dòng)、關(guān)閉防火墻/SELinux、確認(rèn)安全模式退出,若問題仍存,查看日志報(bào)錯(cuò)處理
    2025-08-08
  • Java中的模板模式說明與實(shí)現(xiàn)

    Java中的模板模式說明與實(shí)現(xiàn)

    這篇文章主要介紹了Java中的模板模式說明與實(shí)現(xiàn),模板方法模式,又叫模板模式,在一個(gè)抽象類公開定義了執(zhí)行它的方法的模板,它的子類可以更需要重寫方法實(shí)現(xiàn),但可以成為典型類中定義的方式進(jìn)行,需要的朋友可以參考下
    2023-10-10
  • SpringBoot使用hutool操作FTP的詳細(xì)過程

    SpringBoot使用hutool操作FTP的詳細(xì)過程

    在使用SpringBoot結(jié)合hutool操作FTP時(shí),遇到防火墻導(dǎo)致上傳文件大小為0kb的問題,通過設(shè)置FTP為被動(dòng)模式解決,本文詳細(xì)解析了FTP的主動(dòng)模式和被動(dòng)模式的工作原理、安全性及適用場(chǎng)景,幫助理解FTP的連接方式和解決網(wǎng)絡(luò)限制問題
    2024-09-09
  • Java連接并操作Redis超詳細(xì)教程

    Java連接并操作Redis超詳細(xì)教程

    在分布式系統(tǒng)和高并發(fā)場(chǎng)景中,Redis?作為高性能內(nèi)存數(shù)據(jù)庫(kù)的地位舉足輕重,對(duì)于?Java?開發(fā)者而言,掌握?Redis?的連接與操作是進(jìn)階必備技能,本文從?Java?操作?Redis?的核心需求出發(fā),通過完整代碼示例與逐行解析,需要的朋友可以參考下
    2025-05-05
  • 在Java中解析JSON數(shù)據(jù)代碼示例及說明

    在Java中解析JSON數(shù)據(jù)代碼示例及說明

    這篇文章主要介紹了在Java中解析JSON數(shù)據(jù)的相關(guān)資料,文中講解了如何使用Gson和Jackson庫(kù)解析JSON數(shù)據(jù),并展示了如何將日期時(shí)間字符串轉(zhuǎn)換為時(shí)間戳,通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-03-03
  • Springboot整合zookeeper實(shí)現(xiàn)對(duì)節(jié)點(diǎn)的創(chuàng)建、監(jiān)聽與判斷的案例詳解

    Springboot整合zookeeper實(shí)現(xiàn)對(duì)節(jié)點(diǎn)的創(chuàng)建、監(jiān)聽與判斷的案例詳解

    這篇文章主要介紹了基于Springboot整合zookeeper實(shí)現(xiàn)對(duì)節(jié)點(diǎn)的創(chuàng)建、監(jiān)聽與判斷,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06
  • Springboot @Value獲取值為空問題解決方案

    Springboot @Value獲取值為空問題解決方案

    這篇文章主要介紹了Springboot @Value獲取值為空問題解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • 詳解spring boot starter redis配置文件

    詳解spring boot starter redis配置文件

    spring-boot-starter-Redis主要是通過配置RedisConnectionFactory中的相關(guān)參數(shù)去實(shí)現(xiàn)連接redis service。下面通過本文給大家介紹在spring boot的配置文件中redis的基本配置,需要的的朋友參考下
    2017-07-07
  • MyBatis動(dòng)態(tài)數(shù)據(jù)源切換的完整方案

    MyBatis動(dòng)態(tài)數(shù)據(jù)源切換的完整方案

    在微服務(wù)架構(gòu)和分布式系統(tǒng)中,動(dòng)態(tài)數(shù)據(jù)源是應(yīng)對(duì)多環(huán)境切換、讀寫分離、多租戶等復(fù)雜場(chǎng)景的核心工具,MyBatis 與 Spring 結(jié)合后,可以靈活實(shí)現(xiàn)數(shù)據(jù)源的動(dòng)態(tài)切換,以下是實(shí)現(xiàn) MyBatis 動(dòng)態(tài)數(shù)據(jù)源的完整方案,需要的朋友可以參考下
    2025-08-08
  • 深入了解Spring中的依賴注入DI

    深入了解Spring中的依賴注入DI

    這篇文章主要介紹了Spring?中的依賴注入,包括注入的方式,寫法,該選擇哪個(gè)注入方式以及可能出現(xiàn)的循環(huán)依賴問題等內(nèi)容,需要的可以參考一下
    2023-06-06

最新評(píng)論

陇西县| 淮北市| 花莲市| 南华县| 望谟县| 乐至县| 临夏市| 大埔区| 沙田区| 澳门| 青冈县| 江山市| 清流县| 临海市| 滁州市| 二连浩特市| 通化市| 库伦旗| 万荣县| 肇州县| 英超| 潞西市| 博湖县| 揭西县| 盘山县| 陇川县| 洞头县| 临夏市| 遂平县| 舞阳县| 金乡县| 云霄县| 马边| 元朗区| 日照市| 泰州市| 宣威市| 徐水县| 沂南县| 桂林市| 凤冈县|