JWT令牌的使用以及一些算法

Base64

编码 :字节数组(文本或其他格式)64个字符的表示形式

-解码 :

散列算法 

散列函数生成信息的摘要(数据的指纹。唯一标识),摘要信息长度固定

MD5,SHA-128,SHA-256

 数据完整性的校验,

秒传,先发散列值,判断服务器是否存在

散列值无法变成原始数据(不可逆


密码在数据库的存储,散列函数+盐

 不能找回密码,只能重置

 加密算法 

对称密钥(一个密钥)

非对称密钥(公钥,私钥)

 SSH ,HTTPS

JWT 

官网:https://jwt.io/

令牌是在用户验证通过后颁发给用户的身份标示,之后请求只需携带令牌,令牌中用户的标示,不存储敏感信息,

如何防止被伪造,追加签名???下面将以代码形式带你领略,分为三个模块,初级,中级,高级

初级

工程目录:


 pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>jwt2</groupId>
	<artifactId>jwt2</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<build>
		<sourceDirectory>src</sourceDirectory>
		<plugins>
			<plugin>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.8.0</version>
				<configuration>
					<release>13</release>
				</configuration>
			</plugin>
		</plugins>
	</build>

	<dependencies>

		<!-- JWT 的 java 实现 -->
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt-api</artifactId>
			<version>0.11.1</version>
		</dependency>
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt-impl</artifactId>
			<version>0.11.1</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt-jackson</artifactId>
			<version>0.11.1</version>
			<scope>runtime</scope>
		</dependency>

	</dependencies>

</project>

App.java

package jwt2;

import java.security.Key;
import java.util.Arrays;
import java.util.Base64;
import java.util.Date;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;

public class App {

	public static void main(String[] args) {
		
		// JWT 密钥长度不小于 256 位
		Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
		System.out.println(key.getAlgorithm());
//		System.out.println(key.getFormat());
//		System.out.println(key.toString());
		System.out.println(key.getEncoded().length * 8);
//		System.out.println(Arrays.toString(key.getEncoded()));
		
		// 密钥
		System.out.println(Base64.getEncoder().encodeToString(key.getEncoded()));
		
		// 负载数据
		Claims claims = Jwts.claims();
		claims.put("user", "king");
		claims.put("role", "admin");
		claims.put("roles", new String[] {"admin", "test", "user"});
		
		// 生成了一个 JWT 令牌(未签名)
		String token = Jwts.builder()
				.setSubject("demo")
				.setIssuer("newer")
				.setAudience("you")
				.setIssuedAt(new Date())
				.setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60))
				.addClaims(claims)	// 自定义数据
				.signWith(key)
				.compact();// 压缩
		// header.payload
		System.out.println(token);
		
		// 收到客户端请求,从请求头获得令牌解析令牌中的信息
		Claims c = Jwts.parserBuilder()
				.setSigningKey(key)
				.build()
				.parseClaimsJws(token)
				.getBody();
		
		System.out.println(c);
	}
}

运行程序,控制台输出:


 中级

工程目录:


pom.xml(依赖)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.5.RELEASE</version>
        <relativePath/>
    </parent>
    <groupId>com.newer</groupId>
    <artifactId>jwt</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>jwt</name>

    <properties>
        <java.version>13</java.version>
    </properties>

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

        <!--JWT-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-api</artifactId>
            <version>0.10.7</version>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-impl</artifactId>
            <version>0.10.7</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt-jackson</artifactId>
            <version>0.10.7</version>
            <scope>runtime</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

application.yml(配置信息)

jwt:
  secret: OhtVGp0YixAH5+NnruPpXY/yU2E22uYNk4rwZDOAEvQ=

JwtApplication.java

package com.newer.jwt;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class JwtApplication {

    public static void main(String[] args) {
        SpringApplication.run(JwtApplication.class, args);
    }

}

JWTController.java

package com.newer.jwt.controller;

import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import io.jsonwebtoken.security.SignatureException;
import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@RestController
public class JWTController {

	// 读取配置文件中的值,Spring EL
	@Value("${jwt.secret}")
	String base64Key;

	/**
	 * 生一个Token
	 *
	 * @return String token
	 */
	@PostMapping("/login")
	public String login(@RequestParam(name = "user", defaultValue = "alice") String user,
			@RequestParam(name = "info", defaultValue = "负载信息") String info) {

		Map<String, Object> claims = new HashMap<>();
		claims.put("user", user);
		claims.put("info", info);

		Date nowDate = new Date();

		// 建造者模式(创建对象的设计模式)
		// 生成 JWT 令牌
		return Jwts.builder()
				.setClaims(claims)
				.setSubject("jwt")
				.setIssuedAt(nowDate) // 令牌生成时间
				.setExpiration(new Date(nowDate.getTime() + 1000 * 60 * 5)) // 令牌的有效期
				.signWith(getSecretKey()) // 使用了密钥
				.compact(); // 压缩
	}

	/**
	 * 解码一个Token
	 */
	@PostMapping("/dec")
	public String decode(@RequestParam(name = "jwt") String jwt) {
		try {
			// 令牌解码
			Claims claims = Jwts.parser().setSigningKey(getSecretKey()).parseClaimsJws(jwt).getBody();

			return claims.toString();

		} catch (ExpiredJwtException e) {
			return "Token已过期";
		} catch (UnsupportedJwtException e) {
			e.printStackTrace();
		} catch (MalformedJwtException e) {
			e.printStackTrace();
		} catch (SignatureException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		}

		return "未知的异常";
	}

	/**
	 * 随机生成一个base64的key
	 *
	 * @return String base64Key
	 */
	@GetMapping("/key")
	public String generateKey() {
		// 生成一个 HS256 算法的密钥
		Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);

		// 用 Base64 把密钥编码成 字符串
		return Base64.encodeBase64String(key.getEncoded());
	}

	/**
	 * 从配置文件中获取加密key,并构造SecretKey对象返回
	 * 
	 * @return SecretKey
	 */
	private SecretKey getSecretKey() {
		return new SecretKeySpec(Base64.decodeBase64(base64Key), "HmacSHA256");
	}
}

程序运行,浏览器打开

同时可以通过postman去测试/login以及/dec ,在此就不做演示。


 高级

工程目录:


pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.1.1.RELEASE</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>es.softtek</groupId>
	<artifactId>jwtDemo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>jwtDemo</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>11</java.version>
	</properties>

	<dependencies>

		<!-- Spring Security -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>
		
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>

		<!-- JSON WEB TOKEN -->
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt-api</artifactId>
			<version>0.11.1</version>
		</dependency>
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt-impl</artifactId>
			<version>0.11.1</version>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>io.jsonwebtoken</groupId>
			<artifactId>jjwt-jackson</artifactId>
			<version>0.11.1</version>
			<scope>runtime</scope>
		</dependency>

	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

application.properties

spring.http.log-request-details=true
logging.level.web=debug

jwt.secret=V1beFinb07YUJuAjdBevbvCqv9FNqyw4KhM5bMKxCyU=

User.java

package es.softtek.jwtDemo.dto;

public class User {

	private String user;
	private String pwd;
	private String token;

	public String getUser() {
		return user;
	}

	public void setUser(String user) {
		this.user = user;
	}

	public String getPwd() {
		return pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	public String getToken() {
		return token;
	}

	public void setToken(String token) {
		this.token = token;
	}

}

JwtDemoApplication.java

package es.softtek.jwtDemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class JwtDemoApplication {

	public static void main(String[] args) {
		SpringApplication.run(JwtDemoApplication.class, args);
	}

}

JWTAuthorizationFilter.java

package es.softtek.jwtDemo.security;

import java.io.IOException;
import java.util.List;
import java.util.stream.Collectors;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.MalformedJwtException;
import io.jsonwebtoken.UnsupportedJwtException;

/**
 * 基于 JWT 用户认证的过滤器
 * 
 * @author wtao
 *
 */
public class JWTAuthorizationFilter extends OncePerRequestFilter {

	private final String HEADER = "Authorization";
	private final String PREFIX = "Bearer ";

	String base64Key = "V1beFinb07YUJuAjdBevbvCqv9FNqyw4KhM5bMKxCyU=";

	@Override
	protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
			throws ServletException, IOException {
		try {
			if (checkJWTToken(request, response)) {
				Claims claims = validateToken(request);
				if (claims.get("authorities") != null) {
					setUpSpringAuthentication(claims);
				} else {
					SecurityContextHolder.clearContext();
				}
			}
			chain.doFilter(request, response);
		} catch (ExpiredJwtException | UnsupportedJwtException | MalformedJwtException e) {
			response.setStatus(HttpServletResponse.SC_FORBIDDEN);
			((HttpServletResponse) response).sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
			return;
		}
	}

	private Claims validateToken(HttpServletRequest request) {
		String jwtToken = request.getHeader(HEADER).replace(PREFIX, "");
		return Jwts.parser().setSigningKey(getSecretKey()).parseClaimsJws(jwtToken).getBody();
	}

	private SecretKey getSecretKey() {
		return new SecretKeySpec(Base64.decodeBase64(base64Key), "HmacSHA256");
	}

	/**
	 * Authentication method in Spring flow
	 * 
	 * @param claims
	 */
	private void setUpSpringAuthentication(Claims claims) {
		@SuppressWarnings("unchecked")
		List<String> authorities = (List<String>) claims.get("authorities");

		UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(claims.getSubject(), null,
				authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList()));
		SecurityContextHolder.getContext().setAuthentication(auth);

	}

	private boolean checkJWTToken(HttpServletRequest request, HttpServletResponse res) {
		String authenticationHeader = request.getHeader(HEADER);
		if (authenticationHeader == null || !authenticationHeader.startsWith(PREFIX))
			return false;
		return true;
	}

}

WebSecurityConfig.java

package es.softtek.jwtDemo.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
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.web.authentication.UsernamePasswordAuthenticationFilter;

import es.softtek.jwtDemo.security.JWTAuthorizationFilter;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.csrf()
			.disable()
			.addFilterAfter(new JWTAuthorizationFilter(), UsernamePasswordAuthenticationFilter.class)
			.authorizeRequests().antMatchers(HttpMethod.POST, "/user").permitAll()
			.anyRequest().authenticated();
	}
}

HelloWorldController.java

package es.softtek.jwtDemo.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloWorldController {

	@RequestMapping("/hello")
	public String helloWorld(@RequestParam(value="name", defaultValue="World") String name) {
		return "Hello "+name+"!!";
	}
}

UserController.java

package es.softtek.jwtDemo.controller;

import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.tomcat.util.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import es.softtek.jwtDemo.dto.User;
import io.jsonwebtoken.Jwts;

@RestController
public class UserController {

	@Value("${jwt.secret}")
	String base64Key;

	@PostMapping("/user")
	public User login(@RequestParam("user") String username, @RequestParam("password") String pwd) {

		String token = getJWTToken(username);
		User user = new User();
		user.setUser(username);
		user.setToken(token);
		return user;

	}

	private String getJWTToken(String username) {

		List<GrantedAuthority> grantedAuthorities = AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_USER");

		String token = Jwts.builder().setSubject(username)
				.claim("authorities",
						grantedAuthorities.stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()))
				.setIssuedAt(new Date(System.currentTimeMillis()))
				.setExpiration(new Date(System.currentTimeMillis() + 600000)).signWith(getSecretKey()).compact();

		return "Bearer " + token;
	}

	private SecretKey getSecretKey() {
		return new SecretKeySpec(Base64.decodeBase64(base64Key), "HmacSHA256");
	}
}

JwtDemoApplicationTests.java

package es.softtek.jwtDemo;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class JwtDemoApplicationTests {

	@Test
	public void contextLoads() {
	}

}


程序运行,此时访问/hello是被禁止的,我们先通过post /user获得令牌信息


上图中我们已经获取到令牌信息,然后我们可以用这个令牌访问hello

 


以上就是 JWT令牌的使用以及一些算法,有问题的小伙伴,欢迎留言!!!

原创文章 155 获赞 539 访问量 4万+

猜你喜欢

转载自blog.csdn.net/weixin_44364444/article/details/105871675