From a37a3fb1f498c23c2361e7274aba1a24f6627d06 Mon Sep 17 00:00:00 2001 From: 邓敏 Date: Sun, 11 May 2025 17:32:10 +0800 Subject: [PATCH] Security --- pom.xml | 23 +++++++++++------------ src/main/java/com/zhongzhi/common/configure/SecurityConfig.java | 91 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/com/zhongzhi/common/constant/PDFCheckBox.java | 84 ------------------------------------------------------------------------------------ src/main/java/com/zhongzhi/common/constant/ProjectProgress.java | 9 --------- src/main/java/com/zhongzhi/common/interceptor/JwtAuthenticationEntryPoint.java | 36 ++++++++++++++++++++++++++++++++++++ src/main/java/com/zhongzhi/common/interceptor/JwtAuthenticationTokenFilter.java | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/main/java/com/zhongzhi/common/interceptor/RestAuthenticationAccessDeniedHandler.java | 34 ++++++++++++++++++++++++++++++++++ src/main/java/com/zhongzhi/common/utils/EncryptUtil.java | 45 +++++++++++++++++++++++++++++++++++++++++++++ src/main/java/com/zhongzhi/common/utils/JwtUtil.java | 9 ++++----- src/main/java/com/zhongzhi/common/utils/Localstorage.java | 24 +++++++++--------------- src/main/java/com/zhongzhi/common/utils/PDFUtil.java | 9 --------- src/main/java/com/zhongzhi/controller/AuthController.java | 37 +++++++++++++++++++++++++++++++++++++ src/main/java/com/zhongzhi/dao/UserMapper.java | 8 ++++++++ src/main/java/com/zhongzhi/dto/UserDTO.java | 11 +++++++++++ src/main/java/com/zhongzhi/model/base/UserModel.java | 43 +++++++++++++++++++++++++++++++++++++++++++ src/main/java/com/zhongzhi/service/UserService.java | 12 ++++++++++++ src/main/java/com/zhongzhi/service/impl/UserServiceImpl.java | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 17 files changed, 460 insertions(+), 134 deletions(-) create mode 100644 src/main/java/com/zhongzhi/common/configure/SecurityConfig.java delete mode 100644 src/main/java/com/zhongzhi/common/constant/PDFCheckBox.java delete mode 100644 src/main/java/com/zhongzhi/common/constant/ProjectProgress.java create mode 100644 src/main/java/com/zhongzhi/common/interceptor/JwtAuthenticationEntryPoint.java create mode 100644 src/main/java/com/zhongzhi/common/interceptor/JwtAuthenticationTokenFilter.java create mode 100644 src/main/java/com/zhongzhi/common/interceptor/RestAuthenticationAccessDeniedHandler.java create mode 100644 src/main/java/com/zhongzhi/common/utils/EncryptUtil.java create mode 100644 src/main/java/com/zhongzhi/controller/AuthController.java create mode 100644 src/main/java/com/zhongzhi/dao/UserMapper.java create mode 100644 src/main/java/com/zhongzhi/dto/UserDTO.java create mode 100644 src/main/java/com/zhongzhi/model/base/UserModel.java create mode 100644 src/main/java/com/zhongzhi/service/UserService.java create mode 100644 src/main/java/com/zhongzhi/service/impl/UserServiceImpl.java diff --git a/pom.xml b/pom.xml index d4df389..61a09ee 100644 --- a/pom.xml +++ b/pom.xml @@ -45,6 +45,11 @@ org.springframework.boot + spring-boot-starter-security + + + + org.springframework.boot spring-boot-starter-web @@ -135,18 +140,6 @@ - com.itextpdf - itext-asian - ${itext-asian.version} - - - - com.itextpdf - itextpdf - ${itextpdf.version} - - - com.auth0 java-jwt ${java-jwt.version} @@ -177,6 +170,12 @@ 4.5.13 + + com.amdelamar + jhash + 2.0.0 + + diff --git a/src/main/java/com/zhongzhi/common/configure/SecurityConfig.java b/src/main/java/com/zhongzhi/common/configure/SecurityConfig.java new file mode 100644 index 0000000..6b60dce --- /dev/null +++ b/src/main/java/com/zhongzhi/common/configure/SecurityConfig.java @@ -0,0 +1,91 @@ +package com.zhongzhi.common.configure; + +import com.zhongzhi.common.interceptor.JwtAuthenticationEntryPoint; +import com.zhongzhi.common.interceptor.JwtAuthenticationTokenFilter; +import com.zhongzhi.common.utils.EncryptUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +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.core.userdetails.UserDetailsService; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; + +/** + * @description: security ConfigurerAdapter + * @author DengMin + * @date 2025/5/8 15:30 + * @version 1.0 + */ +@Configuration +@EnableWebSecurity +public class SecurityConfig extends WebSecurityConfigurerAdapter { + + @Autowired + private UserDetailsService userDetailsService; + + @Autowired + @Qualifier("RestAuthenticationAccessDeniedHandler") + private AccessDeniedHandler accessDeniedHandler; + + @Autowired + private JwtAuthenticationEntryPoint unauthorizedHandler; + + + /** + * 配置加密方式(security 不支持明文验证方式) + * @param auth + * @throws Exception + */ + @Override + protected void configure(AuthenticationManagerBuilder auth) throws Exception { + auth.userDetailsService(userDetailsService).passwordEncoder(new PasswordEncoder() { + @Override + public String encode(CharSequence rawPassword) { + return EncryptUtil.encrypt((String) rawPassword); + } + + @Override + public boolean matches(CharSequence charSequence, String s) { + return EncryptUtil.verify(s, charSequence.toString()); + } + }); + } + + @Override + protected void configure(HttpSecurity http) throws Exception { + http + .exceptionHandling().accessDeniedHandler(accessDeniedHandler) + .and() + .csrf().disable() + .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and() + .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .authorizeRequests() + .antMatchers(HttpMethod.POST, "/**").permitAll() + .antMatchers("/openApi/login", "/openApi/**").permitAll()//接口白名单配置 + .anyRequest().authenticated(); + + http.headers().cacheControl(); + http.addFilterBefore(authenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class); + } + + @Bean + public JwtAuthenticationTokenFilter authenticationTokenFilter() { + return new JwtAuthenticationTokenFilter(); + } + + @Bean + @Override + public AuthenticationManager authenticationManagerBean() throws Exception { + return super.authenticationManagerBean(); + } +} diff --git a/src/main/java/com/zhongzhi/common/constant/PDFCheckBox.java b/src/main/java/com/zhongzhi/common/constant/PDFCheckBox.java deleted file mode 100644 index d02ae14..0000000 --- a/src/main/java/com/zhongzhi/common/constant/PDFCheckBox.java +++ /dev/null @@ -1,84 +0,0 @@ -package com.zhongzhi.common.constant; - -import org.apache.commons.lang3.StringUtils; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -public class PDFCheckBox { - - public static String getType(String type, String projectGroup) { - if (StringUtils.isBlank(type) && - projectGroup.equals(ProjectType.TECHNOLOGY_INNOVATION_GROUP)) { - return "□方案设计类 □模型创意类 □虚拟演示类"; - } else if (StringUtils.isBlank(type) && - projectGroup.equals(ProjectType.CULTURAL_CREATIVE_GROUP)) { - return "□服装与服饰类设计 □视觉传达类 □产品设计类"; - } - - String[] typeT = {"方案设计类", "模型创意类", "虚拟演示类"}; - String typeValue = ""; - if (projectGroup.equals(ProjectType.TECHNOLOGY_INNOVATION_GROUP)) { - List typeList = Arrays.stream(typeT).collect(Collectors.toList()); - List str = Arrays.stream(type.split(",")).collect(Collectors.toList()); - for (String s : typeList) { - if (str.contains(s)) { - typeValue += "■" + s + " "; - } else { - typeValue += "□" + s + " "; - } - } - return typeValue; - } else if (projectGroup.equals(ProjectType.CULTURAL_CREATIVE_GROUP)) { - if (type.equals("服装与服饰类设计")) { - return "■服装与服饰类设计 □视觉传达类 □产品设计类"; - } else if (type.equals("视觉传达类")) { - return "□服装与服饰类设计 ■视觉传达类 □产品设计类"; - } else if (type.equals("产品设计类")) { - return "□服装与服饰类设计 □视觉传达类 ■产品设计类"; - } else { - return "□服装与服饰类设计 □视觉传达类 □产品设计类"; - } - } - return ""; - } - - public static String getRoadshow( String projectGroup) { - if (projectGroup.equals(ProjectType.TECHNOLOGY_INNOVATION_GROUP)) { - return "□模型展示 □数字化演示" + - " □PPT演示 □其他"; - } else if (projectGroup.equals(ProjectType.CULTURAL_CREATIVE_GROUP)) { - return "□物化产品展示 □作品模型展示" + - " □数字化演示 □PPT演示 □其他"; - } - - String[] roadshowT = {"模型展示", "数字化演示", "PPT演示", "其他"}; - String[] roadshowC = {"物化产品展示", "作品模型展示", "数字化演示", "PPT演示", "其他"}; - -// List str = Arrays.stream(roadshow.split(",")).collect(Collectors.toList()); - String roadshowValue = ""; - if (projectGroup.equals(ProjectType.TECHNOLOGY_INNOVATION_GROUP)) { - List roadshowTList = Arrays.stream(roadshowT).collect(Collectors.toList()); - for (String s : roadshowTList) { -// if (str.contains(s)) { -// roadshowValue += "■" + s + " "; -// } else { -// roadshowValue += "□" + s + " "; -// } - } - return roadshowValue; - } else if (projectGroup.equals(ProjectType.CULTURAL_CREATIVE_GROUP)) { - List roadshowCList = Arrays.stream(roadshowC).collect(Collectors.toList()); - for (String s : roadshowCList) { -// if (str.contains(s)) { -// roadshowValue += "■" + s + " "; -// } else { -// roadshowValue += "□" + s + " "; -// } - } - return roadshowValue; - } - return ""; - } -} diff --git a/src/main/java/com/zhongzhi/common/constant/ProjectProgress.java b/src/main/java/com/zhongzhi/common/constant/ProjectProgress.java deleted file mode 100644 index 12910d7..0000000 --- a/src/main/java/com/zhongzhi/common/constant/ProjectProgress.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.zhongzhi.common.constant; - -public class ProjectProgress { - - public static final String REGISTERED = "已注册公司"; - - public static final String UNREGISTERED = "创意设计阶段"; - -} diff --git a/src/main/java/com/zhongzhi/common/interceptor/JwtAuthenticationEntryPoint.java b/src/main/java/com/zhongzhi/common/interceptor/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..16ec3bb --- /dev/null +++ b/src/main/java/com/zhongzhi/common/interceptor/JwtAuthenticationEntryPoint.java @@ -0,0 +1,36 @@ +package com.zhongzhi.common.interceptor; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.zhongzhi.common.constant.Code; +import com.zhongzhi.common.utils.ResponseData; +import com.zhongzhi.vo.ResponseVO; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.Serializable; +import java.nio.charset.StandardCharsets; + +/** + * @description: 无权限访问 + * @author DengMin + * @date 2025/5/11 16:23 + * @version 1.0 + */ +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable { + + @Override + public void commence(HttpServletRequest request, + HttpServletResponse response, + AuthenticationException authException) throws IOException { + response.setStatus(200); + response.setCharacterEncoding(StandardCharsets.UTF_8.name()); + response.setContentType("application/json"); + ObjectMapper objectMapper = new ObjectMapper(); + ResponseVO responseVO = ResponseData.generateCreatedResponse(Code.ACCESSDENIED.getCode(), Code.ACCESSDENIED.getMessage(), null); + response.getWriter().write(objectMapper.writeValueAsString(responseVO)); + } +} diff --git a/src/main/java/com/zhongzhi/common/interceptor/JwtAuthenticationTokenFilter.java b/src/main/java/com/zhongzhi/common/interceptor/JwtAuthenticationTokenFilter.java new file mode 100644 index 0000000..caf76b4 --- /dev/null +++ b/src/main/java/com/zhongzhi/common/interceptor/JwtAuthenticationTokenFilter.java @@ -0,0 +1,62 @@ +package com.zhongzhi.common.interceptor; + +import com.auth0.jwt.interfaces.Claim; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.zhongzhi.common.utils.JwtUtil; +import com.zhongzhi.common.utils.Localstorage; +import com.zhongzhi.dao.UserMapper; +import com.zhongzhi.model.base.UserModel; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +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.Map; + +/** + * @description: Token令牌过滤器 + * @author DengMin + * @date 2025/5/11 16:23 + * @version 1.0 + */ +@Component +public class JwtAuthenticationTokenFilter extends OncePerRequestFilter { + + @Autowired + private UserMapper userMapper; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + String token = request.getHeader("Authorization"); + if (StringUtils.isNotEmpty(token)) { + if (token.startsWith("Bearer")) { + token = token.replace("Bearer ", ""); + } + + if (!JwtUtil.isExpired(token) && JwtUtil.verifyToken(token)) { + Map claimMap = JwtUtil.getClaims(token); + if(claimMap != null && SecurityContextHolder.getContext().getAuthentication() == null) { + UserModel userModel = userMapper.selectOne(new QueryWrapper() + .lambda() + .eq(UserModel::getUsername, claimMap.get("username").asString())); + if(userModel != null) { + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userModel, null, userModel.getAuthorities()); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authentication); + Localstorage.setUser(userModel); + } else { + Localstorage.remove(); + } + } + } + } + filterChain.doFilter(request, response); + } +} diff --git a/src/main/java/com/zhongzhi/common/interceptor/RestAuthenticationAccessDeniedHandler.java b/src/main/java/com/zhongzhi/common/interceptor/RestAuthenticationAccessDeniedHandler.java new file mode 100644 index 0000000..036720c --- /dev/null +++ b/src/main/java/com/zhongzhi/common/interceptor/RestAuthenticationAccessDeniedHandler.java @@ -0,0 +1,34 @@ +package com.zhongzhi.common.interceptor; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.zhongzhi.common.constant.Code; +import com.zhongzhi.common.utils.ResponseData; +import com.zhongzhi.vo.ResponseVO; +import org.springframework.security.access.AccessDeniedException; +import org.springframework.security.web.access.AccessDeniedHandler; +import org.springframework.stereotype.Component; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +/** + * @description: 身份验证异常 + * @author DengMin + * @date 2025/5/11 16:22 + * @version 1.0 + */ +@Component("RestAuthenticationAccessDeniedHandler") +public class RestAuthenticationAccessDeniedHandler implements AccessDeniedHandler { + + @Override + public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException { + response.setStatus(200); + response.setContentType("application/json"); + ObjectMapper objectMapper = new ObjectMapper(); + ResponseVO responseVO = ResponseData.generateCreatedResponse(Code.AUTHENTICATION.getCode(), Code.AUTHENTICATION.getMessage()); + response.setCharacterEncoding(StandardCharsets.UTF_8.name()); + response.getWriter().write(objectMapper.writeValueAsString(responseVO)); + } +} diff --git a/src/main/java/com/zhongzhi/common/utils/EncryptUtil.java b/src/main/java/com/zhongzhi/common/utils/EncryptUtil.java new file mode 100644 index 0000000..c19f936 --- /dev/null +++ b/src/main/java/com/zhongzhi/common/utils/EncryptUtil.java @@ -0,0 +1,45 @@ +package com.zhongzhi.common.utils; + +import com.amdelamar.jhash.Hash; +import com.amdelamar.jhash.algorithms.Type; +import com.amdelamar.jhash.exception.InvalidHashException; + +/** + * @description: 加密 + * @author DengMin + * @date 2025/5/11 16:19 + * @version 1.0 + */ +public class EncryptUtil { + + /** + * 设置密文密码 + * + * @param password 原始密码 + * @return 加密密码 + */ + public static String encrypt(String password) { + char[] chars = password.toCharArray(); + return Hash.password(chars).algorithm(Type.PBKDF2_SHA256).create(); + } + + /** + * 验证加密密码 + * + * @param encryptedPassword 密文密码 + * @param plainPassword 明文密码 + * @return 验证是否成功 + */ + public static boolean verify(String encryptedPassword, String plainPassword) { + char[] chars = plainPassword.toCharArray(); + try { + return Hash.password(chars).algorithm(Type.PBKDF2_SHA256).verify(encryptedPassword); + } catch (InvalidHashException e) { + return false; + } + } + + public static void main(String[] args) { + System.out.println(encrypt("123456")); + } +} diff --git a/src/main/java/com/zhongzhi/common/utils/JwtUtil.java b/src/main/java/com/zhongzhi/common/utils/JwtUtil.java index ffe78e5..e642445 100644 --- a/src/main/java/com/zhongzhi/common/utils/JwtUtil.java +++ b/src/main/java/com/zhongzhi/common/utils/JwtUtil.java @@ -4,6 +4,7 @@ import com.auth0.jwt.JWT; import com.auth0.jwt.JWTVerifier; import com.auth0.jwt.algorithms.Algorithm; import com.auth0.jwt.interfaces.Claim; +import org.springframework.security.core.userdetails.UserDetails; import java.util.Date; import java.util.Map; @@ -25,15 +26,13 @@ public class JwtUtil { /** * 生成Token * - * @param id + * @param userDetails * @return */ - public static String generateToken(Long id, String type) { + public static String generateToken(UserDetails userDetails) { Date expireDate = new Date(System.currentTimeMillis() + EXPIRE_TIME); return JWT.create() - .withClaim("id", id) - .withClaim("type", type) - .withAudience() + .withClaim("username", userDetails.getUsername()) .withExpiresAt(expireDate) .withIssuedAt(new Date()) .sign(Algorithm.HMAC256(SECRET)); diff --git a/src/main/java/com/zhongzhi/common/utils/Localstorage.java b/src/main/java/com/zhongzhi/common/utils/Localstorage.java index aee50ad..2fe3696 100644 --- a/src/main/java/com/zhongzhi/common/utils/Localstorage.java +++ b/src/main/java/com/zhongzhi/common/utils/Localstorage.java @@ -2,29 +2,23 @@ package com.zhongzhi.common.utils; import org.springframework.web.bind.annotation.RestController; -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - +/** + * @description: 登陆用户信息 + * @author DengMin + * @date 2025/5/11 16:29 + * @version 1.0 + */ @RestController public class Localstorage { private static final ThreadLocal local = ThreadLocal.withInitial(() -> null); - private static ConcurrentHashMap map = new ConcurrentHashMap<>(); - public static void setUser(Object obj, String type) { - Map map = new HashMap<>(); - map.put("user", obj); - map.put("type", type); - Localstorage.local.set(map); - } - public static Map getMap() { - return (Map) Localstorage.local.get(); + public static void setUser(Object obj) { + Localstorage.local.set(obj); } public static Object getUser() { - Map map = (Map) Localstorage.local.get(); - return map.get("user"); + return Localstorage.local.get(); } public static void remove() { diff --git a/src/main/java/com/zhongzhi/common/utils/PDFUtil.java b/src/main/java/com/zhongzhi/common/utils/PDFUtil.java index f23a440..70e91c6 100644 --- a/src/main/java/com/zhongzhi/common/utils/PDFUtil.java +++ b/src/main/java/com/zhongzhi/common/utils/PDFUtil.java @@ -2,12 +2,7 @@ package com.zhongzhi.common.utils; import com.itextpdf.text.*; import com.itextpdf.text.pdf.BaseFont; -import com.itextpdf.text.pdf.PdfPCell; import com.itextpdf.text.pdf.PdfPTable; -import com.itextpdf.text.pdf.PdfWriter; -import com.zhongzhi.common.constant.PDFCheckBox; -import com.zhongzhi.common.constant.ProjectType; -import com.zhongzhi.common.exception.HttpException; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -16,13 +11,9 @@ import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletResponse; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; @Slf4j @Component diff --git a/src/main/java/com/zhongzhi/controller/AuthController.java b/src/main/java/com/zhongzhi/controller/AuthController.java new file mode 100644 index 0000000..3be436d --- /dev/null +++ b/src/main/java/com/zhongzhi/controller/AuthController.java @@ -0,0 +1,37 @@ +package com.zhongzhi.controller; + +import com.zhongzhi.common.utils.ResponseData; +import com.zhongzhi.dto.UserDTO; +import com.zhongzhi.service.UserService; +import com.zhongzhi.vo.ResponseVO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +/** + * @description: 用户 + * @author DengMin + * @date 2025/5/11 16:32 + * @version 1.0 + */ + +@RestController +@RequestMapping("/openApi") +public class AuthController { + + @Autowired + private UserService userService; + + @PostMapping(value = "/login") + public ResponseVO login(@RequestBody UserDTO userDTO) { + return ResponseData.generateCreatedResponse(0, userService.login(userDTO)); + } + + @PostMapping(value = "/loginOut") + public ResponseVO loginOut() { + userService.loginOut(); + return ResponseData.generateCreatedResponse(0); + } +} diff --git a/src/main/java/com/zhongzhi/dao/UserMapper.java b/src/main/java/com/zhongzhi/dao/UserMapper.java new file mode 100644 index 0000000..c59d671 --- /dev/null +++ b/src/main/java/com/zhongzhi/dao/UserMapper.java @@ -0,0 +1,8 @@ +package com.zhongzhi.dao; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.zhongzhi.model.base.UserModel; + +public interface UserMapper extends BaseMapper { + +} diff --git a/src/main/java/com/zhongzhi/dto/UserDTO.java b/src/main/java/com/zhongzhi/dto/UserDTO.java new file mode 100644 index 0000000..7ce1f3d --- /dev/null +++ b/src/main/java/com/zhongzhi/dto/UserDTO.java @@ -0,0 +1,11 @@ +package com.zhongzhi.dto; + +import lombok.Data; + +@Data +public class UserDTO { + + private String username; + + private String password; +} diff --git a/src/main/java/com/zhongzhi/model/base/UserModel.java b/src/main/java/com/zhongzhi/model/base/UserModel.java new file mode 100644 index 0000000..8ca3c0e --- /dev/null +++ b/src/main/java/com/zhongzhi/model/base/UserModel.java @@ -0,0 +1,43 @@ +package com.zhongzhi.model.base; + +import lombok.Data; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; + +import java.util.Collection; +import java.util.Collections; + +@Data +public class UserModel extends BaseModel implements UserDetails { + + private int id; + + private String username; + + private String password; + + @Override + public Collection getAuthorities() { + return Collections.emptyList(); + } + + @Override + public boolean isAccountNonExpired() { + return true; + } + + @Override + public boolean isAccountNonLocked() { + return true; + } + + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + @Override + public boolean isEnabled() { + return true; + } +} diff --git a/src/main/java/com/zhongzhi/service/UserService.java b/src/main/java/com/zhongzhi/service/UserService.java new file mode 100644 index 0000000..04865b6 --- /dev/null +++ b/src/main/java/com/zhongzhi/service/UserService.java @@ -0,0 +1,12 @@ +package com.zhongzhi.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.zhongzhi.dto.UserDTO; +import com.zhongzhi.model.base.UserModel; + +public interface UserService extends IService { + + String login(UserDTO userDTO); + + void loginOut(); +} diff --git a/src/main/java/com/zhongzhi/service/impl/UserServiceImpl.java b/src/main/java/com/zhongzhi/service/impl/UserServiceImpl.java new file mode 100644 index 0000000..6cae517 --- /dev/null +++ b/src/main/java/com/zhongzhi/service/impl/UserServiceImpl.java @@ -0,0 +1,57 @@ +package com.zhongzhi.service.impl; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.zhongzhi.common.constant.Code; +import com.zhongzhi.common.utils.JwtUtil; +import com.zhongzhi.common.utils.Localstorage; +import com.zhongzhi.dao.UserMapper; +import com.zhongzhi.dto.UserDTO; +import com.zhongzhi.model.base.UserModel; +import com.zhongzhi.service.UserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.stereotype.Service; + +@Service +public class UserServiceImpl extends ServiceImpl implements UserService, UserDetailsService { + + @Autowired + private AuthenticationManager authenticationManager; + + @Autowired + private UserDetailsService userDetailsService; + + @Override + public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { + UserModel userModel = this.baseMapper.selectOne(new QueryWrapper() + .lambda() + .eq(UserModel::getUsername, username)); + if(userModel == null) { + throw new UsernameNotFoundException(Code.USERNAMENOTFOUND.getMessage()); + } + + return userModel; + } + + @Override + public String login(UserDTO userDTO) { + UsernamePasswordAuthenticationToken upToken = new UsernamePasswordAuthenticationToken(userDTO.getUsername(), userDTO.getPassword()); + Authentication authentication = authenticationManager.authenticate(upToken); + SecurityContextHolder.getContext().setAuthentication(authentication); + UserDetails userDetails = userDetailsService.loadUserByUsername(userDTO.getUsername()); + String token = JwtUtil.generateToken(userDetails); + return token; + } + + @Override + public void loginOut() { + Localstorage.remove(); + } +} -- libgit2 0.25.0