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.rhkb.cn/news/248137.html

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

相关文章

【Linux 基础】常用基础指令(上)

文章目录 一、 创建新用户并设置密码二、ls指令ls指令基本概念ls指令的简写操作 三、pwd指令四、cd指令五、touch指令六、rm指令七、mkdir指令八、rmdir 指令 一、 创建新用户并设置密码 ls /home —— 查看存在多少用户 whoami —— 查看当前用户名 adduser 用户名 —— 创建新…

公司宣传电子画册的制作方法

​制作公司宣传电子画册是一种非常有效的方式&#xff0c;可以展示公司的形象和产品&#xff0c;同时也可以吸引更多的潜在客户。不仅低碳环保&#xff0c;还省了不少人力和财力&#xff0c;只要一个二维码、一个链接就能随时随地访问公司的宣传画册。以下是一些制作电子画册的…

(2024,双流编码器,文本引导的风格迁移,调制,FFT 和低频滤波)FreeStyle:使用扩散模型进行文本引导风格迁移

FreeStyle: Free Lunch for Text-guided Style Transfer using Diffusion Models 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 3. 方法 3.1 LDM 3.2 FreeStyle 的模型结构…

springBoot配置文件加密

很多项目的配置文件里&#xff0c;包括数据库密码、缓存密码、还有一些第三方服务的Key都是直接配在里面&#xff0c;没有做任何加密处理&#xff01; 本次我用SpringBoot 集成 Jasypt 对数据库加密以及踩坑经验 1.集成依赖&#xff0c;我用的是目前最新的版本3.0.4版本 <…

常用芯片学习——AMS1117芯片

AMS1117 1A 低压差线性稳压器 使用说明 AMS1117 是一款低压差线性稳压电路&#xff0c;该电路输出电流能力为1A。该系列电路包含固定输出电压版本和可调输出电压版本&#xff0c;其输出电压精度为士1.5%。为了保证芯片和电源系统的稳定性&#xff0c;XBLWAMS1117 内置热保护和…

语音生成、写作增强、论文辅助、英文学习,AI原生应用精彩推荐一箩筐!

崭新的2024年已然降临&#xff0c;飞桨星河社区再次涌现出诸多精彩纷呈的AI原生应用&#xff0c;快来一同探索&#xff0c;发现这些应用带来的无限惊喜与可能吧&#xff01; 语音生成&#xff1a;10音色自由选择 应用介绍 本应用基于ERNIE SDK和语音合成工具&#xff0c;可以…

树--二叉树(C语言纯手凹)

目录 目录 1.什么是树&#xff1f;&#xff08;不深入&#xff0c;仅做了解&#xff09; 2.树的表示方式 2.1孩子兄弟表示法&#xff08;左孩子右兄弟&#xff09; 2.2孩子表示法 2.3双亲表示法 3.什么是二叉树 4.二叉树分类 4.1满二叉树 4.2完全二叉树 4.3二叉搜索树…

获取鼠标点击图片时候的坐标,以及利用html 中的useMap 和area 实现图片固定位置的点击事件

一 编写原因 应项目要求&#xff0c;需要对图片的固定几个位置分别做一个点击事件&#xff0c;响应不同的操作&#xff0c;如下图&#xff0c;需要点击红色区域&#xff0c;弹出不同的提示框&#xff1a; 二 获取点击图片时候的坐标 1. 说明 实现这以上功能的前提是需要确定需…

for循坏

签名&#xff1a;但行好事&#xff0c;莫问前程。 文章目录 前言一、循坏的四要素二、for循环的格式三、for循坏的小练习1、打印1-100以内的偶数&#xff0c;并求和2、输出所有的水仙花数3、求两个数的最大公约数和最小公倍数3.1最大公约数3.2最小公倍数 4、双层for循坏打印九九…

linux安装python3.11

yum install gcc-c zlib-devel bzip2-devel openssl* ncurses-devel sqlite* readline-devel tk-devel gdbm-devel libpcap* xz-devel libffi-devel -y 下载地址 https://www.python.org/ftp/python/3.11.7/Python-3.11.7.tar.xz 上传python文件&#xff0c;解压&#xff…

kubernetes-快速部署一套k8s集群

1、前置知识点 1.1 生产环境可部署Kubernetes集群的两种方式 目前生产部署Kubernetes集群主要有两种方式&#xff1a; kubeadm Kubeadm是一个K8s部署工具&#xff0c;提供kubeadm init和kubeadm join&#xff0c;用于快速部署Kubernetes集群。 二进制包 从github下载发行…

进程的执行过程

文章目录 前言一、进程的执行过程二、进程的示例2.1 示例1所有进程必须有限或者与时钟相关2.2 示例2多进程共享变量2.3 示例3仿真在0时刻结束2.4 示例4仿真变量保持不变 总结 前言 本文主要记录一下进程的执行过程&#xff0c;并通过一些例子&#xff0c;帮助进一步理解这个过…

活字格V9获取图片失败bug,报错404,了解存储路径,已改为批量上传和批量获取

项目场景&#xff1a; 问题描述 原因分析&#xff1a; 解决方案&#xff1a; 完成了批量上传功能&#xff0c;这插件真的很方便 于是写了个批量获取附件的js代码&#xff0c;我真厉害 项目场景&#xff1a; 活字格V9版本获取图片链接Upload 【9.0.103.0】图片上传的存储路…

境外投资企业备案结果公开名录列表数据

境外投资企业备案结果公开名录列表数据 1、时间&#xff1a;更新至2023年10月16日 2、指标&#xff1a;境外投资企业_机构、境内投资者名称、投资国别地区 3、来源&#xff1a;商务部 4、指标解释 境外投资企业&#xff08;机构&#xff09;备案结果公开名录列表&#xff…

USB-C显示器:未来显示技术的革新者

随着科技的不断发展&#xff0c;显示技术也在不断进步&#xff0c;而USB-C显示器作为最新的显示技术&#xff0c;正在引领着显示行业的发展潮流。USB-C显示器具有许多优点&#xff0c;如高速传输、便捷连接、节能环保等&#xff0c;使其成为未来显示技术的革新者。 一、USB-C显…

[PHP]严格类型

PHP: 类型声明 - Manual

部署YUM仓库服务

一、yum仓库 1. yum简介 yum是一个基于RPM包&#xff08;是Red-Hat Package Manager红帽软件包管理器的缩写&#xff09;构建的软件更新机制&#xff0c;能够自动解决软件包之间的依赖关系。 为什么会有依赖关系的发生 因为linux本身就是以系统简洁为自身优势&#xff0c;所以…

基于 Docker 搭建 Uptime-Kuma 一个极简风的应用监控

GitHub&#xff1a;https://github.com/louislam/uptime-kuma 一、uptime-kuma 介绍 Demo&#xff1a;https://uptime.wuhanjiayou.cn/ uptime-kuma 是一款开源的监控工具, 支持 TCP / PING / HTTP 等多种监控方式&#xff0c;可监测网站&#xff0c;数据库&#xff0c;Docker…

再学css

盒模型 有两种&#xff0c; IE盒子模型、W3C盒子模型&#xff1b;盒模型&#xff1a; 内容(content)、填充(padding)、边界(margin)、 边框(border)&#xff1b;区 别&#xff1a; IE的content部分把 border 和 padding计算了进去; 标准盒子模型的模型图 从上图可以看到&#x…

mysql注入联合查询

环境搭建 下载复现漏洞的包 下载小皮面板 将下载好的文件解压在小皮面板的phpstudy_pro\WWW路径下 将这个文件phpstudy_pro\WWW\sqli-labs-php7-master\sql-connections\db-creds.inc 中的密码更改为小皮面板中的密码 选择php版本 在小皮中启动nginx和数据库 使用环回地址访…