1.md5加密密码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; public class Md5Util {
protected static char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; protected static MessageDigest messagedigest = null; static { try { messagedigest = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException nsaex) { System.err.println(Md5Util.class.getName() + "初始化失败,MessageDigest不支持MD5Util。"); nsaex.printStackTrace(); } }
public static String getMD5String(String s) { return getMD5String(s.getBytes()); }
public static boolean checkPassword(String password, String md5PwdStr) { String s = getMD5String(password); return s.equals(md5PwdStr); } public static String getMD5String(byte[] bytes) { messagedigest.update(bytes); return bufferToHex(messagedigest.digest()); } private static String bufferToHex(byte bytes[]) { return bufferToHex(bytes, 0, bytes.length); } private static String bufferToHex(byte bytes[], int m, int n) { StringBuffer stringbuffer = new StringBuffer(2 * n); int k = m + n; for (int l = m; l < k; l++) { appendHexPair(bytes[l], stringbuffer); } return stringbuffer.toString(); } private static void appendHexPair(byte bt, StringBuffer stringbuffer) { char c0 = hexDigits[(bt & 0xf0) >> 4]; char c1 = hexDigits[bt & 0xf]; stringbuffer.append(c0); stringbuffer.append(c1); } }
|
2.JWT令牌使用
导入pom坐标
1 2 3 4 5 6
| <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>4.3.0</version> </dependency>
|
创建工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class JwtUtil { private static final String KEY = "forexample";
public static String genToken(Map<String, Object> claims) { return JWT.create() .withClaim("claims", claims) .withExpiresAt(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 12)) .sign(Algorithm.HMAC256(KEY)); }
public static Map<String, Object> parseToken(String token) { return JWT.require(Algorithm.HMAC256(KEY)) .build() .verify(token) .getClaim("claims") .asMap(); } }
|
在登陆时返回给前端,在进行其他接口调用的时候,将token传会后端,并且对请求进行拦截
在目录中创建拦截器文件interceptors并且定义拦截器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| @Slf4j @Component public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token =request.getHeader("Authorization"); try { Map<String, Object> stringObjectMap = JwtUtil.parseToken(token); ThreadLocalUtil.set(stringObjectMap); return true; } catch (Exception e) { response.setStatus(401); log.info("非法请求"); return false; } } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { ThreadLocalUtil.remove(); } }
|
在配置文件中,对该自定义拦截器进行注册,但是对登陆 和注册接口
1 2 3 4 5 6 7 8 9 10 11
| @Slf4j @Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private LoginInterceptor loginInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { log.info("开始注册自定义拦截器"); registry.addInterceptor(loginInterceptor).excludePathPatterns("/user/login","/user/register"); } }
|
3.后端工程中websocket的使用
导入webscoked的maven坐标
1 2 3 4
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
|
创建webscoked的服务文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| package com.example.text;
import jakarta.websocket.OnClose; import jakarta.websocket.OnMessage; import jakarta.websocket.OnOpen; import jakarta.websocket.Session; import jakarta.websocket.server.PathParam; import jakarta.websocket.server.ServerEndpoint; import org.springframework.stereotype.Component;
import java.io.IOException; import java.util.Collection; import java.util.HashMap; import java.util.Map;
@Component @ServerEndpoint("/ws/{sid}") public class webSocked { private static Map<String, Session> sessionMap =new HashMap();
@OnOpen public void onOpen(Session session, @PathParam("sid") String sid){ System.out.println("与客户端"+sid+"建立链接"); sessionMap.put(sid,session); }
@OnMessage public void onMessage(String message, @PathParam("sid") String sid) { System.out.println("收到来自客户端:" + sid + "的信息:" + message); }
@OnClose public void onClose(@PathParam("sid") String sid) { System.out.println("连接断开:" + sid); sessionMap.remove(sid); }
public void sendToAllClient(String message) { Collection<Session> sessions =sessionMap.values(); for (Session session : sessions) { try { session.getBasicRemote().sendText(message); } catch (IOException e) { throw new RuntimeException(e); } } }
}
|
将webscoked注入配置类中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package com.example.text;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration public class webSockedConfig { @Bean public ServerEndpointExporter serverEndpointExporter(){ return new ServerEndpointExporter(); } }
|
创建测试类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| package com.example.text;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component;
import java.time.LocalDateTime; import java.time.format.DateTimeFormatter;
@Component public class webSockedText { @Autowired private webSocked webSocked; @Scheduled(cron = "0/5 * * * * ?") public void sendMessage() { webSocked.sendToAllClient("这是来自服务端的消息:" + DateTimeFormatter.ofPattern("HH:mm:ss").format(LocalDateTime.now())); } }
|
定时任务在程序主入口出添加允许任务的注解
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| package com.example.text;
import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@Slf4j
@EnableScheduling public class TextApplication {
public static void main(String[] args) { SpringApplication.run(TextApplication.class, args); log.info("服务启动"); }
}
|
4.双token
首先导入jwt的pom依赖
1 2 3 4 5
| <dependency> <groupId>com.auth0</groupId> <artifactId>java-jwt</artifactId> <version>4.3.0</version> </dependency>
|
result结果类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| package com.example.text;
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;
@AllArgsConstructor @NoArgsConstructor @Data public class result<T> { private Integer code; private String message; private T data; public static <E> result<E> success(E data){ return new result<E>(0,"操作成功",data); } public static result success(){ return new result(0,"操作成功",null); } public static result error(String message) { return new result(1, message, null); } }
|
编写一个jwt工具类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| package com.example.text;
import com.auth0.jwt.JWT; import com.auth0.jwt.algorithms.Algorithm;
import java.util.Date; import java.util.Map;
public class jwt {
private static final String KEY = "forexample";
public static String genToken(Map<String, Object> claims, int minute) { return JWT.create() .withClaim("claims", claims) .withExpiresAt(new Date(System.currentTimeMillis() +1000*minute)) .sign(Algorithm.HMAC256(KEY)); }
public static Map<String, Object> parseToken(String token) { return JWT.require(Algorithm.HMAC256(KEY)) .build() .verify(token) .getClaim("claims") .asMap(); }
}
|
定义一个拦截器,核心代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| package com.example.text;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; import org.springframework.web.servlet.HandlerInterceptor; import com.example.text.jwt;
import java.awt.*; import java.util.Map;
@Slf4j @Component public class login implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { String accessToken = request.getHeader("accessToken"); colorPrint.colorPrint("accessToken----" + accessToken, colorPrint.BLUE); String refreshToken = request.getHeader("refreshToken"); colorPrint.colorPrint("refreshToken----" + refreshToken, colorPrint.BLUE); try { Map<String, Object> map = jwt.parseToken(accessToken); colorPrint.colorPrint("请求token通过,允许访问", colorPrint.BLUE); return true; } catch (Exception e) { try { Map<String, Object> map = jwt.parseToken(refreshToken); } catch (Exception exception) { colorPrint.colorPrint("七天请求过期", colorPrint.RED); response.setHeader("isOverdue","true"); response.setStatus(401); return false; } colorPrint.colorPrint("非法请求", colorPrint.RED); response.setStatus(401); return false; } } }
|
为了打印彩色的语句,自己封装了一个彩色打印
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package com.example.text;
public class colorPrint { public static final Integer RED=31; public static final Integer BLACK=30; public static final Integer GREEN=32; public static final Integer ORIGIN=33; public static final Integer BLUE=34; public static final Integer PURPLE=35; public static final Integer AQUA=36; public static final Integer GRAY=37; public static void colorPrint(String message, Integer color) { System.out.println("\033["+color+";4m" + message + "\033[0m"); } }
|
将自定义拦截器注册
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package com.example.text;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class config implements WebMvcConfigurer { @Autowired private login login;
@Override public void addInterceptors(InterceptorRegistry registry) { colorPrint.colorPrint(" 自定义拦截器开始生效",colorPrint.GREEN); registry.addInterceptor(login).excludePathPatterns("/get","/refresh"); } }
|
定义请求层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| package com.example.text;
import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map;
@Slf4j @RestController public class controller { @GetMapping("/text") public result textService() { colorPrint.colorPrint("请求进入", colorPrint.ORIGIN); return result.success(); }
@GetMapping("/get") public result<Map> get() { Map<String, Object> clains = new HashMap<>(); clains.put("id", 1); clains.put("username", 666); log.info("生成jwt令牌"); String accessToken = jwt.genToken(clains, 3); String refreshToken = jwt.genToken(clains, 60); colorPrint.colorPrint(accessToken, colorPrint.RED); colorPrint.colorPrint(refreshToken, colorPrint.BLUE); Map map = new HashMap<>(); map.put("accessToken", accessToken); map.put("refreshToken", refreshToken);
return result.success(map); }
@GetMapping("/refresh") public result<Map> refresh(@RequestHeader(name = "refreshToken") String refreshToken) { Map<String, Object> map = jwt.parseToken(refreshToken); String newAccessToken = jwt.genToken(map, 3); String newRefreshToken = jwt.genToken(map, 60); Map hashMap = new HashMap<>(); colorPrint.colorPrint(newAccessToken, colorPrint.PURPLE); colorPrint.colorPrint(newRefreshToken, colorPrint.PURPLE); hashMap.put("accessToken", newAccessToken); hashMap.put("refreshToken", newRefreshToken); return result.success(hashMap); }
}
|
5.图形验证码使用
验证码生成工具
本项目使用开源的验证码生成工具EasyCaptcha,其支持多种类型的验证码,例如gif、中文、算术等,并且简单易用,具体内容可参考其官方文档。
在common模块的pom.xml文件中增加如下内容
1 2 3 4
| <dependency> <groupId>com.github.whvcse</groupId> <artifactId>easy-captcha</artifactId> </dependency>
|
在service中使用
1 2 3 4 5
| SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 4); specCaptcha.setCharType(Captcha.TYPE_DEFAULT); String code = specCaptcha.text().toLowerCase(); System.out.println(code); String image = specCaptcha.toBase64();
|
启动项目当有请求进入的时候,会生成验证码的code,code是验证吗的值,image由base64编码,到前端进行解码,此处并没有使用redis,正常情况下需要生成一个uuid作为redis存储的key,而code作为redis的value。返回给前端的是验证码图片imag和redis的key,当前端有请求进来时,携带用户名和密码,图片验证码key和code,进入后端查询redis,进行正常的登陆