使用前端缓存cookie的方式实现,十分不安全
后端:
org.springframework.boot spring-boot-starter-web
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletResponse; @Controller public class LoginController { @GetMapping("/") public String index() { return "index"; } @PostMapping("/login") public String login(@RequestParam("username") String username, @RequestParam("password") String password, HttpServletResponse response) { // 进行用户名和密码的验证逻辑 if (isValidUser(username, password)) { // 验证通过,创建一个Cookie保存用户登录信息 Cookie cookie = new Cookie("user", username); cookie.setMaxAge(86400); // 设置Cookie有效期为1天 response.addCookie(cookie); // 重定向到登录成功页面 return "redirect:/success"; } else { // 验证失败,返回登录页面 return "redirect:/?error=1"; } } @GetMapping("/success") public String success() { return "success"; } private boolean isValidUser(String username, String password) { // 在实际应用中,这里可以进行用户名和密码的验证逻辑,比如查询数据库或调用API等 // 这里只是一个示例,始终返回true来模拟验证通过 return true; } }
前端:
Cookie 示例 Cookie 示例
后端保存会话(redis),前端发信息
org.springframework.boot spring-boot-starter-session org.springframework.boot spring-boot-starter-data-redis
# Redis 连接配置 spring.redis.host=localhost spring.redis.port=6379
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; @SpringBootApplication @EnableRedisHttpSession public class MyApplication { public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } }
实现session,Spring 会自动使用 Redis 来管理 HttpSession。
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpSession; @RestController public class MyController { @GetMapping("/profile") public String getProfile(HttpSession session) { // 从会话中获取用户信息 String username = (String) session.getAttribute("username"); if (username != null) { return "Username: " + username; } else { return "Not logged in"; } } }
前端:
// 后端返回的响应中包含 session ID const sessionID = '1234567890'; // 前端将 session ID 存储在 LocalStorage 中 localStorage.setItem('sessionID', sessionID); // 发送请求时手动将 session ID 携带在请求头中或请求参数中 fetch('/profile', { headers: { 'Authorization': 'Bearer ' + localStorage.getItem('sessionID') } }) .then(response => response.json()) .then(data => { if (data.success) { // 成功获取到用户资料信息 console.log(data); } else { // 未登录,进行相应处理 console.log('未登录'); } });
特点:一次登录,到处畅通。
使用sso微服务去认证,通过后保存token,再次验证时出示凭证即可获取登录信息。
com.auth0 java-jwt 3.8.3 io.jsonwebtoken jjwt 0.9.1
@RequestMapping("/login") public Maplogin(String userName, String password){ Map map=new HashMap<>(); try{ String token = Jwts.builder().setSubject(userName) //主题,可以放用户的详细信息 .setIssuedAt(new Date()) //token创建时间 .setExpiration(new Date(System.currentTimeMillis() + 60000)) //token过期时间 .setId("userId") //用户ID //.setClaims(hashMap) //配置角色信息 .signWith(SignatureAlgorithm.HS256, "WuHan") //加密方式和加密密码 .compact(); // System.out.println("token:"+token); map.put("code","1"); map.put("msg","success"); map.put("token",token); map.put("user",userName); }catch (Exception e){ map.put("code","0"); map.put("msg","fail"); e.printStackTrace(); } return map; }
token示例如下:
token:eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ4YyIsImlhdCI6MTU5MTE1NDQwNiwiZXhwIjoxNTkxMTU0NDY2LCJqdGkiOiJ1c2VySWQifQ.c7gCDgIQ_I40dIWRxyG4yd1xaZQyWflnC7kX2Uoc9H8
token构成包含三个部分:
注意事项:
①根据需求设计过期时间(1秒 =1000 毫秒 )
②因为我把时间设计到token里面了所以你可以测试每次产生的token不一样
③设置userId那一栏-我目前是写死了 setId(“userId”) ,你可以根据需求设计不同的值进去
try { JwtParser parser = Jwts.parser(); parser.setSigningKey("WuHan");//解析 要和上面“暗号”一样 JwsclaimsJws = parser.parseClaimsJws(token); Claims body = claimsJws.getBody(); String username = body.getSubject(); // Object role = body.get("role"); return true; } catch (ExpiredJwtException e) { e.printStackTrace(); } catch (UnsupportedJwtException e) { e.printStackTrace(); } catch (MalformedJwtException e) { e.printStackTrace(); } catch (SignatureException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); }
setSigningKey()与builder中签名方法signWith()对应,parser中的此方法拥有与signWith()方法相同的三种参数形式,用于设置JWT的签名key,用户后面对JWT进行解析。
isSigned() 校验JWT是否进行签名。方法很简单,以分隔符" . ",截取JWT第三段,即签名部分进行判断。
前端:
//需要验证token的页面
补充:
window.sessionStorage(session级别):暂时储存,浏览器关闭之后会清除
window.localStorage (namespace级别):本地储存,浏览器关闭之后依旧不会清除,只能人为删除
/** * 登录拦截 */ @Component public class LoginInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String token = request.getParameter("token"); try { JwtParser parser = Jwts.parser(); parser.setSigningKey("WuHan"); JwsclaimsJws = parser.parseClaimsJws(token); Claims body = claimsJws.getBody(); String username = body.getSubject(); Object role = body.get("role"); return true; } catch (ExpiredJwtException e) { e.printStackTrace(); } catch (UnsupportedJwtException e) { e.printStackTrace(); } catch (MalformedJwtException e) { e.printStackTrace(); } catch (SignatureException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } return false; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
@Configuration public class AppConfig implements WebMvcConfigurer { @Resource private LoginInterceptor loginInterceptor; /** * 添加拦截器 * @param registry */ @Override public void addInterceptors(InterceptorRegistry registry) { //.execudePathPatterns()//可以添加不拦截的地址 registry.addInterceptor(loginInterceptor).addPathPatterns("/**"); } }