Spring Boot + security + jwt 测试安全策略

一、测试概述

  主要目的是测试security的用法。因测试搭建mysql和redis比较麻烦,所以我这里将自定义的jwt和用户信息缓存到程序的内存中。
本人测试的项目比较混乱,Spring Boot父类只标出有用的依赖。其子类用的版本为jdk11。后续会继续深入oauth2,敬请期待。
代码地址:https://gitcode.net/qq_40539437/cloud.git
如果想使用自定义jwt工具类往redis里存储请查看源码cloud-jwt模块。

整体代码结构:
在这里插入图片描述

二、maven 相关依赖

1、父类maven相关依赖

 <properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>11</maven.compiler.source><maven.compiler.target>11</maven.compiler.target><junit.version>4.12</junit.version><log4j.version>1.2.17</log4j.version><lombok.version>1.16.18</lombok.version><mysql.version>5.1.47</mysql.version><druid.version>1.1.16</druid.version><spring.boot.version>2.2.5.RELEASE</spring.boot.version><spring.cloud.version>Hoxton.SR3</spring.cloud.version><spring.cloud.alibaba.version>2.2.1.RELEASE</spring.cloud.alibaba.version> <!-- 版本丛2.1.0.RELEASE升到2.2.1.RELEASE 解决nacos 域名访问问题 --><mybatis.spring.boot.version>1.3.0</mybatis.spring.boot.version></properties><dependencyManagement><dependencies><!--springboot 2.2.5--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring.boot.version}</version><type>pom</type><scope>import</scope></dependency><!--Spring cloud Hoxton.SR1--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring.cloud.version}</version><type>pom</type><scope>import</scope></dependency><!--Spring cloud alibaba 2.1.0.RELEASE--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring.cloud.alibaba.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit.version}</version></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><fork>true</fork><addResources>true</addResources></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>1.8</source><target>1.8</target></configuration></plugin></plugins></build>

2、子类相关依赖

 <build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>10</source><target>10</target></configuration></plugin></plugins></build><dependencies><dependency><groupId>com.atguigu.cloud</groupId><artifactId>cloud-api-commons</artifactId><version>1.0-SNAPSHOT</version></dependency><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.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.11.2</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.11.2</version><scope>runtime</scope></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><version>0.11.2</version><scope>runtime</scope></dependency><dependency><groupId>joda-time</groupId><artifactId>joda-time</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>

二、代码块

1、配置文件 application.yaml

server:port: 20000

2、启动类

package com.atguigu.cloud;import com.atguigu.cloud.cache.MyLocaleCache;
import com.atguigu.cloud.utils.RandomStr;
import com.atguigu.cloud.utils.RsaLocaleUtils;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;import java.util.Random;@SpringBootApplication
@EnableWebSecurity
public class CsSecurityTestApplication {public static void main(String[] args) throws Exception {SpringApplication.run(CsSecurityTestApplication.class, args);key();}public static void key() throws Exception {Random random = new Random();int i = random.nextInt(60);String randomString = RandomStr.getRandomString(i);System.err.println("公 私钥随机串: " + randomString);// 生成密钥对RsaLocaleUtils.generateKey(MyLocaleCache.publicKey_S, MyLocaleCache.privateKey_S, randomString, 2048);}}

3、本地缓存

package com.atguigu.cloud.cache;import com.atguigu.cloud.domain.UserInfo;import java.util.HashMap;
import java.util.Map;public class MyLocaleCache {public static String privateKey_S = "privateKey";public static String publicKey_S = "publicKey";private static Map<Long, UserInfo> cache = new HashMap<>();public static UserInfo get(Long key){return cache.get(key);}public static UserInfo set(Long key, UserInfo userInfo){return cache.put(key,userInfo);}
}

4.配置类

package com.atguigu.cloud.conf;import com.atguigu.cloud.filter.JwtAuthenticationTokenFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;@Configuration
public class SpringSecurityConfigurer extends WebSecurityConfigurerAdapter {@Autowiredprivate JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;/*** 密码加密方式 相同密码每次加密方式不同,但是每次都能与之匹配*/@Beanpublic BCryptPasswordEncoder bCryptPasswordEncoder() {return new BCryptPasswordEncoder();}/** 配置Spring Security 的拦截规则*/@Overrideprotected void configure(HttpSecurity http) throws Exception {http.csrf().disable().authorizeRequests().antMatchers("/login1").anonymous().antMatchers("/test/**").hasRole("ADMIN") //需要具有 "ADMIN" 角色的用户访问 "/test/**".anyRequest().authenticated(); // 其他路径需要认证http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);}/** 权限管理器*/@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}/*** {noop} 指代的是当前密码以明文输入  此处测试是指使用security自带的验证页面,设置密码,当实现UserDetailsService之后就不需要进行配置了* @param auth* @throws Exception@Overridepublic void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser("manager").password("{noop}manager").roles("manager").and().withUser("admin").password("{noop}admin").roles("manager", "ADMIN");}*/
}

5.登录及权限验证接口

登录接口 LoginController:
这里不能直接使用login直接当接口,因为会找security里的login接口

package com.atguigu.cloud.controller;import com.atguigu.cloud.cache.MyLocaleCache;
import com.atguigu.cloud.domain.LoginUser;
import com.atguigu.cloud.domain.UserInfo;
import com.atguigu.cloud.utils.JwtUtils;
import com.atguigu.cloud.utils.RsaLocaleUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import java.security.PrivateKey;
import java.util.HashMap;
import java.util.Map;@RestController
@RequestMapping("/login1")
public class LoginController {@Autowiredprivate AuthenticationManager authenticationManager;@GetMapping()public Map<String, Object> login(String username, String password) throws Exception {UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username , password);Authentication authentication = authenticationManager.authenticate(authenticationToken);if(authentication == null) {throw new RuntimeException("用户名或密码错误");}LoginUser loginUser = (LoginUser)authentication.getPrincipal();UserInfo userInfo = loginUser.getUser();MyLocaleCache.set(userInfo.getId(),userInfo);Map<String , Long> params = new HashMap<>() ;params.put("userId" , userInfo.getId()) ;PrivateKey privateKey = RsaLocaleUtils.getPrivateKey(MyLocaleCache.privateKey_S);String token = JwtUtils.generateTokenExpireInMinutes(userInfo, privateKey, 5);// 构建返回数据Map<String , Object> result = new HashMap<>();result.put("token" , token) ;System.out.println(username + "=" + password);return result;}
}

测试接口TestController:

package com.atguigu.cloud.controller;import com.atguigu.cloud.domain.UserInfo;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import java.security.Principal;
import java.util.HashMap;
import java.util.Map;@Controller
@RequestMapping("/test")
public class TestController {@GetMapping("/hello")@ResponseBodypublic Map<String,Object> hello(){UserInfo userInfo = (UserInfo)SecurityContextHolder.getContext().getAuthentication().getPrincipal();Map<String, Object> map = new HashMap<>();map.put("测试:","hello");map.put("用户:",userInfo.toString());return map;}
}

6.实体类

从写UserDetails:

package com.atguigu.cloud.domain;import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;import java.util.ArrayList;
import java.util.Collection;
import java.util.List;/**** 下方其他认证可根据业务情况重写*/
public class LoginUser implements UserDetails {private UserInfo userInfo;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {List list = new ArrayList();list.add(new SimpleGrantedAuthority("ROLE_"+ userInfo.getRole()));return list;}@Overridepublic String getPassword() {return userInfo.getPassword();}@Overridepublic String getUsername() {return userInfo.getUsername();}@Overridepublic boolean isAccountNonExpired() {          // 账号是否没有过期return true;}@Overridepublic boolean isAccountNonLocked() {           // 账号是否没有被锁定return true;}@Overridepublic boolean isCredentialsNonExpired() {      // 账号的凭证是否没有过期return true;}@Overridepublic boolean isEnabled() {                    // 账号是否可用return true;}public LoginUser() {}public LoginUser(UserInfo user) {this.userInfo = user;}public UserInfo getUser() {return userInfo;}public void setUser(UserInfo user) {this.userInfo = user;}
}

载荷Payload:

package com.atguigu.cloud.domain;import java.util.Date;public class Payload<T> {private String id;private T userInfo;private Date expiration;public Payload() {}public Payload(String id, T userInfo, Date expiration) {this.id = id;this.userInfo = userInfo;this.expiration = expiration;}public String getId() {return id;}public void setId(String id) {this.id = id;}public T getUserInfo() {return userInfo;}public void setUserInfo(T userInfo) {this.userInfo = userInfo;}public Date getExpiration() {return expiration;}public void setExpiration(Date expiration) {this.expiration = expiration;}@Overridepublic String toString() {final StringBuffer sb = new StringBuffer("Payload{");sb.append("id='").append(id).append('\'');sb.append(", userInfo=").append(userInfo);sb.append(", expiration=").append(expiration);sb.append('}');return sb.toString();}
}

用户信息UserInfo:

package com.atguigu.cloud.domain;public class UserInfo {private Long id;private String username;private String password;/** 这里多个可以采用分割符分割后续可以尽心解析*/private String role;public UserInfo() {}public UserInfo(Long id, String username, String role) {this.id = id;this.username = username;this.role = role;}public UserInfo(Long id, String username, String password, String role) {this.id = id;this.username = username;this.password = password;this.role = role;}public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getRole() {return role;}public void setRole(String role) {this.role = role;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}@Overridepublic String toString() {final StringBuffer sb = new StringBuffer("UserInfo{");sb.append("id=").append(id);sb.append(", username='").append(username).append('\'');sb.append(", password='").append(password).append('\'');sb.append(", role='").append(role).append('\'');sb.append('}');return sb.toString();}
}

7.JWT过滤器

package com.atguigu.cloud.filter;import com.atguigu.cloud.cache.MyLocaleCache;
import com.atguigu.cloud.domain.Payload;
import com.atguigu.cloud.domain.UserInfo;
import com.atguigu.cloud.utils.JwtUtils;
import com.atguigu.cloud.utils.RsaLocaleUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {// 1、从请求头中获取token,如果请求头中不存在token,直接放行即可!由Spring Security的过滤器进行校验!String token = request.getHeader("token");if(token == null || "".equals(token)) {filterChain.doFilter(request , response);return ;}// 2、对token进行解析,取出其中的userIdPayload<UserInfo> info = null;try {info = JwtUtils.getInfoFromToken(token, RsaLocaleUtils.getPublicKey("publicKey"), UserInfo.class);}catch (Exception e) {e.printStackTrace();throw new RuntimeException("token非法") ;}// 3、使用userId从redis中查询对应的LoginUser对象UserInfo userInfo1 = MyLocaleCache.get(info.getUserInfo().getId());if(userInfo1 != null) {List list = new ArrayList<>();list.add(new SimpleGrantedAuthority("ROLE_"+ userInfo1.getRole()));// 4、然后将查询到的LoginUser对象的相关信息封装到UsernamePasswordAuthenticationToken对象中,然后将该对象存储到Security的上下文对象中UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userInfo1, null ,list) ;SecurityContextHolder.getContext().setAuthentication(authenticationToken);}// 5、放行filterChain.doFilter(request , response);}
}

8.业务类

package com.atguigu.cloud.service;import com.atguigu.cloud.domain.LoginUser;
import com.atguigu.cloud.domain.UserInfo;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;import java.util.HashMap;
import java.util.Map;@Service
public class UserDetailsServiceImpl implements UserDetailsService {static Map<String, UserInfo> dataBase = new HashMap<>();static {/** 测试管理员用户*/UserInfo userInfo = new UserInfo();userInfo.setId(1L);userInfo.setUsername("admin");userInfo.setPassword(new BCryptPasswordEncoder().encode("admin")); //不加密方式 "{noop}admin"userInfo.setRole("ADMIN");/** 测试普通用户*/UserInfo userInfo2 = new UserInfo();userInfo2.setId(2L);userInfo2.setUsername("manager");userInfo2.setPassword(new BCryptPasswordEncoder().encode("manager")); //不加密方式 "{noop}admin"userInfo2.setRole("MANAGER");dataBase.put("admin",userInfo);dataBase.put("manager",userInfo2);}@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {// 根据用户名查询用户数据UserInfo userInfo = dataBase.get(username);System.out.println(userInfo);// 如果查询不到数据,说明用户名或者密码错误,直接抛出异常if(userInfo == null) {throw new RuntimeException("用户名或者密码错误") ;}// 将查询到的对象转换成Spring Security所需要的UserDetails对象  这里不需要比对密码return new LoginUser(userInfo);}
}

9.工具类

JsonUtils

package com.atguigu.cloud.utils;import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
import java.util.Map;public class JsonUtils {public static final ObjectMapper mapper = new ObjectMapper();private static final Logger logger = LoggerFactory.getLogger(JsonUtils.class);public static String toString(Object obj) {if (obj == null) {return null;}if (obj.getClass() == String.class) {return (String) obj;}try {return mapper.writeValueAsString(obj);} catch (JsonProcessingException e) {logger.error("json序列化出错:" + obj, e);return null;}}public static <T> T toBean(String json, Class<T> tClass) {try {return mapper.readValue(json, tClass);} catch (IOException e) {logger.error("json解析出错:" + json, e);return null;}}public static <E> List<E> toList(String json, Class<E> eClass) {try {return mapper.readValue(json, mapper.getTypeFactory().constructCollectionType(List.class, eClass));} catch (IOException e) {logger.error("json解析出错:" + json, e);return null;}}public static <K, V> Map<K, V> toMap(String json, Class<K> kClass, Class<V> vClass) {try {return mapper.readValue(json, mapper.getTypeFactory().constructMapType(Map.class, kClass, vClass));} catch (IOException e) {logger.error("json解析出错:" + json, e);return null;}}public static <T> T nativeRead(String json, TypeReference<T> type) {try {return mapper.readValue(json, type);} catch (IOException e) {logger.error("json解析出错:" + json, e);return null;}}
}

JwtUtils

package com.atguigu.cloud.utils;import com.atguigu.cloud.domain.Payload;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.joda.time.DateTime;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Base64;
import java.util.UUID;public class JwtUtils {private static final String JWT_PAYLOAD_USER_KEY = "user";/*** 私钥加密token** @param userInfo   载荷中的数据* @param privateKey 私钥* @param expire     过期时间,单位分钟* @return JWT*/public static String generateTokenExpireInMinutes(Object userInfo, PrivateKey privateKey, int expire) {return Jwts.builder().claim(JWT_PAYLOAD_USER_KEY, JsonUtils.toString(userInfo)).setId(createJTI()).setExpiration(DateTime.now().plusMinutes(expire).toDate()).signWith(privateKey, SignatureAlgorithm.RS256).compact();}/*** 私钥加密token** @param userInfo   载荷中的数据* @param privateKey 私钥* @param expire     过期时间,单位秒* @return JWT*/public static String generateTokenExpireInSeconds(Object userInfo, PrivateKey privateKey, int expire) {return Jwts.builder().claim(JWT_PAYLOAD_USER_KEY, JsonUtils.toString(userInfo)).setId(createJTI()).setExpiration(DateTime.now().plusSeconds(expire).toDate()).signWith(privateKey, SignatureAlgorithm.RS256).compact();}/*** 公钥解析token** @param token     用户请求中的token* @param publicKey 公钥* @return Jws<Claims>*/private static Jws<Claims> parserToken(String token, PublicKey publicKey) {return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);}private static String createJTI() {return new String(Base64.getEncoder().encode(UUID.randomUUID().toString().getBytes()));}/*** 获取token中的用户信息** @param token     用户请求中的令牌* @param publicKey 公钥* @return 用户信息*/public static <T> Payload<T> getInfoFromToken(String token, PublicKey publicKey, Class<T> userType) {Jws<Claims> claimsJws = parserToken(token, publicKey);Claims body = claimsJws.getBody();Payload<T> claims = new Payload<>();claims.setId(body.getId());claims.setUserInfo(JsonUtils.toBean(body.get(JWT_PAYLOAD_USER_KEY).toString(), userType));claims.setExpiration(body.getExpiration());return claims;}/*** 获取token中的载荷信息** @param token     用户请求中的令牌* @param publicKey 公钥* @return 用户信息*/public static <T> Payload<T> getInfoFromToken(String token, PublicKey publicKey) {Jws<Claims> claimsJws = parserToken(token, publicKey);Claims body = claimsJws.getBody();Payload<T> claims = new Payload<>();claims.setId(body.getId());claims.setExpiration(body.getExpiration());return claims;}public static void main(String[] args) {}
}

随机加密工具类:

package com.atguigu.cloud.utils;import java.util.Random;public class RandomStr {//length用户要求产生字符串的长度public static String getRandomString(int length) {String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";Random random = new Random();StringBuffer sb = new StringBuffer();for (int i = 0; i < length; i++) {int number = random.nextInt(62);sb.append(str.charAt(number));}return sb.toString();}
}

RsaLocaleUtils

package com.atguigu.cloud.utils;import org.springframework.stereotype.Component;import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.util.concurrent.ConcurrentHashMap;@Component
public class RsaLocaleUtils {private static final int DEFAULT_KEY_SIZE = 2048;private static ConcurrentHashMap<String,String> cache = new ConcurrentHashMap<>();public static void setCache(String key,String value){cache.put(key, value);}public static String getCache(String key){return cache.get(key);}/***  @Author: CS*  @Description: 从本地缓存中获取  可以修改为redis*/public static void generateKey(String publicKey, String privateKey, String secret, int keySize) throws Exception {KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");SecureRandom secureRandom = new SecureRandom(secret.getBytes());keyPairGenerator.initialize(Math.max(keySize, DEFAULT_KEY_SIZE), secureRandom);KeyPair keyPair = keyPairGenerator.genKeyPair();// 获取公钥并写出byte[] publicKeyBytes = keyPair.getPublic().getEncoded();setCache(publicKey,Base64.getEncoder().encodeToString(publicKeyBytes));// 获取私钥并写出byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();setCache(privateKey,Base64.getEncoder().encodeToString(privateKeyBytes));}/*** 从Redis中 读取密钥** @param privateKey 私钥保存的Key* @return 私钥对象* @throws Exception*/public static PrivateKey getPrivateKey(String privateKey) throws Exception {privateKey = getCache(privateKey).toString();byte[] bytes  = Base64.getDecoder().decode(privateKey);PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);KeyFactory factory = KeyFactory.getInstance("RSA");return factory.generatePrivate(spec);}/*** 从文件中 获取公钥** @param publicKey 公钥的字节形式* @return* @throws Exception*/public static PublicKey getPublicKey(String publicKey) throws Exception {publicKey = getCache(publicKey).toString();byte[] bytes = Base64.getDecoder().decode(publicKey);System.out.println(bytes.length);X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes);KeyFactory factory = KeyFactory.getInstance("RSA");return factory.generatePublic(spec);}
}

RsaUtils

package com.atguigu.cloud.utils;import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.security.*;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;//import io.jsonwebtoken.security.Keys;public class RsaUtils {private static final int DEFAULT_KEY_SIZE = 2048;/*** 从文件中读取公钥** @param filename 公钥保存路径,相对于classpath* @return 公钥对象* @throws Exception*/public static PublicKey getPublicKey(String filename) throws Exception {byte[] bytes = readFile(filename);return getPublicKey(bytes);}/*** 从文件中读取密钥** @param filename 私钥保存路径,相对于classpath* @return 私钥对象* @throws Exception*/public static PrivateKey getPrivateKey(String filename) throws Exception {byte[] bytes = readFile(filename);return getPrivateKey(bytes);}/*** 从文件中 获取公钥** @param bytes 公钥的字节形式* @return* @throws Exception*/private static PublicKey getPublicKey(byte[] bytes) throws Exception {bytes = Base64.getDecoder().decode(bytes);X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes);KeyFactory factory = KeyFactory.getInstance("RSA");return factory.generatePublic(spec);}/*** 获取密钥** @param bytes 私钥的字节形式* @return* @throws Exception*/private static PrivateKey getPrivateKey(byte[] bytes) throws NoSuchAlgorithmException, InvalidKeySpecException {bytes = Base64.getDecoder().decode(bytes);PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);KeyFactory factory = KeyFactory.getInstance("RSA");return factory.generatePrivate(spec);}/*** 根据密文,生存rsa公钥和私钥,并写入指定文件** @param publicKeyFilename  公钥文件路径* @param privateKeyFilename 私钥文件路径* @param secret             生成密钥的密文*/public static void generateKey(String publicKeyFilename, String privateKeyFilename, String secret, int keySize) throws Exception {KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");SecureRandom secureRandom = new SecureRandom(secret.getBytes());keyPairGenerator.initialize(Math.max(keySize, DEFAULT_KEY_SIZE), secureRandom);KeyPair keyPair = keyPairGenerator.genKeyPair();// 获取公钥并写出byte[] publicKeyBytes = keyPair.getPublic().getEncoded();publicKeyBytes = Base64.getEncoder().encode(publicKeyBytes);writeFile(publicKeyFilename, publicKeyBytes);// 获取私钥并写出byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();privateKeyBytes = Base64.getEncoder().encode(privateKeyBytes);writeFile(privateKeyFilename, privateKeyBytes);}private static byte[] readFile(String fileName) throws Exception {return Files.readAllBytes(new File(fileName).toPath());}private static void writeFile(String destPath, byte[] bytes) throws IOException {File dest = new File(destPath);if (!dest.exists()) {dest.createNewFile();}Files.write(dest.toPath(), bytes);}public static void testfor() {KeyPair keyPair = Keys.keyPairFor(SignatureAlgorithm.RS256);PrivateKey aPrivate = keyPair.getPrivate();PublicKey aPublic = keyPair.getPublic();}
}

10.测试类

package com.cloud.atguigu.jwt;import com.atguigu.cloud.domain.Payload;
import com.atguigu.cloud.domain.UserInfo;
import com.atguigu.cloud.utils.JwtUtils;
import com.atguigu.cloud.utils.RandomStr;
import com.atguigu.cloud.utils.RsaLocaleUtils;
import org.junit.Test;import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Random;public class JwtTest {private  String privateKey_S = "privateKey";private String publicKey_S = "publicKey";@Testpublic void testRSAByLocale() throws Exception {Random random = new Random();int i = random.nextInt(60);String randomString = RandomStr.getRandomString(i);randomString = "cs";System.err.println(randomString);// 生成密钥对RsaLocaleUtils.generateKey(publicKey_S, privateKey_S, randomString, 2048);// 获取私钥PrivateKey privateKey = RsaLocaleUtils.getPrivateKey(privateKey_S);System.out.println("privateKey = " + privateKey.toString());PublicKey publicKey = RsaLocaleUtils.getPublicKey(publicKey_S);System.out.println("publicKey = " + publicKey.toString());}@Testpublic void testJWTByLocale() throws Exception {Random random = new Random();int i = random.nextInt(60);String randomString = RandomStr.getRandomString(i);randomString = "cs";System.err.println(randomString);// 生成密钥对RsaLocaleUtils.generateKey(publicKey_S, privateKey_S, randomString, 2048);// 获取私钥PrivateKey privateKey = RsaLocaleUtils.getPrivateKey(privateKey_S);// 生成tokenString token = JwtUtils.generateTokenExpireInMinutes(new UserInfo(1L, "Jack", "guest"), privateKey, 5);System.out.println("token = " + token);System.err.println("privateKey:" + privateKey.toString());// 获取公钥PublicKey publicKey = RsaLocaleUtils.getPublicKey(publicKey_S);// 解析tokenPayload<UserInfo> info = JwtUtils.getInfoFromToken(token, publicKey, UserInfo.class);System.out.println("info.getExpiration() = " + info.getExpiration());System.out.println("info.getUserInfo() = " + info.getUserInfo());System.out.println("info.getId() = " + info.getId());}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/440111.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

N65总账凭证管理凭证查询(sql)

--核算账簿 select code , name , pk_setofbook from org_setofbook where ( pk_setofbook in ( select pk_setofbook from org_accountingbook where 1 1 and ( pk_group N0001A11000000000037X ) and ( accountenablestate 2 ) ) ) order by code;--核算账簿 select code …

Python(19)Excel表格操作Ⅰ

目录 导包 读取EXCEL文件 1、获取worksheet名称 2、设定当前工作表 3、输出目标单元格数据 4、工作表.rows&#xff08;行&#xff09; 5、工作表.columns&#xff08;列&#xff09; 小结 导包 要想使用 python 操作 Excel 文件&#xff0c;应当导入 openpyxl 包。在…

【习题】使用DevEco Studio高效开发

单选题 1. 用哪一种装饰器修饰的组件可作为页面入口组件&#xff1f;B A. Component B. Entry C. Preview D. Builder 回答正确 2. ArkTS Stage模型支持API Version 9&#xff0c;关于其工程目录结构说法正确的是&#xff1f;C A. oh-package.json5用于存放应用级配置信…

20240130在ubuntu20.04.6下给GTX1080安装最新的驱动和CUDA

20240130在ubuntu20.04.6下给GTX1080安装最新的驱动和CUDA 2024/1/30 12:27 缘起&#xff0c;为了在ubuntu20.4.6下使用whisper&#xff0c;以前用的是GTX1080M&#xff0c;装了535的驱动。 现在在PDD拼多多上了入手了一张二手的GTX1080&#xff0c;需要将安装最新的545的驱动程…

读书人必须知道的9个搜书引擎

各位小伙伴大家好&#xff0c;众所周知&#xff0c;现在找资源的难度要比以前高的多&#xff0c;各种网站封的封删的删&#xff0c;但大家对书籍资源的需求却越来越大。那今天我镜像哥就决定整一期电子书资源狠活儿。 这些资源都是我辛苦收集&#xff0c;并逐一验证筛选出来的的…

如何安装配置HFS并实现无公网ip远程访问本地电脑共享文件

文章目录 前言1.下载安装cpolar1.1 设置HFS访客1.2 虚拟文件系统 2. 使用cpolar建立一条内网穿透数据隧道2.1 保留隧道2.2 隧道名称2.3 成功使用cpolar创建二级子域名访问本地hfs 总结 前言 在大厂的云存储产品热度下降后&#xff0c;私人的NAS热度快速上升&#xff0c;其中最…

Fisher线性判别分析

Fisher线性判别分析 原理 LDA(Linear Discriminant Analysis&#xff09;是一种经典的线性判别方法&#xff0c;又称Fisher判别分析。该方法思想比较简单&#xff1a;给定训练集样例&#xff0c;设法将样例投影到一维的直线上&#xff0c;使得同类样例的投影点尽可能接…

Mybatis-Plus扩展

7 MybatisX插件[扩展] 7.1 MybatisX插件介绍 MybatisX 是一款基于 IDEA 的快速开发插件&#xff0c;为效率而生。 安装方法&#xff1a;打开 IDEA&#xff0c;进入 File -> Settings -> Plugins -> Browse Repositories&#xff0c;输入 mybatisx 搜索并安装。 功…

负载均衡下Webshell连接思路及难点

君衍. 一、应用场景二、环境搭建三、思路以及难点1、查看内部结构2、查看webshell3、使用蚁剑进行连接4、难点1 shell文件上传问题5、难点2 命令执行时飘逸6、难点3 大工具上传失败7、难点4 脚本失效 四、解决方式1、关闭对方节点服务器2、基于IP地址判断是否执行3、脚本实现流…

c#窗体捕捉方向键

方法1 实现方法参考代码&#xff1a; private void Form1_Load(object sender, EventArgs e){this.KeyPreview true;}protected override bool ProcessDialogKey(Keys keyData){if (keyData Keys.Left || keyData Keys.Right || keyData Keys.Up || keyData Keys.Down){s…

Linux下安装edge

edge具有及其强大的功能&#xff0c;受到很多人的喜爱&#xff0c;它也开发Linux版本&#xff0c;下面是安装方法&#xff1a; 1.去edge官网下载Linux(.deb)文件。 https://www.microsoft.com/zh-cn/edge/download?formMA13FJ 2.下载之后输入以下指令&#xff08;后面是安装…

【计算机网络】——TCP协议

&#x1f4d1;前言 本文主要是【计算机网络】——传输层TCP协议的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是青衿&#x1f947; ☁️博客首页&#xff1a;CSDN主页放风讲故事 &#x1f304;每日一句…