17 changed files with 203 additions and 167 deletions
-
6.idea/vcs.xml
-
1.idea/webContexts.xml
-
22pom.xml
-
71src/main/java/cn/star/controller/UsersController.java
-
5src/main/java/cn/star/dao/UsersDao.java
-
12src/main/java/cn/star/domian/Users.java
-
94src/main/java/cn/star/interceptor/TokenInterceptor.java
-
102src/main/java/cn/star/util/JwtUtil.java
-
13src/main/resources/spring-mvc.xml
-
0src/main/webapp/WEB-INF/jsp/Users.jsp
-
0src/main/webapp/WEB-INF/jsp/falselogin.jsp
-
3src/main/webapp/WEB-INF/jsp/index.jsp
-
0src/main/webapp/WEB-INF/jsp/success.jsp
-
0src/main/webapp/WEB-INF/jsp/successlogin.jsp
-
2src/main/webapp/WEB-INF/web.xml
-
0src/main/webapp/images
-
33src/main/webapp/static/css/styles.css
@ -0,0 +1,6 @@ |
|||
<?xml version="1.0" encoding="UTF-8"?> |
|||
<project version="4"> |
|||
<component name="VcsDirectoryMappings"> |
|||
<mapping directory="$PROJECT_DIR$" vcs="Git" /> |
|||
</component> |
|||
</project> |
|||
@ -1,91 +1,47 @@ |
|||
/*package cn.star.interceptor; |
|||
package cn.star.interceptor; |
|||
|
|||
import cn.star.common.ApiResponse; |
|||
import cn.star.util.JwtUtil; |
|||
import com.alibaba.fastjson.JSONObject; |
|||
import org.springframework.web.method.HandlerMethod; |
|||
import io.jsonwebtoken.Claims; |
|||
import org.springframework.web.servlet.HandlerInterceptor; |
|||
import org.springframework.web.servlet.ModelAndView; |
|||
|
|||
import javax.servlet.http.Cookie; |
|||
import javax.servlet.http.HttpServletRequest; |
|||
import javax.servlet.http.HttpServletResponse; |
|||
import java.io.IOException; |
|||
import java.io.PrintWriter; |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
public class TokenInterceptor implements HandlerInterceptor { |
|||
|
|||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException { |
|||
|
|||
// 只处理HandlerMethod类型的处理器(排除静态资源等) |
|||
if (!(handler instanceof HandlerMethod)) { |
|||
return true; |
|||
} |
|||
|
|||
System.out.println("执行方法之前执行这步操作"); |
|||
response.setCharacterEncoding("utf-8"); |
|||
@Override |
|||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { |
|||
//获取请求头中的token |
|||
|
|||
Cookie cookie = getCookieByName(request,"COOKIE_NAME"); |
|||
String token = request.getHeader("Authorization"); |
|||
|
|||
if(null != cookie) { |
|||
boolean result = JwtUtil.verify(cookie.getValue()); |
|||
if(!result) { |
|||
response.sendRedirect(request.getContextPath() + "/login"); |
|||
//验证token格式 |
|||
if(token == null || !token.startsWith("Bearer")) { |
|||
returnError(response,"请先登录"); |
|||
return false; |
|||
} |
|||
return true; |
|||
} |
|||
else { |
|||
response.sendRedirect(request.getContextPath() + "/login"); |
|||
token = token.substring(7); |
|||
|
|||
//验证token有效性 |
|||
if (!JwtUtil.isTokenValid(token)) { |
|||
returnError(response,"登录已过期,请重新登录"); |
|||
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 {} |
|||
|
|||
//根据名字获取cookie |
|||
public static Cookie getCookieByName(HttpServletRequest request , String name) { |
|||
Map<String,Cookie> cookieMap = ReadCookieMap(request); |
|||
if (cookieMap.containsKey(name)) { |
|||
Cookie cookie = cookieMap.get(name); |
|||
return cookie; |
|||
} |
|||
else { |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
private static Map<String,Cookie> ReadCookieMap(HttpServletRequest request) { |
|||
Map<String,Cookie> cookieMap = new HashMap<String,Cookie>(); |
|||
Cookie[] cookies = request.getCookies(); |
|||
if (cookies != null) { |
|||
for (Cookie cookie : cookies) { |
|||
cookieMap.put(cookie.getName(), cookie); |
|||
} |
|||
} |
|||
return cookieMap; |
|||
//解析token获取角色,存入request继续使用 |
|||
Claims claims = JwtUtil.parseToken(token); |
|||
request.setAttribute("userId",claims.get("userId",Long.class)); |
|||
request.setAttribute("role",claims.get("role",Long.class)); |
|||
return true; |
|||
} |
|||
|
|||
private void responseMessage(HttpServletRequest request, HttpServletResponse response, PrintWriter out, ApiResponse apiResponse) |
|||
throws IOException |
|||
{ |
|||
response.setContentType("text/html;charset=utf-8"); |
|||
out.print(JSONObject.toJSONString(apiResponse));//这个ApiResponse需要创建一个类然后调用 |
|||
//返回错误信息 |
|||
private void returnError(HttpServletResponse response, String message) throws Exception { |
|||
response.setContentType("text/html;charset=UTF-8"); |
|||
PrintWriter out = response.getWriter(); |
|||
out.write("<script>alert('" + message + "'); window.location.href='/login.html';</script>"); |
|||
out.flush(); |
|||
out.close(); |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
}*/ |
|||
} |
|||
} |
|||
@ -1,79 +1,49 @@ |
|||
package cn.star.util; |
|||
|
|||
import com.auth0.jwt.JWT; |
|||
import com.auth0.jwt.JWTVerifier; |
|||
import com.auth0.jwt.algorithms.Algorithm; |
|||
import com.auth0.jwt.interfaces.DecodedJWT; |
|||
|
|||
import java.io.UnsupportedEncodingException; |
|||
import io.jsonwebtoken.Claims; |
|||
import io.jsonwebtoken.Jwts; |
|||
import io.jsonwebtoken.SignatureAlgorithm; |
|||
import io.jsonwebtoken.security.Keys; |
|||
import javax.crypto.SecretKey; |
|||
import java.util.Date; |
|||
import java.util.HashMap; |
|||
import java.util.Map; |
|||
|
|||
import static java.lang.System.currentTimeMillis; |
|||
|
|||
public class JwtUtil { |
|||
//密钥-实际项目应该存在配置文件(?怎么弄 |
|||
private static final SecretKey SECRET_KEY = Keys.secretKeyFor(SignatureAlgorithm.HS256); |
|||
//Token 有效时间 |
|||
private static final long EXPIRATION_TIME = 2 * 60 * 60 * 1000; |
|||
|
|||
//生成token |
|||
public static String generateToken(Long userId,String role) { |
|||
|
|||
Date now = new Date(); |
|||
Date expiration = new Date(now.getTime() + EXPIRATION_TIME); |
|||
|
|||
return Jwts.builder().claim("usersId",userId) |
|||
.claim("role",role) |
|||
.setIssuedAt(now) |
|||
.setExpiration(expiration) |
|||
.signWith(SECRET_KEY) |
|||
.compact(); |
|||
} |
|||
|
|||
private static final long EXPIRE_TIME = 24 * 60 * 60 * 1000; //expire-到期时间 |
|||
|
|||
// token私匙 |
|||
private static final String TOKEN_SECRET = "f26e587c28064d0e855e72c0a6a0e618";//只是模拟自己设置的? |
|||
|
|||
//校验token是否正确 |
|||
public static boolean verify(String token) { |
|||
try { |
|||
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET); |
|||
JWTVerifier verifier = JWT.require(algorithm).build(); |
|||
DecodedJWT jwt = verifier.verify(token); |
|||
return true; |
|||
} catch (Exception e) { |
|||
return false; |
|||
} |
|||
} |
|||
// 解析Token获取信息 |
|||
|
|||
//return token包含的用户名 |
|||
public static String getUsername(String token) { |
|||
try { |
|||
DecodedJWT jwt = JWT.decode(token); |
|||
return jwt.getClaim("username").asString(); |
|||
} catch (Exception e) { |
|||
return null; |
|||
public static Claims parseToken(String token) { |
|||
return Jwts.parserBuilder() |
|||
.setSigningKey(SECRET_KEY) |
|||
.build() |
|||
.parseClaimsJws(token) |
|||
.getBody(); |
|||
} |
|||
} |
|||
|
|||
//获取登录用户id |
|||
public static String getUserId(String token) { |
|||
//解析token是否有效 |
|||
public static boolean isTokenValid(String token) { |
|||
try { |
|||
DecodedJWT jwt = JWT.decode(token); |
|||
return jwt.getClaim("userId").asString(); |
|||
} catch (Exception e) { |
|||
return null; |
|||
Claims claims = parseToken(token); |
|||
return !claims.getExpiration().before(new Date()); |
|||
}catch (Exception e) { |
|||
return false;//无效或过期 |
|||
} |
|||
} |
|||
|
|||
//生成签名,15min后过期 |
|||
public static String sign(String username,String userId) { |
|||
// 过期时间 |
|||
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME); |
|||
// 私钥及加密算法 |
|||
Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET); |
|||
// 设置头部信息 |
|||
Map<String, Object> header = new HashMap<>(2); |
|||
header.put("typ", "JWT"); |
|||
header.put("alg", "HS256"); |
|||
// 附带username,userId信息,生成签名 |
|||
return JWT.create() |
|||
.withHeader(header) |
|||
.withClaim("loginName", username) |
|||
.withClaim("userId",userId) |
|||
.withExpiresAt(date) |
|||
.sign(algorithm); |
|||
} |
|||
|
|||
|
|||
|
|||
|
|||
|
|||
|
|||
} |
|||
|
|||
@ -1,9 +1,10 @@ |
|||
<%@ page contentType="text/html;charset=UTF-8" language="java" %> |
|||
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> |
|||
<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %> |
|||
<html> |
|||
<head> |
|||
<title>主界面</title> |
|||
<link rel="stylesheet" href="static/css/styles.css"> |
|||
<link rel="stylesheet" href="../static/css/styles.css"> |
|||
<style> |
|||
.my-class { |
|||
text-align: center; |
|||
@ -1,7 +1,30 @@ |
|||
a { |
|||
color: #f80d43; |
|||
} |
|||
|
|||
.center-text { |
|||
.my-class { |
|||
text-align: center; |
|||
} |
|||
/* 新增样式:登录表单容器 */ |
|||
.login-container { |
|||
position: relative; /* 相对定位,用于子元素绝对定位 */ |
|||
width: 300px; /* 固定宽度 */ |
|||
margin: 20px auto; /* 居中显示 */ |
|||
padding: 20px; |
|||
border: 1px solid #eee; /* 轻微边框 */ |
|||
} |
|||
/* 按钮容器样式 */ |
|||
.button-group { |
|||
display: flex; /* 弹性布局 */ |
|||
justify-content: space-between; /* 两端对齐 */ |
|||
margin-top: 15px; /* 与上方内容间距 */ |
|||
} |
|||
/* 基础按钮样式 */ |
|||
.base-btn { |
|||
padding: 6px 12px; |
|||
border: 1px solid #ccc; |
|||
background-color: #f5f5f5; |
|||
cursor: pointer; /* 鼠标悬停显示手型 */ |
|||
text-decoration: none; /* 去除链接下划线 */ |
|||
color: #333; /* 文字颜色 */ |
|||
font-size: 14px; |
|||
} |
|||
.base-btn:hover { |
|||
background-color: #e0e0e0; /* 悬停效果 */ |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue