| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- package com.flow.service.impl;
- import com.baomidou.mybatisplus.core.toolkit.StringUtils;
- import com.flow.common.core.exception.BaseException;
- import com.flow.common.core.util.ApplicationContextUtil;
- import com.flow.common.core.util.SecurityContextUtil;
- import com.flow.dao.AuthDao;
- import com.flow.entity.Menu;
- import com.flow.entity.User;
- import com.flow.model.*;
- import com.flow.service.AuthService;
- import com.wf.captcha.ArithmeticCaptcha;
- import lombok.extern.slf4j.Slf4j;
- import org.json.JSONObject;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.data.redis.core.StringRedisTemplate;
- 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.security.oauth2.common.OAuth2AccessToken;
- import org.springframework.security.oauth2.common.exceptions.InvalidGrantException;
- import org.springframework.security.oauth2.provider.*;
- import org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter;
- import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
- import org.springframework.security.oauth2.provider.token.TokenStore;
- import org.springframework.stereotype.Service;
- import org.springframework.web.context.request.RequestContextHolder;
- import org.springframework.web.context.request.ServletRequestAttributes;
- import javax.servlet.http.HttpServletRequest;
- import java.nio.charset.StandardCharsets;
- import java.security.KeyFactory;
- import java.security.PrivateKey;
- import java.security.spec.PKCS8EncodedKeySpec;
- import java.util.Base64;
- import javax.crypto.Cipher;
- import java.util.*;
- import java.util.concurrent.TimeUnit;
- import java.util.stream.Collectors;
- @Slf4j
- @Service
- public class AuthServiceImpl implements AuthService {
- @Autowired
- private ClientDetailsService clientDetailsService;
- @Autowired
- private TokenStore tokenStore;
- @Autowired
- private StringRedisTemplate redisTemplate;
- @Autowired
- private AuthDao authDao;
- @Autowired
- private UserDetailsService userDetailsService;
- @Autowired
- private AuthorizationServerTokenServices tokenServices;
- private static final String PRIVATE_KEY = "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBALE9Y/QdMET28R4z\n" +
- "fhDHTdTyhWYLrEipY9G4jm3wnTMQNC50CBco+PLwTRDdxfzTRQ0FPHaBR9FE2s42\n" +
- "oAsoOcnVITqoJQN5c57Pyxr3kZD13gFfulKNkus9+cIFMG1vksaRjnOaWa2kbYBX\n" +
- "14mv6RCqGz+vRziePBoONUbiQXdlAgMBAAECgYBjSDdAXEVYrFdeiouYjHwdyAhP\n" +
- "pERKo5BFvzMRhJIaM353cwnBJ3NkapVQ2Fn6iMIKTB+VZk+7eu1yTAkUluDfLowd\n" +
- "REZS4ipOBY5UuNnjbXmSOoUQw6vRnox0X4x6S1vd4FBHgpVe1VkiE7Nz5U7Clyd5\n" +
- "yw2P1lHwMyB/guAH4QJBAN3dGkMASj0jm23maHOfehp/zlACB8HpMKuV4z/bEg45\n" +
- "nC9Hw5NloUHrXdzEXP1+S46MCH2THflxDVYtnZTRLO0CQQDMgp3Jrn7kkKtNceZF\n" +
- "R08hLbVmfNlatgONgFJ5JnR+GTQ6o2gwM6SLyoBkfAIiEDpr6c6nBXTU09GOYxBk\n" +
- "+h1ZAkB32pXxVBrG5JF20V3j+GcyIZEGz9H5A0xzpUlambIrVRv2vsH8wo5W2hue\n" +
- "w8Woe629mBCOJgevVU9rGsFiP44RAkEApbTYAQjAjJakFpZJjKzg8vNEXoye2R9N\n" +
- "9aOaL8v27A2kAjdRPm050IL+UW0hlVQs4i+KYE7NgX03+PVP3WHD0QJBANLo4PRw\n" +
- "7Y+dLPAzuazsD3/5SYaSh+KSD/+tVbc6CFvLyfFUKp/a4PzzvGaLo/Ky/ffOY5k0\n" +
- "hmavbHCKcg+r+hg=";
- @Override
- public ImageCode getImageCode() {
- // 算术验证码:三个参数分别为宽、高、位数
- ArithmeticCaptcha captcha = new ArithmeticCaptcha(111, 36, 2);
- // code保存到redis
- String code = captcha.text().toLowerCase();
- String uuid = UUID.randomUUID().toString();
- redisTemplate.opsForValue().set("image_code:" + uuid, code, 2L, TimeUnit.MINUTES);
- // 返回结果
- return new ImageCode(captcha.toBase64(), uuid);
- }
- // 盐值登录
- @Override
- public AccessToken saltLogin(SaltLogin salt) {
- log.info("盐值登录");
- if (StringUtils.isBlank(salt.getSalt())) {
- throw new BaseException("盐值不能为空");
- }
- log.info("盐值: " + salt.getSalt());
- String saltData = salt.getSalt();
- AccessToken accessToken = null;
- long now = System.currentTimeMillis();
- String decryptedData = null;
- try {
- decryptedData = decrypt(saltData);
- } catch (Exception e) {
- throw new BaseException("盐值解析异常,请联系管理员" + e.getMessage());
- }
- log.info("解密后的数据: " + decryptedData);
- if (StringUtils.isBlank(decryptedData)) {
- throw new BaseException("盐值数据为空,请联系管理员");
- } else {
- JSONObject jsonObject = new JSONObject(decryptedData);
- String user = jsonObject.getString("user");
- long time = jsonObject.getLong("time");
- String form = jsonObject.getString("form");
- // 判断时间戳是否过期
- // if (now - time < 10000) {
- // throw new BaseException("请求超时,请重试");
- // } else {
- //
- // }
- if (StringUtils.isNotBlank(user)) {
- accessToken = loginByUsername(user);
- }
- }
- return accessToken;
- }
- // RSA解密
- public String decrypt(String encryptedData) throws Exception {
- String privateKeyBase64 = PRIVATE_KEY.replaceAll("\\s", "");
- // 将Base64编码的私钥转换为PrivateKey对象
- byte[] privateKeyBytes = Base64.getDecoder().decode(privateKeyBase64);
- // 生成PrivateKey对象
- PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
- KeyFactory keyFactory = KeyFactory.getInstance("RSA");
- PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
- // 创建Cipher对象进行解密
- Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
- cipher.init(Cipher.DECRYPT_MODE, privateKey);
- // 解密
- encryptedData = encryptedData.replaceAll(" ", "+");
- byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);
- byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
- // 将解密后的字节转换为字符串
- return new String(decryptedBytes, StandardCharsets.UTF_8);
- }
- // 获取时间戳
- @Override
- public Long getTimeStamp() {
- return System.currentTimeMillis();
- }
- public AccessToken loginByUsername(String username) {
- UserDetails userDetails = userDetailsService.loadUserByUsername(username);
- ClientDetails clientDetails = clientDetailsService.loadClientByClientId("client");
- // 直接创建OAuth2认证
- OAuth2Request oauth2Request = new OAuth2Request(
- Collections.emptyMap(),
- clientDetails.getClientId(),
- null,
- true,
- clientDetails.getScope(),
- null,
- null,
- null,
- null
- );
- Authentication userAuth = new UsernamePasswordAuthenticationToken(
- userDetails, null, userDetails.getAuthorities());
- OAuth2Authentication oauth2Authentication = new OAuth2Authentication(oauth2Request, userAuth);
- // 直接生成token
- OAuth2AccessToken token = tokenServices.createAccessToken(oauth2Authentication);
- return new AccessToken(token);
- }
- @Override
- public AccessToken login(LoginForm loginForm) {
- OAuth2AccessToken oAuth2AccessToken = null;
- String uuid = loginForm.getUuid();
- String code = loginForm.getCode();
- if (StringUtils.isBlank(code) || StringUtils.isBlank(uuid)) {
- throw new BaseException("验证码不能为空");
- }
- String redisCode = redisTemplate.opsForValue().get("image_code:" + uuid);
- if (StringUtils.isBlank(redisCode)) {
- throw new BaseException("验证码不存在或已过期");
- }
- if (!code.equalsIgnoreCase(redisCode)) {
- throw new BaseException("验证码错误");
- }
- HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
- request.setAttribute("login_type", "social_login");
- ClientDetails clientDetails = clientDetailsService.loadClientByClientId("client");
- Map<String, String> requestParameters = new HashMap<>(5);
- requestParameters.put("grant_type", "password");
- requestParameters.put("username", loginForm.getUsername());
- requestParameters.put("password", loginForm.getPassword());
- TokenRequest tokenRequest = new TokenRequest(
- requestParameters,
- clientDetails.getClientId(), clientDetails.getScope(),
- requestParameters.get("grant_type")
- );
- try {
- ResourceOwnerPasswordTokenGranter granter = ApplicationContextUtil.getBean(ResourceOwnerPasswordTokenGranter.class);
- oAuth2AccessToken = granter.grant(tokenRequest.getGrantType(), tokenRequest);
- } catch (InvalidGrantException ex) {
- throw new BaseException("用户名或密码错误");
- }
- return new AccessToken(oAuth2AccessToken);
- }
- @Override
- public void logout() {
- String accessToken = SecurityContextUtil.getAccessToken();
- if (StringUtils.isNotBlank(accessToken)) {
- OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(SecurityContextUtil.getAccessToken());
- tokenStore.removeAccessToken(oAuth2AccessToken);
- if (Objects.nonNull(oAuth2AccessToken.getRefreshToken())) {
- tokenStore.removeRefreshToken(oAuth2AccessToken.getRefreshToken());
- }
- SecurityContextHolder.getContext().setAuthentication(null);
- SecurityContextHolder.clearContext();
- }
- }
- @Override
- public User info() {
- String userId = SecurityContextUtil.getUserId();
- Optional<User> optional = Optional.ofNullable(authDao.queryUserByUserId(userId));
- return optional.orElse(null);
- }
- @Override
- public Permission permissions() {
- String userId = SecurityContextUtil.getUserId();
- List<Menu> menus = "admin".equals(userId) ?
- authDao.getMenuAll() :
- authDao.getMenuByUserId(userId);
- // 按钮权限
- Set<String> buttonList = menus.stream().filter(b -> b.getType() == 2)
- .map(Menu::getPermission)
- .collect(Collectors.toSet());
- // 构建菜单
- List<Menu> menuList = menus.stream().filter(m -> m.getType() != 2).collect(Collectors.toList());
- List<Route> routeList = this.buildMenu(menuList);
- // 权限信息
- Permission permission = new Permission();
- permission.setRoutes(routeList);
- permission.setButtons(buttonList);
- return permission;
- }
- @Override
- public List<Route> buildMenu(List<Menu> menus) {
- return menus.stream()
- .filter(m -> m.getPid() == 0)
- .sorted(Comparator.comparingInt(Menu::getSort))
- .map(m -> {
- Route route = new Route(m);
- route.setChildren(buildMenu(m, menus));
- return route;
- }).collect(Collectors.toList());
- }
- private List<Route> buildMenu(Menu root, List<Menu> allListTree) {
- return allListTree.stream().filter((treeEntity) -> treeEntity.getPid().equals(root.getId()))
- .sorted(Comparator.comparingInt(Menu::getSort))
- .map((treeEntity) -> {
- Route routeDTO = new Route(treeEntity);
- routeDTO.setChildren(this.buildMenu(treeEntity, allListTree));
- return routeDTO;
- }).collect(Collectors.toList());
- }
- }
|