cookie方式实现
使用前端缓存cookie的方式实现,十分不安全
后端:
<dependencies>
<!-- 其他依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
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;
}
}
前端:
<!DOCTYPE html>
<html>
<head>
<title>Cookie 示例</title>
</head>
<body>
<h1>Cookie 示例</h1>
<script>
function getCookie(name) {
const value = "; " + document.cookie;
const parts = value.split("; " + name + "=");
if (parts.length === 2) {
return parts.pop().split(";").shift();
}
}
function setCookie(name, value, days) {
const date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
const expires = "expires=" + date.toUTCString();
document.cookie = name + "=" + value + ";" + expires + ";path=/";
}
function updateCookie(name, value) {
document.cookie = name + "=" + value + ";path=/";
}
function deleteCookie(name) {
document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/;";
}
// 获取Cookie的值
const username = getCookie("user");
if (username !== undefined) {
console.log("用户名:", username);
} else {
console.log("用户未登录或没有保存用户的Cookie");
}
// 设置Cookie的值
setCookie("user", "John Doe", 7); // 将用户的登录信息保存到Cookie中,有效期为7天
// 修改Cookie的值
updateCookie("user", "Jane Doe"); // 将用户的用户名更新为"Jane Doe"
// 删除Cookie
deleteCookie("user"); // 删除名为"user"的Cookie
</script>
</body>
</html>
session的方式
后端保存会话(redis),前端发信息
<!-- Maven 依赖 -->
<dependencies>
<!-- Spring Session -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-session</artifactId>
</dependency>
<!-- Redis 驱动 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
</dependencies>
# 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('未登录');
}
});
jwt方式实现
特点:一次登录,到处畅通。
使用sso微服务去认证,通过后保存token,再次验证时出示凭证即可获取登录信息。
1. 添加依赖
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.8.3</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
2.controller:
@RequestMapping("/login")
public Map<String,String> login(String userName, String password){
Map<String,String> 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构成包含三个部分:
- Header 头部
- Payload 负载
- Signature 签名
注意事项:
①根据需求设计过期时间(1秒 =1000 毫秒 )
②因为我把时间设计到token里面了所以你可以测试每次产生的token不一样
③设置userId那一栏-我目前是写死了 setId(“userId”) ,你可以根据需求设计不同的值进去
3.校验Token:
try {
JwtParser parser = Jwts.parser();
parser.setSigningKey("WuHan");//解析 要和上面“暗号”一样
Jws<Claims> claimsJws = 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第三段,即签名部分进行判断。
前端:
<script type="text/javascript">
$("#login").click(function () {
var name=$("#userName").val();
var pwd=$("#password").val();
$.post("http://localhost:8080/user/login",{userName:name,password:pwd},function(data) {
console.log(data);
if(data.code=="1"){
/* document.cookie=data.token;*/
sessionStorage.setItem("token",data.token);
sessionStorage.setItem("user",data.user);
window.location.href="index.html";
}else{
window.location.href="login.html";
}
},"json");
});
</script>
//需要验证token的页面
<script>
var data = sessionStorage.getItem("token");
if(data==null){
window.location.href="login.html";
}
</script>
补充:
window.sessionStorage(session级别):暂时储存,浏览器关闭之后会清除
window.localStorage (namespace级别):本地储存,浏览器关闭之后依旧不会清除,只能人为删除
4.开启登录拦截器
/**
* 登录拦截
*/
@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");
Jws<Claims> claimsJws = 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 {
}
}
5.加载拦截器
@Configuration
public class AppConfig implements WebMvcConfigurer {
@Resource
private LoginInterceptor loginInterceptor;
/**
* 添加拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
//.execudePathPatterns()//可以添加不拦截的地址
registry.addInterceptor(loginInterceptor).addPathPatterns("/**");
}
}