From 95688e400b6974953505c159f8fbf9d65784c724 Mon Sep 17 00:00:00 2001
From: 648540858 <648540858@qq.com>
Date: Mon, 13 Mar 2023 09:45:00 +0800
Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E6=AD=A5=E5=AE=9E=E7=8E=B0=E7=99=BB?=
=?UTF-8?q?=E5=BD=95=E8=BF=94=E5=9B=9Etoken?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
pom.xml | 15 +-
.../AnonymousAuthenticationEntryPoint.java | 16 +-
.../DefaultUserDetailsServiceImpl.java | 15 +-
.../conf/security/InvalidSessionHandler.java | 24 ---
.../security/JwtAuthenticationFilter.java | 65 +++++++++
.../iot/vmp/conf/security/JwtUtils.java | 138 ++++++++++++++++++
.../conf/security/LoginSuccessHandler.java | 13 +-
.../iot/vmp/conf/security/SecurityUtils.java | 25 +++-
.../vmp/conf/security/WebSecurityConfig.java | 95 +++++++-----
.../iot/vmp/conf/security/dto/JwtUser.java | 53 +++++++
.../iot/vmp/vmanager/user/UserController.java | 8 +-
11 files changed, 378 insertions(+), 89 deletions(-)
delete mode 100644 src/main/java/com/genersoft/iot/vmp/conf/security/InvalidSessionHandler.java
create mode 100644 src/main/java/com/genersoft/iot/vmp/conf/security/JwtAuthenticationFilter.java
create mode 100644 src/main/java/com/genersoft/iot/vmp/conf/security/JwtUtils.java
create mode 100644 src/main/java/com/genersoft/iot/vmp/conf/security/dto/JwtUser.java
diff --git a/pom.xml b/pom.xml
index bcc3c36a..a675c6ff 100644
--- a/pom.xml
+++ b/pom.xml
@@ -216,8 +216,6 @@
4.10.0
-
-
io.github.rburgst
@@ -226,10 +224,17 @@
+
+
+
+
+
+
+
- net.sf.kxml
- kxml2
- 2.3.0
+ org.bitbucket.b_c
+ jose4j
+ 0.9.3
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java b/src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java
index 35c68d5d..7a178d9e 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java
@@ -1,10 +1,11 @@
package com.genersoft.iot.vmp.conf.security;
import com.alibaba.fastjson2.JSONObject;
+import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
@@ -17,12 +18,17 @@ import java.io.IOException;
* @author lin
*/
@Component
-public class AnonymousAuthenticationEntryPoint implements AuthenticationEntryPoint {
-
- private final static Logger logger = LoggerFactory.getLogger(DefaultUserDetailsServiceImpl.class);
+public class AnonymousAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) {
+ System.err.println(e.getMessage());
+ String jwt = request.getHeader(JwtUtils.getHeader());
+ JwtUser jwtUser = JwtUtils.verifyToken(jwt);
+ String username = jwtUser.getUserName();
+ UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, jwtUser.getPassword() );
+ SecurityContextHolder.getContext().setAuthentication(token);
+ System.out.println(jwt);
// 允许跨域
String origin = request.getHeader("Origin");
response.setHeader("Access-Control-Allow-Credentials", "true");
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/DefaultUserDetailsServiceImpl.java b/src/main/java/com/genersoft/iot/vmp/conf/security/DefaultUserDetailsServiceImpl.java
index 509a1e03..0cda4a5c 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/security/DefaultUserDetailsServiceImpl.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/security/DefaultUserDetailsServiceImpl.java
@@ -1,7 +1,9 @@
package com.genersoft.iot.vmp.conf.security;
-import java.time.LocalDateTime;
-
+import com.alibaba.excel.util.StringUtils;
+import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
+import com.genersoft.iot.vmp.service.IUserService;
+import com.genersoft.iot.vmp.storager.dao.dto.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -10,10 +12,7 @@ import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
-import com.alibaba.excel.util.StringUtils;
-import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
-import com.genersoft.iot.vmp.service.IUserService;
-import com.genersoft.iot.vmp.storager.dao.dto.User;
+import java.time.LocalDateTime;
/**
* 用户登录认证逻辑
@@ -45,4 +44,8 @@ public class DefaultUserDetailsServiceImpl implements UserDetailsService {
}
+
+
+
+
}
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/InvalidSessionHandler.java b/src/main/java/com/genersoft/iot/vmp/conf/security/InvalidSessionHandler.java
deleted file mode 100644
index f3fd0685..00000000
--- a/src/main/java/com/genersoft/iot/vmp/conf/security/InvalidSessionHandler.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.genersoft.iot.vmp.conf.security;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.security.web.session.InvalidSessionStrategy;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-
-/**
- * 登录超时的处理
- */
-public class InvalidSessionHandler implements InvalidSessionStrategy {
-
- private final static Logger logger = LoggerFactory.getLogger(InvalidSessionHandler.class);
-
- @Override
- public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse httpServletResponse) throws IOException, ServletException {
- String username = request.getParameter("username");
- logger.info("[登录超时] - [{}]", username);
- }
-}
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/JwtAuthenticationFilter.java b/src/main/java/com/genersoft/iot/vmp/conf/security/JwtAuthenticationFilter.java
new file mode 100644
index 00000000..91709aa7
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/conf/security/JwtAuthenticationFilter.java
@@ -0,0 +1,65 @@
+package com.genersoft.iot.vmp.conf.security;
+
+import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+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;
+
+/**
+ * jwt token 过滤器
+ */
+
+@Component
+public class JwtAuthenticationFilter extends OncePerRequestFilter {
+
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
+ String jwt = request.getHeader(JwtUtils.getHeader());
+ // 这里如果没有jwt,继续往后走,因为后面还有鉴权管理器等去判断是否拥有身份凭证,所以是可以放行的
+ // 没有jwt相当于匿名访问,若有一些接口是需要权限的,则不能访问这些接口
+ if (StringUtils.isBlank(jwt)) {
+ chain.doFilter(request, response);
+ return;
+ }
+
+
+ JwtUser jwtUser = JwtUtils.verifyToken(jwt);
+ String username = jwtUser.getUserName();
+ // TODO 处理各个状态
+ switch (jwtUser.getStatus()){
+ case EXPIRED:
+ response.setStatus(400);
+ chain.doFilter(request, response);
+ // 异常
+ return;
+ case EXCEPTION:
+ // 过期
+ response.setStatus(400);
+ chain.doFilter(request, response);
+ return;
+ case EXPIRING_SOON:
+ // 即将过期
+// return;
+ default:
+ }
+
+// String password = SecurityUtils.encryptPassword(jwtUser.getPassword());
+// user.setPassword(password);
+
+ // 构建UsernamePasswordAuthenticationToken,这里密码为null,是因为提供了正确的JWT,实现自动登录
+ UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, jwtUser.getPassword(), new ArrayList<>() );
+ SecurityContextHolder.getContext().setAuthentication(token);
+ chain.doFilter(request, response);
+ }
+
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/JwtUtils.java b/src/main/java/com/genersoft/iot/vmp/conf/security/JwtUtils.java
new file mode 100644
index 00000000..378e5d64
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/conf/security/JwtUtils.java
@@ -0,0 +1,138 @@
+package com.genersoft.iot.vmp.conf.security;
+
+import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
+import org.jose4j.json.JsonUtil;
+import org.jose4j.jwk.RsaJsonWebKey;
+import org.jose4j.jws.AlgorithmIdentifiers;
+import org.jose4j.jws.JsonWebSignature;
+import org.jose4j.jwt.JwtClaims;
+import org.jose4j.jwt.NumericDate;
+import org.jose4j.jwt.consumer.ErrorCodes;
+import org.jose4j.jwt.consumer.InvalidJwtException;
+import org.jose4j.jwt.consumer.JwtConsumer;
+import org.jose4j.jwt.consumer.JwtConsumerBuilder;
+import org.jose4j.lang.JoseException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.security.PrivateKey;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+
+public class JwtUtils {
+
+ private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class);
+
+ private static final String HEADER = "Access-Token";
+ private static final String AUDIENCE = "Audience";
+
+ private static final long EXPIRED_THRESHOLD = 10 * 60;
+
+ private static final String keyId = "3e79646c4dbc408383a9eed09f2b85ae";
+ private static final String privateKeyStr = "{\"kty\":\"RSA\",\"kid\":\"3e79646c4dbc408383a9eed09f2b85ae\",\"alg\":\"RS256\",\"n\":\"gndmVdiOTSJ5et2HIeTM5f1m61x5ojLUi5HDfvr-jRrESQ5kbKuySGHVwR4QhwinpY1wQqBnwc80tx7cb_6SSqsTOoGln6T_l3k2Pb54ClVnGWiW_u1kmX78V2TZOsVmZmwtdZCMi-2zWIyAdIEXE-gncIehoAgEoq2VAhaCURbJWro_EwzzQwNmCTkDodLAx4npXRd_qSu0Ayp0txym9OFovBXBULRvk4DPiy3i_bPUmCDxzC46pTtFOe9p82uybTehZfULZtXXqRm85FL9n5zkrsTllPNAyEGhgb0RK9sE5nK1m_wNNysDyfLC4EFf1VXTrKm14XNVjc2vqLb7Mw\",\"e\":\"AQAB\",\"d\":\"ed7U_k3rJ4yTk70JtRSIfjKGiEb67BO1TabcymnljKO7RU8nage84zZYuSu_XpQsHk6P1f0Gzxkicghm_Er-FrfVn2pp70Xu52z3yRd6BJUgWLDFk97ngScIyw5OiULKU9SrZk2frDpftNCSUcIgb50F8m0QAnBa_CdPsQKbuuhLv8V8tBAV7F_lAwvSBgu56wRo3hPz5dWH8YeXM7XBfQ9viFMNEKd21sP_j5C7ueUnXT66nBxe3ZJEU3iuMYM6D6dB_KW2GfZC6WmTgvGhhxJD0h7aYmfjkD99MDleB7SkpbvoODOqiQ5Epb7Nyh6kv5u4KUv2CJYtATLZkUeMkQ\",\"p\":\"uBUjWPWtlGksmOqsqCNWksfqJvMcnP_8TDYN7e4-WnHL4N-9HjRuPDnp6kHvCIEi9SEfxm7gNxlRcWegvNQr3IZCz7TnCTexXc5NOklB9OavWFla6u-s3Thn6Tz45-EUjpJr0VJMxhO-KxGmuTwUXBBp4vN6K2qV6rQNFmgkWzk\",\"q\":\"tW_i7cCec56bHkhITL_79dXHz_PLC_f7xlynmlZJGU_d6mqOKmLBNBbTMLnYW8uAFiFzWxDeDHh1o5uF0mSQR-Z1Fg35OftnpbWpy0Cbc2la5WgXQjOwtG1eLYIY2BD3-wQ1VYDBCvowr4FDi-sngxwLqvwmrJ0xjhi99O-Gzcs\",\"dp\":\"q1d5jE85Hz_6M-eTh_lEluEf0NtPEc-vvhw-QO4V-cecNpbrCBdTWBmr4dE3NdpFeJc5ZVFEv-SACyei1MBEh0ItI_pFZi4BmMfy2ELh8ptaMMkTOESYyVy8U7veDq9RnBcr5i1Nqr0rsBkA77-9T6gzdvycBZdzLYAkAmwzEvk\",\"dq\":\"q29A2K08Crs-jmp2Bi8Q_8QzvIX6wSBbwZ4ir24AO-5_HNP56IrPS0yV2GCB0pqCOGb6_Hz_koDvhtuYoqdqvMVAtMoXR3YJBUaVXPt65p4RyNmFwIPe31zHs_BNUTsXVRMw4c16mci03-Af1sEm4HdLfxAp6sfM3xr5wcnhcek\",\"qi\":\"rHPgVTyHUHuYzcxfouyBfb1XAY8nshwn0ddo81o1BccD4Z7zo5It6SefDHjxCAbcmbiCcXBSooLcY-NF5FMv3fg19UE21VyLQltHcVjRRp2tRs4OHcM8yaXIU2x6N6Z6BP2tOksHb9MOBY1wAQzFOAKg_G4Sxev6-_6ud6RISuc\"}";
+ private static final String publicKeyStr = "{\"kty\":\"RSA\",\"kid\":\"3e79646c4dbc408383a9eed09f2b85ae\",\"alg\":\"RS256\",\"n\":\"gndmVdiOTSJ5et2HIeTM5f1m61x5ojLUi5HDfvr-jRrESQ5kbKuySGHVwR4QhwinpY1wQqBnwc80tx7cb_6SSqsTOoGln6T_l3k2Pb54ClVnGWiW_u1kmX78V2TZOsVmZmwtdZCMi-2zWIyAdIEXE-gncIehoAgEoq2VAhaCURbJWro_EwzzQwNmCTkDodLAx4npXRd_qSu0Ayp0txym9OFovBXBULRvk4DPiy3i_bPUmCDxzC46pTtFOe9p82uybTehZfULZtXXqRm85FL9n5zkrsTllPNAyEGhgb0RK9sE5nK1m_wNNysDyfLC4EFf1VXTrKm14XNVjc2vqLb7Mw\",\"e\":\"AQAB\"}";
+
+ /**
+ * token过期时间(分钟)
+ */
+ public static final long expirationTime = 30;
+
+ public static String createToken(String username, String password) {
+ try {
+ /**
+ * “iss” (issuer) 发行人
+ *
+ * “sub” (subject) 主题
+ *
+ * “aud” (audience) 接收方 用户
+ *
+ * “exp” (expiration time) 到期时间
+ *
+ * “nbf” (not before) 在此之前不可用
+ *
+ * “iat” (issued at) jwt的签发时间
+ */
+ //Payload
+ JwtClaims claims = new JwtClaims();
+ claims.setGeneratedJwtId();
+ claims.setIssuedAtToNow();
+ // 令牌将过期的时间 分钟
+ claims.setExpirationTimeMinutesInTheFuture(expirationTime);
+ claims.setNotBeforeMinutesInThePast(0);
+ claims.setSubject("login");
+ claims.setAudience(AUDIENCE);
+ //添加自定义参数,必须是字符串类型
+ claims.setClaim("username", username);
+ claims.setClaim("password", password);
+
+ //jws
+ JsonWebSignature jws = new JsonWebSignature();
+ //签名算法RS256
+ jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
+ jws.setKeyIdHeaderValue(keyId);
+ jws.setPayload(claims.toJson());
+
+ PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(privateKeyStr)).getPrivateKey();
+ jws.setKey(privateKey);
+
+ //get token
+ String idToken = jws.getCompactSerialization();
+ return idToken;
+ } catch (JoseException e) {
+ logger.error("[Token生成失败]: {}", e.getMessage());
+ }
+
+ return null;
+ }
+
+ public static String getHeader() {
+ return HEADER;
+ }
+
+
+ public static JwtUser verifyToken(String token) {
+
+ JwtUser jwtUser = new JwtUser();
+
+ try {
+ JwtConsumer consumer = new JwtConsumerBuilder()
+ .setRequireExpirationTime()
+ .setMaxFutureValidityInMinutes(5256000)
+ .setAllowedClockSkewInSeconds(30)
+ .setRequireSubject()
+ //.setExpectedIssuer("")
+ .setExpectedAudience(AUDIENCE)
+ .setVerificationKey(new RsaJsonWebKey(JsonUtil.parseJson(publicKeyStr)).getPublicKey())
+ .build();
+
+ JwtClaims claims = consumer.processToClaims(token);
+ NumericDate expirationTime = claims.getExpirationTime();
+ // 判断是否即将过期, 默认剩余时间小于5分钟未即将过期
+ // 剩余时间 (秒)
+ long timeRemaining = LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8)) - expirationTime.getValue();
+ if (timeRemaining < 5 * 60) {
+ jwtUser.setStatus(JwtUser.TokenStatus.EXPIRING_SOON);
+ }else {
+ jwtUser.setStatus(JwtUser.TokenStatus.NORMAL);
+ }
+
+ String username = (String) claims.getClaimValue("username");
+ String password = (String) claims.getClaimValue("password");
+ jwtUser.setUserName(username);
+ jwtUser.setPassword(password);
+
+ return jwtUser;
+ } catch (InvalidJwtException e) {
+ if (e.hasErrorCode(ErrorCodes.EXPIRED)) {
+ jwtUser.setStatus(JwtUser.TokenStatus.EXPIRED);
+ }else {
+ jwtUser.setStatus(JwtUser.TokenStatus.EXCEPTION);
+ }
+ return jwtUser;
+ }catch (Exception e) {
+ logger.error("[Token解析失败]: {}", e.getMessage());
+ jwtUser.setStatus(JwtUser.TokenStatus.EXPIRED);
+ return jwtUser;
+ }
+ }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/LoginSuccessHandler.java b/src/main/java/com/genersoft/iot/vmp/conf/security/LoginSuccessHandler.java
index 2d7e8a1b..d26342ef 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/security/LoginSuccessHandler.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/security/LoginSuccessHandler.java
@@ -21,7 +21,16 @@ public class LoginSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
- String username = request.getParameter("username");
- logger.info("[登录成功] - [{}]", username);
+// String username = request.getParameter("username");
+// httpServletResponse.setContentType("application/json;charset=UTF-8");
+// // 生成JWT,并放置到请求头中
+// String jwt = JwtUtils.createToken(authentication.getName(), );
+// httpServletResponse.setHeader(JwtUtils.getHeader(), jwt);
+// ServletOutputStream outputStream = httpServletResponse.getOutputStream();
+// outputStream.write(JSON.toJSONString(ErrorCode.SUCCESS).getBytes(StandardCharsets.UTF_8));
+// outputStream.flush();
+// outputStream.close();
+
+// logger.info("[登录成功] - [{}]", username);
}
}
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/SecurityUtils.java b/src/main/java/com/genersoft/iot/vmp/conf/security/SecurityUtils.java
index fd29d112..76f11620 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/security/SecurityUtils.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/security/SecurityUtils.java
@@ -1,6 +1,7 @@
package com.genersoft.iot.vmp.conf.security;
import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
+import com.genersoft.iot.vmp.storager.dao.dto.User;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
@@ -9,6 +10,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import javax.security.sasl.AuthenticationException;
+import java.time.LocalDateTime;
public class SecurityUtils {
@@ -25,10 +27,16 @@ public class SecurityUtils {
public static LoginUser login(String username, String password, AuthenticationManager authenticationManager) throws AuthenticationException {
//使用security框架自带的验证token生成器 也可以自定义。
UsernamePasswordAuthenticationToken token =new UsernamePasswordAuthenticationToken(username,password);
- Authentication authenticate = authenticationManager.authenticate(token);
- SecurityContextHolder.getContext().setAuthentication(authenticate);
- LoginUser user = (LoginUser) authenticate.getPrincipal();
- return user;
+// Authentication authenticate = authenticationManager.authenticate(token);
+// SecurityContextHolder.getContext().setAuthentication(authenticate);
+ SecurityContextHolder.getContext().setAuthentication(token);
+
+
+// LoginUser user = (LoginUser) authenticate.getPrincipal();
+ User user = new User();
+ user.setUsername(username);
+ LoginUser loginUser = new LoginUser(user, LocalDateTime.now());
+ return loginUser;
}
/**
@@ -49,8 +57,13 @@ public class SecurityUtils {
if(authentication!=null){
Object principal = authentication.getPrincipal();
if(principal!=null && !"anonymousUser".equals(principal)){
- LoginUser user = (LoginUser) authentication.getPrincipal();
- return user;
+// LoginUser user = (LoginUser) authentication.getPrincipal();
+
+ String username = (String) principal;
+ User user = new User();
+ user.setUsername(username);
+ LoginUser loginUser = new LoginUser(user, LocalDateTime.now());
+ return loginUser;
}
}
return null;
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java b/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
index cce0d11c..c700b8c1 100644
--- a/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
+++ b/src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
@@ -15,7 +15,9 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import java.util.List;
@@ -56,22 +58,14 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
*/
@Autowired
private AnonymousAuthenticationEntryPoint anonymousAuthenticationEntryPoint;
-// /**
-// * 超时处理
-// */
-// @Autowired
-// private InvalidSessionHandler invalidSessionHandler;
+ @Autowired
+ private JwtAuthenticationFilter jwtAuthenticationFilter;
-// /**
-// * 顶号处理
-// */
-// @Autowired
-// private SessionInformationExpiredHandler sessionInformationExpiredHandler;
-// /**
-// * 登录用户没有权限访问资源
-// */
-// @Autowired
-// private LoginUserAccessDeniedHandler accessDeniedHandler;
+// @Bean
+// JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {
+// JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(authenticationManager());
+// return jwtAuthenticationFilter;
+// }
/**
@@ -126,35 +120,56 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
- http.cors().and().csrf().disable();
- // 设置允许添加静态文件
- http.headers().contentTypeOptions().disable();
- http.authorizeRequests()
- // 放行接口
+ http.headers().contentTypeOptions().disable()
+ .and().cors()
+ .and().csrf().disable()
+ .sessionManagement()
+ .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+
+ // 配置拦截规则
+ .and()
+ .authorizeRequests()
.antMatchers("/api/user/login","/index/hook/**").permitAll()
- // 除上面外的所有请求全部需要鉴权认证
.anyRequest().authenticated()
- // 异常处理(权限拒绝、登录失效等)
- .and().exceptionHandling()
- //匿名用户访问无权限资源时的异常处理
+ // 异常处理器
+ .and()
+ .exceptionHandling()
.authenticationEntryPoint(anonymousAuthenticationEntryPoint)
-// .accessDeniedHandler(accessDeniedHandler)//登录用户没有权限访问资源
- // 登入 允许所有用户
- .and().formLogin().permitAll()
- //登录成功处理逻辑
- .successHandler(loginSuccessHandler)
- //登录失败处理逻辑
- .failureHandler(loginFailureHandler)
- // 登出
- .and().logout().logoutUrl("/api/user/logout").permitAll()
- //登出成功处理逻辑
- .logoutSuccessHandler(logoutHandler)
- .deleteCookies("JSESSIONID")
- // 会话管理
-// .and().sessionManagement().invalidSessionStrategy(invalidSessionHandler) // 超时处理
-// .maximumSessions(1)//同一账号同时登录最大用户数
-// .expiredSessionStrategy(sessionInformationExpiredHandler) // 顶号处理
+// .accessDeniedHandler(jwtAccessDeniedHandler)
+ // 配置自定义的过滤器
+// .and()
+// .addFilter(jwtAuthenticationFilter)
+ // 验证码过滤器放在UsernamePassword过滤器之前
+// .addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class)
;
+ http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
+// // 设置允许添加静态文件
+// http.headers().contentTypeOptions().disable();
+// http.authorizeRequests()
+// // 放行接口
+// .antMatchers("/api/user/login","/index/hook/**").permitAll()
+// // 除上面外的所有请求全部需要鉴权认证
+// .anyRequest().authenticated()
+// // 禁用session
+// .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+// // 异常处理(权限拒绝、登录失效等)
+// .and().exceptionHandling()
+// // 匿名用户访问无权限资源时的异常处理
+// .authenticationEntryPoint(anonymousAuthenticationEntryPoint)
+// // 登录 允许所有用户
+// .and().formLogin()
+// // 登录成功处理逻辑 在这里给出JWT
+// .successHandler(loginSuccessHandler)
+// // 登录失败处理逻辑
+// .failureHandler(loginFailureHandler)
+// // 登出
+// .and().logout().logoutUrl("/api/user/logout").permitAll()
+// // 登出成功处理逻辑
+// .logoutSuccessHandler(logoutHandler)
+// // 配置自定义的过滤器
+// .and()
+// .addFilter(jwtAuthenticationFilter())
+// ;
}
diff --git a/src/main/java/com/genersoft/iot/vmp/conf/security/dto/JwtUser.java b/src/main/java/com/genersoft/iot/vmp/conf/security/dto/JwtUser.java
new file mode 100644
index 00000000..1639d1fc
--- /dev/null
+++ b/src/main/java/com/genersoft/iot/vmp/conf/security/dto/JwtUser.java
@@ -0,0 +1,53 @@
+package com.genersoft.iot.vmp.conf.security.dto;
+
+public class JwtUser {
+
+ public enum TokenStatus{
+ /**
+ * 正常的使用状态
+ */
+ NORMAL,
+ /**
+ * 过期而失效
+ */
+ EXPIRED,
+ /**
+ * 即将过期
+ */
+ EXPIRING_SOON,
+ /**
+ * 异常
+ */
+ EXCEPTION
+ }
+
+ private String userName;
+
+ private String password;
+
+ private TokenStatus status;
+
+ public String getUserName() {
+ return userName;
+ }
+
+ public void setUserName(String userName) {
+ this.userName = userName;
+ }
+
+ public TokenStatus getStatus() {
+ return status;
+ }
+
+ public void setStatus(TokenStatus status) {
+ this.status = status;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+}
diff --git a/src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java b/src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java
index 127e83b8..826dd51e 100644
--- a/src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java
+++ b/src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java
@@ -1,6 +1,7 @@
package com.genersoft.iot.vmp.vmanager.user;
import com.genersoft.iot.vmp.conf.exception.ControllerException;
+import com.genersoft.iot.vmp.conf.security.JwtUtils;
import com.genersoft.iot.vmp.conf.security.SecurityUtils;
import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
import com.genersoft.iot.vmp.service.IRoleService;
@@ -21,6 +22,8 @@ import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;
import javax.security.sasl.AuthenticationException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
import java.util.List;
@Tag(name = "用户管理")
@@ -43,7 +46,7 @@ public class UserController {
@Operation(summary = "登录")
@Parameter(name = "username", description = "用户名", required = true)
@Parameter(name = "password", description = "密码(32位md5加密)", required = true)
- public LoginUser login(@RequestParam String username, @RequestParam String password){
+ public LoginUser login(HttpServletRequest request, HttpServletResponse response, @RequestParam String username, @RequestParam String password){
LoginUser user = null;
try {
user = SecurityUtils.login(username, password, authenticationManager);
@@ -52,6 +55,9 @@ public class UserController {
}
if (user == null) {
throw new ControllerException(ErrorCode.ERROR100.getCode(), "用户名或密码错误");
+ }else {
+ String jwt = JwtUtils.createToken(username, password);
+ response.setHeader(JwtUtils.getHeader(), jwt);
}
return user;
}