Commit 95688e400b6974953505c159f8fbf9d65784c724

Authored by 648540858
1 parent ec90519c

初步实现登录返回token

... ... @@ -216,8 +216,6 @@
216 216 <version>4.10.0</version>
217 217 </dependency>
218 218  
219   -
220   -
221 219 <!-- okhttp-digest -->
222 220 <dependency>
223 221 <groupId>io.github.rburgst</groupId>
... ... @@ -226,10 +224,17 @@
226 224 </dependency>
227 225  
228 226 <!-- https://mvnrepository.com/artifact/net.sf.kxml/kxml2 -->
  227 +<!-- <dependency>-->
  228 +<!-- <groupId>net.sf.kxml</groupId>-->
  229 +<!-- <artifactId>kxml2</artifactId>-->
  230 +<!-- <version>2.3.0</version>-->
  231 +<!-- </dependency>-->
  232 +
  233 + <!-- jwt实现 -->
229 234 <dependency>
230   - <groupId>net.sf.kxml</groupId>
231   - <artifactId>kxml2</artifactId>
232   - <version>2.3.0</version>
  235 + <groupId>org.bitbucket.b_c</groupId>
  236 + <artifactId>jose4j</artifactId>
  237 + <version>0.9.3</version>
233 238 </dependency>
234 239  
235 240 <!--反向代理-->
... ...
src/main/java/com/genersoft/iot/vmp/conf/security/AnonymousAuthenticationEntryPoint.java
1 1 package com.genersoft.iot.vmp.conf.security;
2 2  
3 3 import com.alibaba.fastjson2.JSONObject;
  4 +import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
4 5 import com.genersoft.iot.vmp.vmanager.bean.ErrorCode;
5   -import org.slf4j.Logger;
6   -import org.slf4j.LoggerFactory;
  6 +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
7 7 import org.springframework.security.core.AuthenticationException;
  8 +import org.springframework.security.core.context.SecurityContextHolder;
8 9 import org.springframework.security.web.AuthenticationEntryPoint;
9 10 import org.springframework.stereotype.Component;
10 11  
... ... @@ -17,12 +18,17 @@ import java.io.IOException;
17 18 * @author lin
18 19 */
19 20 @Component
20   -public class AnonymousAuthenticationEntryPoint implements AuthenticationEntryPoint {
21   -
22   - private final static Logger logger = LoggerFactory.getLogger(DefaultUserDetailsServiceImpl.class);
  21 +public class AnonymousAuthenticationEntryPoint implements AuthenticationEntryPoint {
23 22  
24 23 @Override
25 24 public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) {
  25 + System.err.println(e.getMessage());
  26 + String jwt = request.getHeader(JwtUtils.getHeader());
  27 + JwtUser jwtUser = JwtUtils.verifyToken(jwt);
  28 + String username = jwtUser.getUserName();
  29 + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, jwtUser.getPassword() );
  30 + SecurityContextHolder.getContext().setAuthentication(token);
  31 + System.out.println(jwt);
26 32 // 允许跨域
27 33 String origin = request.getHeader("Origin");
28 34 response.setHeader("Access-Control-Allow-Credentials", "true");
... ...
src/main/java/com/genersoft/iot/vmp/conf/security/DefaultUserDetailsServiceImpl.java
1 1 package com.genersoft.iot.vmp.conf.security;
2 2  
3   -import java.time.LocalDateTime;
4   -
  3 +import com.alibaba.excel.util.StringUtils;
  4 +import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
  5 +import com.genersoft.iot.vmp.service.IUserService;
  6 +import com.genersoft.iot.vmp.storager.dao.dto.User;
5 7 import org.slf4j.Logger;
6 8 import org.slf4j.LoggerFactory;
7 9 import org.springframework.beans.factory.annotation.Autowired;
... ... @@ -10,10 +12,7 @@ import org.springframework.security.core.userdetails.UserDetailsService;
10 12 import org.springframework.security.core.userdetails.UsernameNotFoundException;
11 13 import org.springframework.stereotype.Component;
12 14  
13   -import com.alibaba.excel.util.StringUtils;
14   -import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
15   -import com.genersoft.iot.vmp.service.IUserService;
16   -import com.genersoft.iot.vmp.storager.dao.dto.User;
  15 +import java.time.LocalDateTime;
17 16  
18 17 /**
19 18 * 用户登录认证逻辑
... ... @@ -45,4 +44,8 @@ public class DefaultUserDetailsServiceImpl implements UserDetailsService {
45 44 }
46 45  
47 46  
  47 +
  48 +
  49 +
  50 +
48 51 }
... ...
src/main/java/com/genersoft/iot/vmp/conf/security/InvalidSessionHandler.java deleted 100644 → 0
1   -package com.genersoft.iot.vmp.conf.security;
2   -
3   -import org.slf4j.Logger;
4   -import org.slf4j.LoggerFactory;
5   -import org.springframework.security.web.session.InvalidSessionStrategy;
6   -
7   -import javax.servlet.ServletException;
8   -import javax.servlet.http.HttpServletRequest;
9   -import javax.servlet.http.HttpServletResponse;
10   -import java.io.IOException;
11   -
12   -/**
13   - * 登录超时的处理
14   - */
15   -public class InvalidSessionHandler implements InvalidSessionStrategy {
16   -
17   - private final static Logger logger = LoggerFactory.getLogger(InvalidSessionHandler.class);
18   -
19   - @Override
20   - public void onInvalidSessionDetected(HttpServletRequest request, HttpServletResponse httpServletResponse) throws IOException, ServletException {
21   - String username = request.getParameter("username");
22   - logger.info("[登录超时] - [{}]", username);
23   - }
24   -}
src/main/java/com/genersoft/iot/vmp/conf/security/JwtAuthenticationFilter.java 0 → 100644
  1 +package com.genersoft.iot.vmp.conf.security;
  2 +
  3 +import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
  4 +import org.apache.commons.lang3.StringUtils;
  5 +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
  6 +import org.springframework.security.core.context.SecurityContextHolder;
  7 +import org.springframework.stereotype.Component;
  8 +import org.springframework.web.filter.OncePerRequestFilter;
  9 +
  10 +import javax.servlet.FilterChain;
  11 +import javax.servlet.ServletException;
  12 +import javax.servlet.http.HttpServletRequest;
  13 +import javax.servlet.http.HttpServletResponse;
  14 +import java.io.IOException;
  15 +import java.util.ArrayList;
  16 +
  17 +/**
  18 + * jwt token 过滤器
  19 + */
  20 +
  21 +@Component
  22 +public class JwtAuthenticationFilter extends OncePerRequestFilter {
  23 +
  24 +
  25 + @Override
  26 + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
  27 + String jwt = request.getHeader(JwtUtils.getHeader());
  28 + // 这里如果没有jwt,继续往后走,因为后面还有鉴权管理器等去判断是否拥有身份凭证,所以是可以放行的
  29 + // 没有jwt相当于匿名访问,若有一些接口是需要权限的,则不能访问这些接口
  30 + if (StringUtils.isBlank(jwt)) {
  31 + chain.doFilter(request, response);
  32 + return;
  33 + }
  34 +
  35 +
  36 + JwtUser jwtUser = JwtUtils.verifyToken(jwt);
  37 + String username = jwtUser.getUserName();
  38 + // TODO 处理各个状态
  39 + switch (jwtUser.getStatus()){
  40 + case EXPIRED:
  41 + response.setStatus(400);
  42 + chain.doFilter(request, response);
  43 + // 异常
  44 + return;
  45 + case EXCEPTION:
  46 + // 过期
  47 + response.setStatus(400);
  48 + chain.doFilter(request, response);
  49 + return;
  50 + case EXPIRING_SOON:
  51 + // 即将过期
  52 +// return;
  53 + default:
  54 + }
  55 +
  56 +// String password = SecurityUtils.encryptPassword(jwtUser.getPassword());
  57 +// user.setPassword(password);
  58 +
  59 + // 构建UsernamePasswordAuthenticationToken,这里密码为null,是因为提供了正确的JWT,实现自动登录
  60 + UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, jwtUser.getPassword(), new ArrayList<>() );
  61 + SecurityContextHolder.getContext().setAuthentication(token);
  62 + chain.doFilter(request, response);
  63 + }
  64 +
  65 +}
... ...
src/main/java/com/genersoft/iot/vmp/conf/security/JwtUtils.java 0 → 100644
  1 +package com.genersoft.iot.vmp.conf.security;
  2 +
  3 +import com.genersoft.iot.vmp.conf.security.dto.JwtUser;
  4 +import org.jose4j.json.JsonUtil;
  5 +import org.jose4j.jwk.RsaJsonWebKey;
  6 +import org.jose4j.jws.AlgorithmIdentifiers;
  7 +import org.jose4j.jws.JsonWebSignature;
  8 +import org.jose4j.jwt.JwtClaims;
  9 +import org.jose4j.jwt.NumericDate;
  10 +import org.jose4j.jwt.consumer.ErrorCodes;
  11 +import org.jose4j.jwt.consumer.InvalidJwtException;
  12 +import org.jose4j.jwt.consumer.JwtConsumer;
  13 +import org.jose4j.jwt.consumer.JwtConsumerBuilder;
  14 +import org.jose4j.lang.JoseException;
  15 +import org.slf4j.Logger;
  16 +import org.slf4j.LoggerFactory;
  17 +
  18 +import java.security.PrivateKey;
  19 +import java.time.LocalDateTime;
  20 +import java.time.ZoneOffset;
  21 +
  22 +public class JwtUtils {
  23 +
  24 + private static final Logger logger = LoggerFactory.getLogger(JwtUtils.class);
  25 +
  26 + private static final String HEADER = "Access-Token";
  27 + private static final String AUDIENCE = "Audience";
  28 +
  29 + private static final long EXPIRED_THRESHOLD = 10 * 60;
  30 +
  31 + private static final String keyId = "3e79646c4dbc408383a9eed09f2b85ae";
  32 + 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\"}";
  33 + 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\"}";
  34 +
  35 + /**
  36 + * token过期时间(分钟)
  37 + */
  38 + public static final long expirationTime = 30;
  39 +
  40 + public static String createToken(String username, String password) {
  41 + try {
  42 + /**
  43 + * “iss” (issuer) 发行人
  44 + *
  45 + * “sub” (subject) 主题
  46 + *
  47 + * “aud” (audience) 接收方 用户
  48 + *
  49 + * “exp” (expiration time) 到期时间
  50 + *
  51 + * “nbf” (not before) 在此之前不可用
  52 + *
  53 + * “iat” (issued at) jwt的签发时间
  54 + */
  55 + //Payload
  56 + JwtClaims claims = new JwtClaims();
  57 + claims.setGeneratedJwtId();
  58 + claims.setIssuedAtToNow();
  59 + // 令牌将过期的时间 分钟
  60 + claims.setExpirationTimeMinutesInTheFuture(expirationTime);
  61 + claims.setNotBeforeMinutesInThePast(0);
  62 + claims.setSubject("login");
  63 + claims.setAudience(AUDIENCE);
  64 + //添加自定义参数,必须是字符串类型
  65 + claims.setClaim("username", username);
  66 + claims.setClaim("password", password);
  67 +
  68 + //jws
  69 + JsonWebSignature jws = new JsonWebSignature();
  70 + //签名算法RS256
  71 + jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
  72 + jws.setKeyIdHeaderValue(keyId);
  73 + jws.setPayload(claims.toJson());
  74 +
  75 + PrivateKey privateKey = new RsaJsonWebKey(JsonUtil.parseJson(privateKeyStr)).getPrivateKey();
  76 + jws.setKey(privateKey);
  77 +
  78 + //get token
  79 + String idToken = jws.getCompactSerialization();
  80 + return idToken;
  81 + } catch (JoseException e) {
  82 + logger.error("[Token生成失败]: {}", e.getMessage());
  83 + }
  84 +
  85 + return null;
  86 + }
  87 +
  88 + public static String getHeader() {
  89 + return HEADER;
  90 + }
  91 +
  92 +
  93 + public static JwtUser verifyToken(String token) {
  94 +
  95 + JwtUser jwtUser = new JwtUser();
  96 +
  97 + try {
  98 + JwtConsumer consumer = new JwtConsumerBuilder()
  99 + .setRequireExpirationTime()
  100 + .setMaxFutureValidityInMinutes(5256000)
  101 + .setAllowedClockSkewInSeconds(30)
  102 + .setRequireSubject()
  103 + //.setExpectedIssuer("")
  104 + .setExpectedAudience(AUDIENCE)
  105 + .setVerificationKey(new RsaJsonWebKey(JsonUtil.parseJson(publicKeyStr)).getPublicKey())
  106 + .build();
  107 +
  108 + JwtClaims claims = consumer.processToClaims(token);
  109 + NumericDate expirationTime = claims.getExpirationTime();
  110 + // 判断是否即将过期, 默认剩余时间小于5分钟未即将过期
  111 + // 剩余时间 (秒)
  112 + long timeRemaining = LocalDateTime.now().toEpochSecond(ZoneOffset.ofHours(8)) - expirationTime.getValue();
  113 + if (timeRemaining < 5 * 60) {
  114 + jwtUser.setStatus(JwtUser.TokenStatus.EXPIRING_SOON);
  115 + }else {
  116 + jwtUser.setStatus(JwtUser.TokenStatus.NORMAL);
  117 + }
  118 +
  119 + String username = (String) claims.getClaimValue("username");
  120 + String password = (String) claims.getClaimValue("password");
  121 + jwtUser.setUserName(username);
  122 + jwtUser.setPassword(password);
  123 +
  124 + return jwtUser;
  125 + } catch (InvalidJwtException e) {
  126 + if (e.hasErrorCode(ErrorCodes.EXPIRED)) {
  127 + jwtUser.setStatus(JwtUser.TokenStatus.EXPIRED);
  128 + }else {
  129 + jwtUser.setStatus(JwtUser.TokenStatus.EXCEPTION);
  130 + }
  131 + return jwtUser;
  132 + }catch (Exception e) {
  133 + logger.error("[Token解析失败]: {}", e.getMessage());
  134 + jwtUser.setStatus(JwtUser.TokenStatus.EXPIRED);
  135 + return jwtUser;
  136 + }
  137 + }
  138 +}
... ...
src/main/java/com/genersoft/iot/vmp/conf/security/LoginSuccessHandler.java
... ... @@ -21,7 +21,16 @@ public class LoginSuccessHandler implements AuthenticationSuccessHandler {
21 21  
22 22 @Override
23 23 public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
24   - String username = request.getParameter("username");
25   - logger.info("[登录成功] - [{}]", username);
  24 +// String username = request.getParameter("username");
  25 +// httpServletResponse.setContentType("application/json;charset=UTF-8");
  26 +// // 生成JWT,并放置到请求头中
  27 +// String jwt = JwtUtils.createToken(authentication.getName(), );
  28 +// httpServletResponse.setHeader(JwtUtils.getHeader(), jwt);
  29 +// ServletOutputStream outputStream = httpServletResponse.getOutputStream();
  30 +// outputStream.write(JSON.toJSONString(ErrorCode.SUCCESS).getBytes(StandardCharsets.UTF_8));
  31 +// outputStream.flush();
  32 +// outputStream.close();
  33 +
  34 +// logger.info("[登录成功] - [{}]", username);
26 35 }
27 36 }
... ...
src/main/java/com/genersoft/iot/vmp/conf/security/SecurityUtils.java
1 1 package com.genersoft.iot.vmp.conf.security;
2 2  
3 3 import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
  4 +import com.genersoft.iot.vmp.storager.dao.dto.User;
4 5 import org.springframework.security.authentication.AuthenticationManager;
5 6 import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
6 7 import org.springframework.security.core.Authentication;
... ... @@ -9,6 +10,7 @@ import org.springframework.security.core.context.SecurityContextHolder;
9 10 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
10 11  
11 12 import javax.security.sasl.AuthenticationException;
  13 +import java.time.LocalDateTime;
12 14  
13 15 public class SecurityUtils {
14 16  
... ... @@ -25,10 +27,16 @@ public class SecurityUtils {
25 27 public static LoginUser login(String username, String password, AuthenticationManager authenticationManager) throws AuthenticationException {
26 28 //使用security框架自带的验证token生成器 也可以自定义。
27 29 UsernamePasswordAuthenticationToken token =new UsernamePasswordAuthenticationToken(username,password);
28   - Authentication authenticate = authenticationManager.authenticate(token);
29   - SecurityContextHolder.getContext().setAuthentication(authenticate);
30   - LoginUser user = (LoginUser) authenticate.getPrincipal();
31   - return user;
  30 +// Authentication authenticate = authenticationManager.authenticate(token);
  31 +// SecurityContextHolder.getContext().setAuthentication(authenticate);
  32 + SecurityContextHolder.getContext().setAuthentication(token);
  33 +
  34 +
  35 +// LoginUser user = (LoginUser) authenticate.getPrincipal();
  36 + User user = new User();
  37 + user.setUsername(username);
  38 + LoginUser loginUser = new LoginUser(user, LocalDateTime.now());
  39 + return loginUser;
32 40 }
33 41  
34 42 /**
... ... @@ -49,8 +57,13 @@ public class SecurityUtils {
49 57 if(authentication!=null){
50 58 Object principal = authentication.getPrincipal();
51 59 if(principal!=null && !"anonymousUser".equals(principal)){
52   - LoginUser user = (LoginUser) authentication.getPrincipal();
53   - return user;
  60 +// LoginUser user = (LoginUser) authentication.getPrincipal();
  61 +
  62 + String username = (String) principal;
  63 + User user = new User();
  64 + user.setUsername(username);
  65 + LoginUser loginUser = new LoginUser(user, LocalDateTime.now());
  66 + return loginUser;
54 67 }
55 68 }
56 69 return null;
... ...
src/main/java/com/genersoft/iot/vmp/conf/security/WebSecurityConfig.java
... ... @@ -15,7 +15,9 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
15 15 import org.springframework.security.config.annotation.web.builders.WebSecurity;
16 16 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
17 17 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  18 +import org.springframework.security.config.http.SessionCreationPolicy;
18 19 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  20 +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
19 21  
20 22 import java.util.List;
21 23  
... ... @@ -56,22 +58,14 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
56 58 */
57 59 @Autowired
58 60 private AnonymousAuthenticationEntryPoint anonymousAuthenticationEntryPoint;
59   -// /**
60   -// * 超时处理
61   -// */
62   -// @Autowired
63   -// private InvalidSessionHandler invalidSessionHandler;
64   -
65   -// /**
66   -// * 顶号处理
67   -// */
68   -// @Autowired
69   -// private SessionInformationExpiredHandler sessionInformationExpiredHandler;
70   -// /**
71   -// * 登录用户没有权限访问资源
72   -// */
73   -// @Autowired
74   -// private LoginUserAccessDeniedHandler accessDeniedHandler;
  61 + @Autowired
  62 + private JwtAuthenticationFilter jwtAuthenticationFilter;
  63 +
  64 +// @Bean
  65 +// JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {
  66 +// JwtAuthenticationFilter jwtAuthenticationFilter = new JwtAuthenticationFilter(authenticationManager());
  67 +// return jwtAuthenticationFilter;
  68 +// }
75 69  
76 70  
77 71 /**
... ... @@ -126,35 +120,56 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
126 120  
127 121 @Override
128 122 protected void configure(HttpSecurity http) throws Exception {
129   - http.cors().and().csrf().disable();
130   - // 设置允许添加静态文件
131   - http.headers().contentTypeOptions().disable();
132   - http.authorizeRequests()
133   - // 放行接口
  123 + http.headers().contentTypeOptions().disable()
  124 + .and().cors()
  125 + .and().csrf().disable()
  126 + .sessionManagement()
  127 + .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
  128 +
  129 + // 配置拦截规则
  130 + .and()
  131 + .authorizeRequests()
134 132 .antMatchers("/api/user/login","/index/hook/**").permitAll()
135   - // 除上面外的所有请求全部需要鉴权认证
136 133 .anyRequest().authenticated()
137   - // 异常处理(权限拒绝、登录失效等)
138   - .and().exceptionHandling()
139   - //匿名用户访问无权限资源时的异常处理
  134 + // 异常处理器
  135 + .and()
  136 + .exceptionHandling()
140 137 .authenticationEntryPoint(anonymousAuthenticationEntryPoint)
141   -// .accessDeniedHandler(accessDeniedHandler)//登录用户没有权限访问资源
142   - // 登入 允许所有用户
143   - .and().formLogin().permitAll()
144   - //登录成功处理逻辑
145   - .successHandler(loginSuccessHandler)
146   - //登录失败处理逻辑
147   - .failureHandler(loginFailureHandler)
148   - // 登出
149   - .and().logout().logoutUrl("/api/user/logout").permitAll()
150   - //登出成功处理逻辑
151   - .logoutSuccessHandler(logoutHandler)
152   - .deleteCookies("JSESSIONID")
153   - // 会话管理
154   -// .and().sessionManagement().invalidSessionStrategy(invalidSessionHandler) // 超时处理
155   -// .maximumSessions(1)//同一账号同时登录最大用户数
156   -// .expiredSessionStrategy(sessionInformationExpiredHandler) // 顶号处理
  138 +// .accessDeniedHandler(jwtAccessDeniedHandler)
  139 + // 配置自定义的过滤器
  140 +// .and()
  141 +// .addFilter(jwtAuthenticationFilter)
  142 + // 验证码过滤器放在UsernamePassword过滤器之前
  143 +// .addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class)
157 144 ;
  145 + http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
  146 +// // 设置允许添加静态文件
  147 +// http.headers().contentTypeOptions().disable();
  148 +// http.authorizeRequests()
  149 +// // 放行接口
  150 +// .antMatchers("/api/user/login","/index/hook/**").permitAll()
  151 +// // 除上面外的所有请求全部需要鉴权认证
  152 +// .anyRequest().authenticated()
  153 +// // 禁用session
  154 +// .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
  155 +// // 异常处理(权限拒绝、登录失效等)
  156 +// .and().exceptionHandling()
  157 +// // 匿名用户访问无权限资源时的异常处理
  158 +// .authenticationEntryPoint(anonymousAuthenticationEntryPoint)
  159 +// // 登录 允许所有用户
  160 +// .and().formLogin()
  161 +// // 登录成功处理逻辑 在这里给出JWT
  162 +// .successHandler(loginSuccessHandler)
  163 +// // 登录失败处理逻辑
  164 +// .failureHandler(loginFailureHandler)
  165 +// // 登出
  166 +// .and().logout().logoutUrl("/api/user/logout").permitAll()
  167 +// // 登出成功处理逻辑
  168 +// .logoutSuccessHandler(logoutHandler)
  169 +// // 配置自定义的过滤器
  170 +// .and()
  171 +// .addFilter(jwtAuthenticationFilter())
  172 +// ;
158 173  
159 174 }
160 175  
... ...
src/main/java/com/genersoft/iot/vmp/conf/security/dto/JwtUser.java 0 → 100644
  1 +package com.genersoft.iot.vmp.conf.security.dto;
  2 +
  3 +public class JwtUser {
  4 +
  5 + public enum TokenStatus{
  6 + /**
  7 + * 正常的使用状态
  8 + */
  9 + NORMAL,
  10 + /**
  11 + * 过期而失效
  12 + */
  13 + EXPIRED,
  14 + /**
  15 + * 即将过期
  16 + */
  17 + EXPIRING_SOON,
  18 + /**
  19 + * 异常
  20 + */
  21 + EXCEPTION
  22 + }
  23 +
  24 + private String userName;
  25 +
  26 + private String password;
  27 +
  28 + private TokenStatus status;
  29 +
  30 + public String getUserName() {
  31 + return userName;
  32 + }
  33 +
  34 + public void setUserName(String userName) {
  35 + this.userName = userName;
  36 + }
  37 +
  38 + public TokenStatus getStatus() {
  39 + return status;
  40 + }
  41 +
  42 + public void setStatus(TokenStatus status) {
  43 + this.status = status;
  44 + }
  45 +
  46 + public String getPassword() {
  47 + return password;
  48 + }
  49 +
  50 + public void setPassword(String password) {
  51 + this.password = password;
  52 + }
  53 +}
... ...
src/main/java/com/genersoft/iot/vmp/vmanager/user/UserController.java
1 1 package com.genersoft.iot.vmp.vmanager.user;
2 2  
3 3 import com.genersoft.iot.vmp.conf.exception.ControllerException;
  4 +import com.genersoft.iot.vmp.conf.security.JwtUtils;
4 5 import com.genersoft.iot.vmp.conf.security.SecurityUtils;
5 6 import com.genersoft.iot.vmp.conf.security.dto.LoginUser;
6 7 import com.genersoft.iot.vmp.service.IRoleService;
... ... @@ -21,6 +22,8 @@ import org.springframework.util.ObjectUtils;
21 22 import org.springframework.web.bind.annotation.*;
22 23  
23 24 import javax.security.sasl.AuthenticationException;
  25 +import javax.servlet.http.HttpServletRequest;
  26 +import javax.servlet.http.HttpServletResponse;
24 27 import java.util.List;
25 28  
26 29 @Tag(name = "用户管理")
... ... @@ -43,7 +46,7 @@ public class UserController {
43 46 @Operation(summary = "登录")
44 47 @Parameter(name = "username", description = "用户名", required = true)
45 48 @Parameter(name = "password", description = "密码(32位md5加密)", required = true)
46   - public LoginUser login(@RequestParam String username, @RequestParam String password){
  49 + public LoginUser login(HttpServletRequest request, HttpServletResponse response, @RequestParam String username, @RequestParam String password){
47 50 LoginUser user = null;
48 51 try {
49 52 user = SecurityUtils.login(username, password, authenticationManager);
... ... @@ -52,6 +55,9 @@ public class UserController {
52 55 }
53 56 if (user == null) {
54 57 throw new ControllerException(ErrorCode.ERROR100.getCode(), "用户名或密码错误");
  58 + }else {
  59 + String jwt = JwtUtils.createToken(username, password);
  60 + response.setHeader(JwtUtils.getHeader(), jwt);
55 61 }
56 62 return user;
57 63 }
... ...