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;
@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(); // 压缩
}
@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 "未知的异常";
}
@GetMapping("/key")
public String generateKey() {
// 生成一个 HS256 算法的密钥
Key key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
// 用 Base64 把密钥编码成 字符串
return Base64.encodeBase64String(key.getEncoded());
}
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;
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");
}
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令牌的使用以及一些算法,有问题的小伙伴,欢迎留言!!!