parent
46fa7bf45e
commit
f0a9ba9243
@ -1,8 +1,10 @@
|
||||
# TeamModel extension
|
||||
> SpringBoot base version of TeamModel extension
|
||||
>
|
||||
> **注意**: 所有复盘输出均已脱敏,不包含任何业务,密码等关键信息
|
||||
|
||||
## 迁移目录:
|
||||
- Azure OIDC(SSO) 迁移
|
||||
- id-token(jwt) 验证迁移 (出现语言框架之间的签名算法规范问题,解决见: [输出复盘](https://juejin.cn/post/7300036605099163702))
|
||||
# TeamModel extension
|
||||
> SpringBoot base version of TeamModel extension
|
||||
>
|
||||
> **注意**: 所有复盘输出均已脱敏,不包含任何业务,密码等关键信息
|
||||
|
||||
## 迁移目录:
|
||||
- Azure OIDC(SSO) 迁移
|
||||
- id-token(jwt) 验证迁移 (出现语言框架之间的签名算法规范问题,解决见: [输出复盘](https://juejin.cn/post/7300036605099163702))
|
||||
- 钉钉告警: 异常通知
|
||||
- 异常文件记录
|
@ -0,0 +1,37 @@
|
||||
package cn.teammodel.common;
|
||||
|
||||
public enum ErrorCode {
|
||||
|
||||
SUCCESS(0, "ok"),
|
||||
PARAMS_ERROR(40000, "请求参数错误"),
|
||||
NOT_LOGIN_ERROR(40100, "未登录"),
|
||||
NO_AUTH_ERROR(40101, "无权限"),
|
||||
NOT_FOUND_ERROR(40400, "请求数据不存在"),
|
||||
FORBIDDEN_ERROR(40300, "禁止访问"),
|
||||
SYSTEM_ERROR(50000, "系统内部异常"),
|
||||
OPERATION_ERROR(50001, "操作失败");
|
||||
|
||||
/**
|
||||
* 状态码
|
||||
*/
|
||||
private final int code;
|
||||
|
||||
/**
|
||||
* 信息
|
||||
*/
|
||||
private final String message;
|
||||
|
||||
ErrorCode(int code, String message) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
}
|
@ -1,37 +1,48 @@
|
||||
package cn.teammodel.common;
|
||||
|
||||
public class R {
|
||||
private Integer code;
|
||||
private String message;
|
||||
private String data;
|
||||
|
||||
public R(Integer code, String message, String data) {
|
||||
this.code = code;
|
||||
this.message = message;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public Integer getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(Integer code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public String getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
package cn.teammodel.common;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class R<T> implements Serializable {
|
||||
|
||||
private int code;
|
||||
|
||||
private T data;
|
||||
|
||||
private String message;
|
||||
|
||||
public R(int code, T data, String message) {
|
||||
this.code = code;
|
||||
this.data = data;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public R(int code, T data) {
|
||||
this(code, data, "");
|
||||
}
|
||||
|
||||
public R(ErrorCode errorCode) {
|
||||
this(errorCode.getCode(), null, errorCode.getMessage());
|
||||
}
|
||||
public R(ErrorCode errorCode, T data) {
|
||||
this(errorCode.getCode(), data, errorCode.getMessage());
|
||||
}
|
||||
|
||||
public static <T> R<T> success(T data) {
|
||||
return new R<>(ErrorCode.SUCCESS, data);
|
||||
}
|
||||
|
||||
public static <T> R<T> error(String msg) {
|
||||
return new R<>(ErrorCode.SYSTEM_ERROR);
|
||||
}
|
||||
|
||||
public static <T> R<T> error(Integer code, String msg) {
|
||||
return new R<>(code, null, msg);
|
||||
}
|
||||
|
||||
public static <T> R<T> error(ErrorCode errorCode) {
|
||||
return new R<>(errorCode);
|
||||
}
|
||||
}
|
@ -0,0 +1,110 @@
|
||||
package cn.teammodel.config.exception;
|
||||
|
||||
import cn.teammodel.common.R;
|
||||
import cn.teammodel.manager.NotificationService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.MissingPathVariableException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/**
|
||||
* 全局异常处理器
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestControllerAdvice
|
||||
@Slf4j
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
@Resource
|
||||
private NotificationService notificationService;
|
||||
/**
|
||||
* 业务异常
|
||||
*/
|
||||
@ExceptionHandler(ServiceException.class)
|
||||
public R<?> handleServiceException(ServiceException e, HttpServletRequest request)
|
||||
{
|
||||
log.error(e.getMessage(), e);
|
||||
Integer code = e.getCode();
|
||||
return ObjectUtils.isNotEmpty(code) ? R.error(code, e.getMessage()) : R.error(e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求路径中缺少必需的路径变量
|
||||
*/
|
||||
@ExceptionHandler(MissingPathVariableException.class)
|
||||
public R<?> handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求路径中缺少必需的路径变量'{}',发生系统异常.", requestURI, e);
|
||||
return R.error(String.format("请求路径中缺少必需的路径变量[%s]", e.getVariableName()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求参数类型不匹配
|
||||
*/
|
||||
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
|
||||
public R<?> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求参数类型不匹配'{}',发生系统异常.", requestURI, e);
|
||||
return R.error(String.format("请求参数类型不匹配,参数[%s]要求类型为:'%s',但输入值为:'%s'", e.getName(), e.getRequiredType().getName(), e.getValue()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 拦截未知的运行时异常
|
||||
*/
|
||||
@ExceptionHandler(RuntimeException.class)
|
||||
public R<?> handleRuntimeException(RuntimeException e, HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',发生未知异常.", requestURI, e);
|
||||
notificationService.send("RuntimeException 告警: " + e.getMessage());
|
||||
return R.error(e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统异常
|
||||
*/
|
||||
@ExceptionHandler(Exception.class)
|
||||
public R<?> handleException(Exception e, HttpServletRequest request)
|
||||
{
|
||||
String requestURI = request.getRequestURI();
|
||||
log.error("请求地址'{}',发生系统异常.", requestURI, e);
|
||||
|
||||
notificationService.send("Exception 告警: " + e.getMessage());
|
||||
return R.error(e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义验证异常
|
||||
*/
|
||||
@ExceptionHandler(BindException.class)
|
||||
public R<?> handleBindException(BindException e)
|
||||
{
|
||||
log.error(e.getMessage(), e);
|
||||
String message = e.getAllErrors().get(0).getDefaultMessage();
|
||||
return R.error(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义验证异常
|
||||
*/
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e)
|
||||
{
|
||||
log.error(e.getMessage(), e);
|
||||
String message = Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage();
|
||||
return R.error(message);
|
||||
}
|
||||
|
||||
}
|
@ -1,20 +1,20 @@
|
||||
package cn.teammodel.controller;
|
||||
|
||||
import cn.teammodel.common.R;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/")
|
||||
public class HelloController {
|
||||
|
||||
@GetMapping("hello")
|
||||
@PreAuthorize("@ss.hasRole('admin')")
|
||||
public R hello() {
|
||||
System.out.println(SecurityContextHolder.getContext().getAuthentication());
|
||||
return new R(200, "success","hello world");
|
||||
}
|
||||
package cn.teammodel.controller;
|
||||
|
||||
import cn.teammodel.common.R;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/")
|
||||
public class HelloController {
|
||||
|
||||
@GetMapping("hello")
|
||||
@PreAuthorize("@ss.hasRole('admin')")
|
||||
public R hello() {
|
||||
System.out.println(SecurityContextHolder.getContext().getAuthentication());
|
||||
return new R(200, "success","hello world");
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
package cn.teammodel.manager;
|
||||
|
||||
import com.dingtalk.api.DefaultDingTalkClient;
|
||||
import com.dingtalk.api.DingTalkClient;
|
||||
import com.dingtalk.api.request.OapiRobotSendRequest;
|
||||
import com.taobao.api.ApiException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 钉钉告警服务
|
||||
* @author winter
|
||||
* @create 2023-11-14 10:11
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class DingAlertNotifier implements NotificationService{
|
||||
private final DingTalkClient client;
|
||||
@Autowired
|
||||
public DingAlertNotifier(@Value("${ding.server-url}") String dingServerUrl) {
|
||||
this.client = new DefaultDingTalkClient(dingServerUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(String message) {
|
||||
OapiRobotSendRequest request = new OapiRobotSendRequest();
|
||||
// 文本消息
|
||||
request.setMsgtype("text");
|
||||
OapiRobotSendRequest.Text text = new OapiRobotSendRequest.Text();
|
||||
text.setContent(message);
|
||||
request.setText(text);
|
||||
// at 管理员提醒异常
|
||||
OapiRobotSendRequest.At atAll = new OapiRobotSendRequest.At();
|
||||
atAll.setIsAtAll(true);
|
||||
request.setAt(atAll);
|
||||
try {
|
||||
client.execute(request);
|
||||
} catch (ApiException e) {
|
||||
log.error("钉钉 robot 推送消息渠道异常: {}", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package cn.teammodel.manager;
|
||||
|
||||
/**
|
||||
* 消息通知接口
|
||||
* @author winter
|
||||
* @create 2023-11-14 10:08
|
||||
*/
|
||||
public interface NotificationService {
|
||||
|
||||
/**
|
||||
* 发送消息
|
||||
* @author: winter
|
||||
* @date: 2023/11/14 10:09
|
||||
*/
|
||||
void send(String message);
|
||||
}
|
@ -1,50 +1,50 @@
|
||||
package cn.teammodel.model.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author winter
|
||||
* @create 2023-11-09 15:28
|
||||
*/
|
||||
@Data
|
||||
public class TmdUserDetail implements UserDetails {
|
||||
private User user;
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
package cn.teammodel.model.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* @author winter
|
||||
* @create 2023-11-09 15:28
|
||||
*/
|
||||
@Data
|
||||
public class TmdUserDetail implements UserDetails {
|
||||
private User user;
|
||||
@Override
|
||||
public Collection<? extends GrantedAuthority> getAuthorities() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPassword() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUsername() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonExpired() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAccountNonLocked() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCredentialsNonExpired() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,24 @@
|
||||
package cn.teammodel.model.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author winter
|
||||
* @create 2023-11-09 15:43
|
||||
*/
|
||||
@Data
|
||||
@ToString
|
||||
public class User {
|
||||
private String id;
|
||||
private String name;
|
||||
private String picture;
|
||||
private String standard;
|
||||
private String scope;
|
||||
private String website;
|
||||
private String area;
|
||||
private Set<String> roles;
|
||||
private Set<String> permissions;
|
||||
}
|
||||
package cn.teammodel.model.entity;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author winter
|
||||
* @create 2023-11-09 15:43
|
||||
*/
|
||||
@Data
|
||||
@ToString
|
||||
public class User {
|
||||
private String id;
|
||||
private String name;
|
||||
private String picture;
|
||||
private String standard;
|
||||
private String scope;
|
||||
private String website;
|
||||
private String area;
|
||||
private Set<String> roles;
|
||||
private Set<String> permissions;
|
||||
}
|
||||
|
@ -1,55 +1,53 @@
|
||||
package cn.teammodel.security.filter;
|
||||
|
||||
import cn.teammodel.config.exception.ServiceException;
|
||||
import cn.teammodel.model.entity.TmdUserDetail;
|
||||
import cn.teammodel.security.utils.JwtTokenUtil;
|
||||
import cn.teammodel.security.utils.SecurityUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
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.Collection;
|
||||
|
||||
/**
|
||||
* x-auth-authToken filter
|
||||
* @author winter
|
||||
* @create 2023-11-09 10:43
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class AuthInnerTokenFilter extends OncePerRequestFilter {
|
||||
|
||||
@Autowired
|
||||
JwtTokenUtil jwtTokenUtil;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
SecurityContext context = SecurityContextHolder.getContext();
|
||||
Authentication authentication = context.getAuthentication();
|
||||
// 进入此过滤器说明 OIDC 认证成功,则验证 authToken
|
||||
// 验证 authToken 合法
|
||||
TmdUserDetail tmdUserDetail = jwtTokenUtil.getValidUserDetail(request);
|
||||
if (tmdUserDetail == null) {
|
||||
log.error("authToken authentication failed");
|
||||
throw new ServiceException("无权限");
|
||||
}
|
||||
System.out.println(tmdUserDetail.getUser());
|
||||
// 组装 authToken 的 jwt 进 authentication
|
||||
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
|
||||
UsernamePasswordAuthenticationToken finalAuthentication = new UsernamePasswordAuthenticationToken(tmdUserDetail, null, authorities);
|
||||
context.setAuthentication(finalAuthentication);
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
package cn.teammodel.security.filter;
|
||||
|
||||
import cn.teammodel.model.entity.TmdUserDetail;
|
||||
import cn.teammodel.security.utils.JwtTokenUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContext;
|
||||
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.nio.file.AccessDeniedException;
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* x-auth-authToken filter
|
||||
* @author winter
|
||||
* @create 2023-11-09 10:43
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class AuthInnerTokenFilter extends OncePerRequestFilter {
|
||||
|
||||
@Autowired
|
||||
JwtTokenUtil jwtTokenUtil;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
SecurityContext context = SecurityContextHolder.getContext();
|
||||
Authentication authentication = context.getAuthentication();
|
||||
// 进入此过滤器说明 OIDC 认证成功,则验证 authToken
|
||||
// 验证 authToken 合法
|
||||
TmdUserDetail tmdUserDetail = jwtTokenUtil.getValidUserDetail(request);
|
||||
if (tmdUserDetail == null) {
|
||||
log.error("authToken authentication failed");
|
||||
throw new AccessDeniedException("无权限");
|
||||
}
|
||||
System.out.println(tmdUserDetail.getUser());
|
||||
// 组装 authToken 的 jwt 进 authentication
|
||||
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
|
||||
UsernamePasswordAuthenticationToken finalAuthentication = new UsernamePasswordAuthenticationToken(tmdUserDetail, null, authorities);
|
||||
context.setAuthentication(finalAuthentication);
|
||||
filterChain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
|
@ -1,107 +1,107 @@
|
||||
package cn.teammodel.security.utils;
|
||||
|
||||
import cn.teammodel.config.exception.ServiceException;
|
||||
import cn.teammodel.model.entity.User;
|
||||
import cn.teammodel.model.entity.TmdUserDetail;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
/**
|
||||
* 安全服务工具类
|
||||
*
|
||||
* @author winter
|
||||
*/
|
||||
public class SecurityUtils
|
||||
{
|
||||
/**
|
||||
* 用户ID
|
||||
**/
|
||||
public static String getUserId()
|
||||
{
|
||||
try
|
||||
{
|
||||
return getLoginUser().getId();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ServiceException("获取用户ID异常", HttpStatus.UNAUTHORIZED.value());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取用户账户
|
||||
**/
|
||||
public static String getUsername()
|
||||
{
|
||||
try
|
||||
{
|
||||
return getLoginUser().getName();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ServiceException("获取用户账户异常", HttpStatus.UNAUTHORIZED.value());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户
|
||||
**/
|
||||
public static User getLoginUser()
|
||||
{
|
||||
try
|
||||
{
|
||||
return ((TmdUserDetail) getAuthentication().getPrincipal()).getUser();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED.value());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Authentication
|
||||
*/
|
||||
public static Authentication getAuthentication()
|
||||
{
|
||||
return SecurityContextHolder.getContext().getAuthentication();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成BCryptPasswordEncoder密码
|
||||
*
|
||||
* @param password 密码
|
||||
* @return 加密字符串
|
||||
*/
|
||||
public static String encryptPassword(String password)
|
||||
{
|
||||
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
return passwordEncoder.encode(password);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断密码是否相同
|
||||
*
|
||||
* @param rawPassword 真实密码
|
||||
* @param encodedPassword 加密后字符
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean matchesPassword(String rawPassword, String encodedPassword)
|
||||
{
|
||||
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
return passwordEncoder.matches(rawPassword, encodedPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为管理员
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean isAdmin(Long userId)
|
||||
{
|
||||
return userId != null && 1L == userId;
|
||||
}
|
||||
}
|
||||
package cn.teammodel.security.utils;
|
||||
|
||||
import cn.teammodel.config.exception.ServiceException;
|
||||
import cn.teammodel.model.entity.User;
|
||||
import cn.teammodel.model.entity.TmdUserDetail;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
|
||||
/**
|
||||
* 安全服务工具类
|
||||
*
|
||||
* @author winter
|
||||
*/
|
||||
public class SecurityUtils
|
||||
{
|
||||
/**
|
||||
* 用户ID
|
||||
**/
|
||||
public static String getUserId()
|
||||
{
|
||||
try
|
||||
{
|
||||
return getLoginUser().getId();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ServiceException("获取用户ID异常", HttpStatus.UNAUTHORIZED.value());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取用户账户
|
||||
**/
|
||||
public static String getUsername()
|
||||
{
|
||||
try
|
||||
{
|
||||
return getLoginUser().getName();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ServiceException("获取用户账户异常", HttpStatus.UNAUTHORIZED.value());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户
|
||||
**/
|
||||
public static User getLoginUser()
|
||||
{
|
||||
try
|
||||
{
|
||||
return ((TmdUserDetail) getAuthentication().getPrincipal()).getUser();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED.value());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取Authentication
|
||||
*/
|
||||
public static Authentication getAuthentication()
|
||||
{
|
||||
return SecurityContextHolder.getContext().getAuthentication();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成BCryptPasswordEncoder密码
|
||||
*
|
||||
* @param password 密码
|
||||
* @return 加密字符串
|
||||
*/
|
||||
public static String encryptPassword(String password)
|
||||
{
|
||||
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
return passwordEncoder.encode(password);
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断密码是否相同
|
||||
*
|
||||
* @param rawPassword 真实密码
|
||||
* @param encodedPassword 加密后字符
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean matchesPassword(String rawPassword, String encodedPassword)
|
||||
{
|
||||
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
|
||||
return passwordEncoder.matches(rawPassword, encodedPassword);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为管理员
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @return 结果
|
||||
*/
|
||||
public static boolean isAdmin(Long userId)
|
||||
{
|
||||
return userId != null && 1L == userId;
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,21 @@
|
||||
spring:
|
||||
cloud:
|
||||
azure:
|
||||
cosmos:
|
||||
endpoint: https://cdhabookdep-free.documents.azure.cn:443
|
||||
database: TEAMModelOS
|
||||
key: v07dMthUjNk8AbwI8698AXHPbXBaaADgtgdYf4sFGXohei6aD2doq6XV45sLMGpDtDDpENAnlGkEUBu9RaAhpg==
|
||||
|
||||
security:
|
||||
oauth2:
|
||||
resourceserver:
|
||||
jwt:
|
||||
issuer-uri: https://login.partner.microsoftonline.cn/4807e9cf-87b8-4174-aa5b-e76497d7392b/v2.0
|
||||
audiences: 72643704-b2e7-4b26-b881-bd5865e7a7a5
|
||||
|
||||
jwt:
|
||||
secret: fXO6ko/qyXeYrkecPeKdgXnuLXf9vMEtnBC9OB3s+aA=
|
||||
|
||||
dingding:
|
||||
spring:
|
||||
cloud:
|
||||
azure:
|
||||
cosmos:
|
||||
endpoint: https://cdhabookdep-free.documents.azure.cn:443
|
||||
database: TEAMModelOS
|
||||
key: v07dMthUjNk8AbwI8698AXHPbXBaaADgtgdYf4sFGXohei6aD2doq6XV45sLMGpDtDDpENAnlGkEUBu9RaAhpg==
|
||||
|
||||
security:
|
||||
oauth2:
|
||||
resourceserver:
|
||||
jwt:
|
||||
issuer-uri: https://login.partner.microsoftonline.cn/4807e9cf-87b8-4174-aa5b-e76497d7392b/v2.0
|
||||
audiences: 72643704-b2e7-4b26-b881-bd5865e7a7a5
|
||||
|
||||
jwt:
|
||||
secret: fXO6ko/qyXeYrkecPeKdgXnuLXf9vMEtnBC9OB3s+aA=
|
||||
|
||||
# 钉钉 webhook
|
||||
ding:
|
||||
server-url: https://oapi.dingtalk.com/robot/send?access_token=32d9b24f69c2c4fd7c2dab43268b6258a7214d2620e0805d7b6d1429003b64b6
|
@ -1,13 +1,19 @@
|
||||
package cn.teammodel;
|
||||
|
||||
import cn.teammodel.manager.DingAlertNotifier;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
@SpringBootTest
|
||||
class TeamModelExtensionApplicationTests {
|
||||
|
||||
@Autowired
|
||||
private DingAlertNotifier notifier;
|
||||
|
||||
@Test
|
||||
void contextLoads() {
|
||||
notifier.send("告警: 测试消息推送封装模块");
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in new issue