Commit a37a3fb1 by 邓敏

Security

1 parent 5c526ac8
......@@ -45,6 +45,11 @@
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
......@@ -135,18 +140,6 @@
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>${itext-asian.version}</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>${itextpdf.version}</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>${java-jwt.version}</version>
......@@ -177,6 +170,12 @@
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>com.amdelamar</groupId>
<artifactId>jhash</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
<repositories>
......
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();
}
}
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<String> typeList = Arrays.stream(typeT).collect(Collectors.toList());
List<String> 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<String> str = Arrays.stream(roadshow.split(",")).collect(Collectors.toList());
String roadshowValue = "";
if (projectGroup.equals(ProjectType.TECHNOLOGY_INNOVATION_GROUP)) {
List<String> 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<String> roadshowCList = Arrays.stream(roadshowC).collect(Collectors.toList());
for (String s : roadshowCList) {
// if (str.contains(s)) {
// roadshowValue += "■" + s + " ";
// } else {
// roadshowValue += "□" + s + " ";
// }
}
return roadshowValue;
}
return "";
}
}
package com.zhongzhi.common.constant;
public class ProjectProgress {
public static final String REGISTERED = "已注册公司";
public static final String UNREGISTERED = "创意设计阶段";
}
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));
}
}
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<String, Claim> claimMap = JwtUtil.getClaims(token);
if(claimMap != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserModel userModel = userMapper.selectOne(new QueryWrapper<UserModel>()
.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);
}
}
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));
}
}
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"));
}
}
......@@ -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));
......
......@@ -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<Object> local = ThreadLocal.withInitial(() -> null);
private static ConcurrentHashMap<String, Object> map = new ConcurrentHashMap<>();
public static void setUser(Object obj, String type) {
Map<String, Object> map = new HashMap<>();
map.put("user", obj);
map.put("type", type);
Localstorage.local.set(map);
}
public static Map<String, Object> getMap() {
return (Map<String, Object>) Localstorage.local.get();
public static void setUser(Object obj) {
Localstorage.local.set(obj);
}
public static Object getUser() {
Map<String, Object> map = (Map<String, Object>) Localstorage.local.get();
return map.get("user");
return Localstorage.local.get();
}
public static void remove() {
......
......@@ -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
......
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);
}
}
package com.zhongzhi.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zhongzhi.model.base.UserModel;
public interface UserMapper extends BaseMapper<UserModel> {
}
package com.zhongzhi.dto;
import lombok.Data;
@Data
public class UserDTO {
private String username;
private String password;
}
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<? extends GrantedAuthority> 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;
}
}
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<UserModel> {
String login(UserDTO userDTO);
void loginOut();
}
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<UserMapper, UserModel> 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<UserModel>()
.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();
}
}
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!