nacos源码修改编译(亲测)

nacos源码修改编译

文章目录

  • nacos源码修改编译
    • 内容概述
    • 源码修改
    • 源码编译
    • 测试

内容概述

生产项目选型时选择nacos作为项目的注册中心,但是由于内网安全要求,用户名和密码必须加密传输,故此更改nacos源码进行编译使用。

源码修改

首先从仓库下载nacos的源码,地址为:https://github.com/alibaba/nacos
下载之后的内容我们需要修改前端代码以及后端代码,前端将用户名和密码进行编码之后传递到后台,后台接收到参数后进行解码操作,本文使用的加密算法为非对称加密算法RSA。

  1. 前端内容修改

修改文件:C:\Users\Administrator\Desktop\nacos-2.0.4\console-ui\src\pages\Login\Login.jsx

/*
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/**
 * 新增内容
 */
/* eslint-disable */
import React from 'react';
import {Card, Form, Input, Message, ConfigProvider, Field} from '@alifd/next';
import {withRouter} from 'react-router-dom';

import './index.scss';
import Header from '../../layouts/Header';
import PropTypes from 'prop-types';
import {login} from '../../reducers/base';
/**
 * 新增内容
 */
import {JSEncrypt} from 'jsencrypt';

const FormItem = Form.Item;

@withRouter
@ConfigProvider.config
class Login extends React.Component {
  static displayName = 'Login';

  static propTypes = {
    locale: PropTypes.object,
    history: PropTypes.object,
  };

  constructor(props) {
    super(props);
    this.field = new Field(this);
  }

  componentDidMount() {
    if (localStorage.getItem('token')) {
      const [baseUrl] = location.href.split('#');
      location.href = `${baseUrl}#/`;
    }
  }

  handleSubmit = () => {
    /**
     * 新增内容
     */
    let encrypt = new JSEncrypt();

    /**
     * 新增内容
     */
    encrypt.setPublicKey('MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6a5ZRaBn5earnUBI7tQIWNZUvqim/iZUhb2PLSY+kcUVcKuguWTqsUqdyHvYofK0oYNrAwUUGqiSyNwMl5NPg/Rc60m1RAKERl+bP3ZEyyhS1/jzVe7yQ7WuYrtYF8nk70b9iHwOJABJMNYarWWq4eT1vd81zoBENRXqV3yEhlQIDAQAB');
    const {locale = {}} = this.props;
    this.field.validate((errors, values) => {
      if (errors) {
        return;
      }
      /**
       * 新增内容
       */
      let authstring = values.username + ":::" + values.password;
      let requestData = {authstring: encrypt.encrypt(authstring)};
      /**
       * 修改内容
       */

      // const { locale = {} } = this.props;
      // this.field.validate((errors, values) => {
      //   if (errors) {
      //     return;
      //   }
      login(requestData)
        .then(res => {
          localStorage.setItem('token', JSON.stringify(res));
          this.props.history.push('/');
        })
        .catch(() => {
          Message.error({
            content: locale.invalidUsernameOrPassword,
          });
        });
    });
  };

  onKeyDown = event => {
    // 'keypress' event misbehaves on mobile so we track 'Enter' key via 'keydown' event
    if (event.key === 'Enter') {
      event.preventDefault();
      event.stopPropagation();
      this.handleSubmit();
    }
  };

  render() {
    const {locale = {}} = this.props;

    return (
      <div className="home-page">
        <Header/>
        <section
          className="top-section"
          style={{
            background: 'url(img/black_dot.png) repeat',
            backgroundSize: '14px 14px',
          }}
        >
          <div className="vertical-middle product-area">
            <img className="product-logo" src="img/nacos.png"/>
            <p className="product-desc">
              an easy-to-use dynamic service discovery, configuration and service management
              platform for building cloud native applications
            </p>
          </div>
          <div className="animation animation1"/>
          <div className="animation animation2"/>
          <div className="animation animation3"/>
          <div className="animation animation4"/>
          <div className="animation animation5"/>
          <Card className="login-panel" contentHeight="auto">
            <div className="login-header">{locale.login}</div>
            <div className="internal-sys-tip">
              <div>{locale.internalSysTip1}</div>
              <div>{locale.internalSysTip2}</div>
            </div>
            <Form className="login-form" field={this.field}>
              <FormItem>
                <Input
                  {...this.field.init('username', {
                    rules: [
                      {
                        required: true,
                        message: locale.usernameRequired,
                      },
                    ],
                  })}
                  placeholder={locale.pleaseInputUsername}
                  onKeyDown={this.onKeyDown}
                />
              </FormItem>
              <FormItem>
                <Input
                  htmlType="password"
                  placeholder={locale.pleaseInputPassword}
                  {...this.field.init('password', {
                    rules: [
                      {
                        required: true,
                        message: locale.passwordRequired,
                      },
                    ],
                  })}
                  onKeyDown={this.onKeyDown}
                />
              </FormItem>
              <FormItem label=" ">
                <Form.Submit onClick={this.handleSubmit}>{locale.submit}</Form.Submit>
              </FormItem>
            </Form>
          </Card>
        </section>
      </div>
    );
  }
}

export default Login;

修改文件:C:\Users\Administrator\Desktop\nacos-2.0.4\console-ui\package.json

{
  "name": "console-ui",
  "version": "1.0.0",
  "description": "console ui",
  "main": "index.js",
  "scripts": {
    "start": "cross-env NODE_ENV=development webpack-dev-server --config build/webpack.dev.conf.js",
    "build": "cross-env NODE_ENV=production webpack --config build/webpack.prod.conf.js && node build/copyFile.js",
    "eslint": "eslint --ext .js src/",
    "eslint-fix": "eslint  --ext .js --fix src/"
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  },
  "lint-staged": {
    "*.{js,css,less}": [
      "prettier --write",
      "git add"
    ]
  },
  "license": "Apache-2.0",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/alibaba/nacos.git"
  },
  "devDependencies": {
    "@alifd/next-theme-loader": "^1.3.1",
    "@babel/cli": "^7.7.7",
    "@babel/core": "^7.7.7",
    "@babel/plugin-proposal-decorators": "^7.7.4",
    "@babel/preset-env": "^7.7.7",
    "@babel/runtime": "^7.7.7",
    "babel-eslint": "^10.0.1",
    "babel-loader": "^8.0.4",
    "babel-plugin-import": "^1.13.0",
    "babel-preset-react-app": "^9.1.0",
    "clean-webpack-plugin": "^3.0.0",
    "copy-webpack-plugin": "^5.1.1 ",
    "cross-env": "^6.0.3",
    "css-loader": "^3.4.0",
    "eslint": "^6.8.0",
    "eslint-config-ali": "^9.0.2",
    "eslint-config-prettier": "^6.8.0",
    "eslint-loader": "^3.0.3",
    "eslint-plugin-import": "^2.14.0",
    "eslint-plugin-prettier": "^3.0.0",
    "eslint-plugin-react": "^7.17.0",
    "eslint-plugin-react-hooks": "^2.3.0",
    "file-loader": "^5.0.2",
    "html-webpack-plugin": "^3.2.0",
    "husky": "^3.1.0",
    "lint-staged": "^9.5.0",
    "mini-css-extract-plugin": "^0.9.0",
    "node-sass": "^4.13.0",
    "optimize-css-assets-webpack-plugin": "^5.0.3",
    "prettier": "1.19.1",
    "sass-loader": "^8.0.0",
    "style-loader": "^1.1.2",
    "uglifyjs-webpack-plugin": "^2.2.0",
    "url-loader": "^3.0.0",
    "webpack": "^4.43.0",
    "webpack-cli": "^3.3.12",
    "webpack-dev-server": "^3.11.0"
  },
  "dependencies": {
    "@alifd/next": "^1.17.4",
    "axios": "^0.21.1",
    
    "core-js": "2",
    "jsencrypt": "^3.0.0-rc.1",
    
    "moment": "^2.23.0",
    "qs": "^6.8.2",
    "prop-types": "^15.6.2",
    "react": "^16.12.0",
    "react-dom": "^16.12.0",
    "react-redux": "^7.1.3",
    "react-router": "^5.1.2",
    "react-router-dom": "^5.1.2",
    "react-router-redux": "^4.0.8",
    "redux": "^4.0.5",
    "redux-thunk": "^2.3.0",
    "yamljs": "^0.3.0"
  }
}

    "core-js": "2",
    "jsencrypt": "^3.0.0-rc.1",
  1. 后端内容修改

新增文件:C:\Users\Administrator\Desktop\nacos-2.0.4\console\src\main\java\com\alibaba\nacos\console\utils\RsaCoder.java

package com.alibaba.nacos.console.utils;

import org.apache.commons.codec.binary.Base64;

import javax.crypto.Cipher;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.HashMap;
import java.util.Map;

/**
 * RsaCoder encoder tool
 *
 * @author twosoy
 */
public class RsaCoder {
    public static final String KEY_ALGORITHM = "RSA";
    public static final String SIGNATURE_ALGORITHM = "MD5withRSA";

    private static final String PUBLIC_KEY = "nacosplc";
    private static final String PRIVATE_KEY = "nacospri";

    public static byte[] decryptBASE64(String key) {
        return Base64.decodeBase64(key);
    }

    public static String encryptBASE64(byte[] bytes) {
        return Base64.encodeBase64String(bytes);
    }

    /**
     * 用私钥对信息生成数字签名
     *
     * @param data       加密数据
     * @param privateKey 私钥
     * @return
     * @throws Exception
     */
    public static String sign(byte[] data, String privateKey) throws Exception {
        // 解密由base64编码的私钥
        byte[] keyBytes = decryptBASE64(privateKey);
        // 构造PKCS8EncodedKeySpec对象
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        // KEY_ALGORITHM 指定的加密算法
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        // 取私钥匙对象
        PrivateKey priKey = keyFactory.generatePrivate(pkcs8KeySpec);
        // 用私钥对信息生成数字签名
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initSign(priKey);
        signature.update(data);
        return encryptBASE64(signature.sign());
    }


    /**
     * 校验数字签名
     *
     * @param data      加密数据
     * @param publicKey 公钥
     * @param sign      数字签名
     * @return 校验成功返回true 失败返回false
     * @throws Exception
     */
    public static boolean verify(byte[] data, String publicKey, String sign)
        throws Exception {
        // 解密由base64编码的公钥
        byte[] keyBytes = decryptBASE64(publicKey);
        // 构造X509EncodedKeySpec对象
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        // KEY_ALGORITHM 指定的加密算法
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        // 取公钥匙对象
        PublicKey pubKey = keyFactory.generatePublic(keySpec);
        Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
        signature.initVerify(pubKey);
        signature.update(data);
        // 验证签名是否正常
        return signature.verify(decryptBASE64(sign));
    }

    public static byte[] decryptByPrivateKey(byte[] data, String key) throws Exception{
        // 对密钥解密
        byte[] keyBytes = decryptBASE64(key);
        // 取得私钥
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM);
        Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec);
        // 对数据解密
        Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm());
        cipher.init(Cipher.DECRYPT_MODE, privateKey);
        return cipher.doFinal(data);
    }

    /**
     * 解密
* 用私钥解密 * * @param data * @param key * @return * @throws Exception */
public static byte[] decryptByPrivateKey(String data, String key) throws Exception { return decryptByPrivateKey(decryptBASE64(data),key); } /** * 解密
* 用公钥解密 * * @param data * @param key * @return * @throws Exception */
public static byte[] decryptByPublicKey(byte[] data, String key) throws Exception { // 对密钥解密 byte[] keyBytes = decryptBASE64(key); // 取得公钥 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicKey = keyFactory.generatePublic(x509KeySpec); // 对数据解密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.DECRYPT_MODE, publicKey); return cipher.doFinal(data); } /** * 加密
* 用公钥加密 * * @param data * @param key * @return * @throws Exception */
public static byte[] encryptByPublicKey(String data, String key) throws Exception { // 对公钥解密 byte[] keyBytes = decryptBASE64(key); // 取得公钥 X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key publicKey = keyFactory.generatePublic(x509KeySpec); // 对数据加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, publicKey); return cipher.doFinal(data.getBytes()); } /** * 加密
* 用私钥加密 * * @param data * @param key * @return * @throws Exception */
public static byte[] encryptByPrivateKey(byte[] data, String key) throws Exception { // 对密钥解密 byte[] keyBytes = decryptBASE64(key); // 取得私钥 PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes); KeyFactory keyFactory = KeyFactory.getInstance(KEY_ALGORITHM); Key privateKey = keyFactory.generatePrivate(pkcs8KeySpec); // 对数据加密 Cipher cipher = Cipher.getInstance(keyFactory.getAlgorithm()); cipher.init(Cipher.ENCRYPT_MODE, privateKey); return cipher.doFinal(data); } /** * 取得私钥 * * @param keyMap * @return * @throws Exception */ public static String getPrivateKey(Map<String, Key> keyMap) throws Exception { Key key = (Key) keyMap.get(PRIVATE_KEY); return encryptBASE64(key.getEncoded()); } /** * 取得公钥 * * @param keyMap * @return * @throws Exception */ public static String getPublicKey(Map<String, Key> keyMap) throws Exception { Key key = keyMap.get(PUBLIC_KEY); return encryptBASE64(key.getEncoded()); } /** * 初始化密钥 * * @return * @throws Exception */ public static Map<String, Key> initKey() throws Exception { KeyPairGenerator keyPairGen = KeyPairGenerator .getInstance(KEY_ALGORITHM); keyPairGen.initialize(1024); KeyPair keyPair = keyPairGen.generateKeyPair(); Map<String, Key> keyMap = new HashMap(2); keyMap.put(PUBLIC_KEY, keyPair.getPublic()); keyMap.put(PRIVATE_KEY, keyPair.getPrivate()); return keyMap; } /** * 生成公钥和私钥 * @param args * @throws Exception */ public static void main(String[] args) throws Exception { Map<String, Key> keyMap = RsaCoder.initKey(); String publicKey = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC6a5ZRaBn5earnUBI7tQIWNZUvqim/iZUhb2PLSY+kcUVcKuguWTqsUqdyHvYofK0oYNrAwUUGqiSyNwMl5NPg/Rc60m1RAKERl+bP3ZEyyhS1/jzVe7yQ7WuYrtYF8nk70b9iHwOJABJMNYarWWq4eT1vd81zoBENRXqV3yEhlQIDAQAB"; String privateKey = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALprllFoGfl5qudQEju1AhY1lS+qKb+JlSFvY8tJj6RxRVwq6C5ZOqxSp3Ie9ih8rShg2sDBRQaqJLI3AyXk0+D9FzrSbVEAoRGX5s/dkTLKFLX+PNV7vJDta5iu1gXyeTvRv2IfA4kAEkw1hqtZarh5PW93zXOgEQ1FepXfISGVAgMBAAECgYB48goxQJ/xel1F+24I7LOw4wyqQvUY/lMRwSn2nwAhiRed53yBbYSifnGCmdHMjK7vDn9+JSX6X/K06PoS4LYRG6WZ1+kPp6BJHcReOfg6ILFFzYXpUksf07tJDACBt0orG1tAuXBFzoyhZR6PJ61PGiqL58J2YdzlNTGSIzYh9QJBAOGk5th/bjocVECGRXeCbXadVksSabifiuF5z6IuAqdXNEG7ADyBrnpzAN/FibVdkK5Nwy6dVr752Z13+e9Jbr8CQQDTf9RvDZy8qCApN+yQ/t6C/g0MCn/YsHqu5dRM97G/nN1Bys+FJGJ3r/jq0ATwJV3Ww2UzuLBKn0jJ9P54HdirAkEAotDzRXrF1aaFYL3COFbjl3g2QRs7L93nP4U+vl6GyarR6S//HqnQdUiwc8c886Jc+HjiAqvDYTA1xztAHFqXTwJBAKWHOl/gK3eLrgAUgNXKY6Pp6ZQu83hIRvxzbAEBKuBoiNJhRKFTpK0/0HUWcYbx98uKCb69IVyF5ZYKZM7lrRkCQQDfqMQpuXGDdrXIJ4jKgyJEd0zAakdGGjJEd7y+VV4CBvGgaVtWTZgxd+f5vV/PDJyR5AnqcaShqt8HwtP4iyUh"; byte[] decodedData = RsaCoder.decryptByPrivateKey("UDYi7GGzuVqkOi5I2MCfZmAn2or2FYwzxbzCeErCuASlIZ1TI+bAvArl5c0VH31FpJsF/xNxCmBdvZzegGH+Sq4NfSneyIEe3ElzixmVAeki4xxkX63sQRur1FivTyhwUV+8HtapGmMjqK5Q+Ke8NQD63422Ir6KMY7vMastCDA=", privateKey); String outputStr = new String(decodedData); System.err.println("加密前: " + "hahah" + "\n\r" + "解密后: " + outputStr); } }

修改文件:C:\Users\Administrator\Desktop\nacos-2.0.4\console\src\main\java\com\alibaba\nacos\console\controller\UserController.java

/*
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.alibaba.nacos.console.controller;

import com.alibaba.nacos.api.common.Constants;
import com.alibaba.nacos.auth.annotation.Secured;
import com.alibaba.nacos.auth.common.ActionTypes;
import com.alibaba.nacos.auth.common.AuthConfigs;
import com.alibaba.nacos.auth.common.AuthSystemTypes;
import com.alibaba.nacos.auth.exception.AccessException;
import com.alibaba.nacos.common.model.RestResult;
import com.alibaba.nacos.common.model.RestResultUtils;
import com.alibaba.nacos.common.utils.JacksonUtils;
import com.alibaba.nacos.config.server.auth.RoleInfo;
import com.alibaba.nacos.config.server.model.User;
import com.alibaba.nacos.config.server.utils.RequestUtil;
import com.alibaba.nacos.console.security.nacos.JwtTokenManager;
import com.alibaba.nacos.console.security.nacos.NacosAuthConfig;
import com.alibaba.nacos.console.security.nacos.NacosAuthManager;
import com.alibaba.nacos.console.security.nacos.roles.NacosRoleServiceImpl;
import com.alibaba.nacos.console.security.nacos.users.NacosUser;
import com.alibaba.nacos.console.security.nacos.users.NacosUserDetailsServiceImpl;
import com.alibaba.nacos.console.utils.PasswordEncoderUtil;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
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.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.alibaba.nacos.console.utils.RsaCoder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
import java.util.Objects;

/**
 * User related methods entry.
 *
 * @author wfnuser
 * @author nkorange
 */
@RestController("user")
@RequestMapping({"/v1/auth", "/v1/auth/users"})
public class UserController {
    
    @Autowired
    private JwtTokenManager jwtTokenManager;
    
    @Autowired
    private AuthenticationManager authenticationManager;
    
    @Autowired
    private NacosUserDetailsServiceImpl userDetailsService;
    
    @Autowired
    private NacosRoleServiceImpl roleService;
    
    @Autowired
    private AuthConfigs authConfigs;
    
    @Autowired
    private NacosAuthManager authManager;
    
    private String privateKey = "MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBALprllFoGfl5qudQEju1AhY1lS+qKb+JlSFvY8tJj6RxRVwq6C5ZOqxSp3Ie9ih8rShg2sDBRQaqJLI3AyXk0+D9FzrSbVEAoRGX5s/dkTLKFLX+PNV7vJDta5iu1gXyeTvRv2IfA4kAEkw1hqtZarh5PW93zXOgEQ1FepXfISGVAgMBAAECgYB48goxQJ/xel1F+24I7LOw4wyqQvUY/lMRwSn2nwAhiRed53yBbYSifnGCmdHMjK7vDn9+JSX6X/K06PoS4LYRG6WZ1+kPp6BJHcReOfg6ILFFzYXpUksf07tJDACBt0orG1tAuXBFzoyhZR6PJ61PGiqL58J2YdzlNTGSIzYh9QJBAOGk5th/bjocVECGRXeCbXadVksSabifiuF5z6IuAqdXNEG7ADyBrnpzAN/FibVdkK5Nwy6dVr752Z13+e9Jbr8CQQDTf9RvDZy8qCApN+yQ/t6C/g0MCn/YsHqu5dRM97G/nN1Bys+FJGJ3r/jq0ATwJV3Ww2UzuLBKn0jJ9P54HdirAkEAotDzRXrF1aaFYL3COFbjl3g2QRs7L93nP4U+vl6GyarR6S//HqnQdUiwc8c886Jc+HjiAqvDYTA1xztAHFqXTwJBAKWHOl/gK3eLrgAUgNXKY6Pp6ZQu83hIRvxzbAEBKuBoiNJhRKFTpK0/0HUWcYbx98uKCb69IVyF5ZYKZM7lrRkCQQDfqMQpuXGDdrXIJ4jKgyJEd0zAakdGGjJEd7y+VV4CBvGgaVtWTZgxd+f5vV/PDJyR5AnqcaShqt8HwtP4iyUh";

    /**
     * Create a new user.
     *
     * @param username username
     * @param password password
     * @return ok if create succeed
     * @throws IllegalArgumentException if user already exist
     * @since 1.2.0
     */
    @Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "users", action = ActionTypes.WRITE)
    @PostMapping
    public Object createUser(@RequestParam String username, @RequestParam String password) {
        
        User user = userDetailsService.getUserFromDatabase(username);
        if (user != null) {
            throw new IllegalArgumentException("user '" + username + "' already exist!");
        }
        userDetailsService.createUser(username, PasswordEncoderUtil.encode(password));
        return RestResultUtils.success("create user ok!");
    }
    
    /**
     * Delete an existed user.
     *
     * @param username username of user
     * @return ok if deleted succeed, keep silent if user not exist
     * @since 1.2.0
     */
    @DeleteMapping
    @Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "users", action = ActionTypes.WRITE)
    public Object deleteUser(@RequestParam String username) {
        List<RoleInfo> roleInfoList = roleService.getRoles(username);
        if (roleInfoList != null) {
            for (RoleInfo roleInfo : roleInfoList) {
                if (roleInfo.getRole().equals(NacosRoleServiceImpl.GLOBAL_ADMIN_ROLE)) {
                    throw new IllegalArgumentException("cannot delete admin: " + username);
                }
            }
        }
        userDetailsService.deleteUser(username);
        return RestResultUtils.success("delete user ok!");
    }
    
    /**
     * Update an user.
     *
     * @param username    username of user
     * @param newPassword new password of user
     * @param response http response
     * @param request http request
     * @return ok if update succeed
     * @throws IllegalArgumentException if user not exist or oldPassword is incorrect
     * @since 1.2.0
     */
    @PutMapping
    @Secured(resource = NacosAuthConfig.UPDATE_PASSWORD_ENTRY_POINT, action = ActionTypes.WRITE)
    public Object updateUser(@RequestParam String username, @RequestParam String newPassword,
            HttpServletResponse response, HttpServletRequest request) throws IOException {
        // admin or same user
        if (!hasPermission(username, request)) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN, "authorization failed!");
        }

        User user = userDetailsService.getUserFromDatabase(username);
        if (user == null) {
            throw new IllegalArgumentException("user " + username + " not exist!");
        }
        
        userDetailsService.updateUserPassword(username, PasswordEncoderUtil.encode(newPassword));
        
        return RestResultUtils.success("update user ok!");
    }

    private boolean hasPermission(String username, HttpServletRequest request) {
        if (!authConfigs.isAuthEnabled()) {
            return true;
        }
        if (Objects.isNull(request.getAttribute(RequestUtil.NACOS_USER_KEY))) {
            return false;
        }

        NacosUser user = (NacosUser) request.getAttribute(RequestUtil.NACOS_USER_KEY);
        // admin
        if (user.isGlobalAdmin()) {
            return true;
        }
        // same user
        return user.getUserName().equals(username);
    }
    
    /**
     * Get paged users.
     *
     * @param pageNo   number index of page
     * @param pageSize size of page
     * @return A collection of users, empty set if no user is found
     * @since 1.2.0
     */
    @GetMapping
    @Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "users", action = ActionTypes.READ)
    public Object getUsers(@RequestParam int pageNo, @RequestParam int pageSize) {
        return userDetailsService.getUsersFromDatabase(pageNo, pageSize);
    }
    
    /**
     * Login to Nacos
     *
     * 

This methods uses username and password to require a new token. * * @param response http response * @param request http request * @return new token of the user * @throws AccessException if user info is incorrect */ // @PostMapping("/login") // public Object login(@RequestParam String username, @RequestParam String password, HttpServletResponse response, // HttpServletRequest request) throws AccessException { // if (AuthSystemTypes.NACOS.name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType()) || AuthSystemTypes.LDAP // .name().equalsIgnoreCase(authConfigs.getNacosAuthSystemType())) { // NacosUser user = (NacosUser) authManager.login(request); // response.addHeader(NacosAuthConfig.AUTHORIZATION_HEADER, NacosAuthConfig.TOKEN_PREFIX + user.getToken()); // ObjectNode result = JacksonUtils.createEmptyJsonNode(); // result.put(Constants.ACCESS_TOKEN, user.getToken()); // result.put(Constants.TOKEN_TTL, authConfigs.getTokenValidityInSeconds()); // result.put(Constants.GLOBAL_ADMIN, user.isGlobalAdmin()); // result.put(Constants.USERNAME, user.getUserName()); // return result; // } // // create Authentication class through username and password, the implement class is UsernamePasswordAuthenticationToken // UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, // password); // try { // // use the method authenticate of AuthenticationManager(default implement is ProviderManager) to valid Authentication // Authentication authentication = authenticationManager.authenticate(authenticationToken); // // bind SecurityContext to Authentication // SecurityContextHolder.getContext().setAuthentication(authentication); // // generate Token // String token = jwtTokenManager.createToken(authentication); // // write Token to Http header // response.addHeader(NacosAuthConfig.AUTHORIZATION_HEADER, "Bearer " + token); // return RestResultUtils.success("Bearer " + token); // } catch (BadCredentialsException authentication) { // return RestResultUtils.failed(HttpStatus.UNAUTHORIZED.value(), null, "Login failed"); // } // } @PostMapping("/login") public Object login(@RequestParam String authstring, HttpServletResponse response, HttpServletRequest request) throws AccessException { RestResult<String> rr = new RestResult<String>(); int paramsSize = 2; int usernameIndex = 0; int passwordIndex = 1; /*获取一个字符串然后再解码*/ byte[] decodedData = new byte[0]; try { decodedData = RsaCoder.decryptByPrivateKey(authstring, privateKey); } catch (Exception e) { e.printStackTrace(); return RestResultUtils.failed(401, null, "参数验证失败"); } String authstringDecode = new String(decodedData); String[] usernameAndPassword = authstringDecode.split(":::"); if(usernameAndPassword.length != paramsSize){ // rr.setCode(401); // rr.setMessage("参数传递不正确"); // return rr; return RestResultUtils.failed(401, null, "参数传递不正确"); } // 通过用户名和密码创建一个 Authentication 认证对象,实现类为 UsernamePasswordAuthenticationToken UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(usernameAndPassword[usernameIndex], usernameAndPassword[passwordIndex]); try { //通过 AuthenticationManager(默认实现为ProviderManager)的authenticate方法验证 Authentication 对象 Authentication authentication = authenticationManager.authenticate(authenticationToken); //将 Authentication 绑定到 SecurityContext SecurityContextHolder.getContext().setAuthentication(authentication); //生成Token // String token = jwtTokenUtils.createToken(authentication); String token = jwtTokenManager.createToken(authentication); //将Token写入到Http头部 response.addHeader(NacosAuthConfig.AUTHORIZATION_HEADER, "Bearer " + token); rr.setCode(200); rr.setData("Bearer " + token); return rr; } catch (BadCredentialsException authentication) { // rr.setCode(401); // rr.setMessage("Login failed"); // return rr; return RestResultUtils.failed(401, null, "登录失败"); } } /** * Update password. * * @param oldPassword old password * @param newPassword new password * @return Code 200 if update successfully, Code 401 if old password invalid, otherwise 500 */ @PutMapping("/password") @Deprecated public RestResult<String> updatePassword(@RequestParam(value = "oldPassword") String oldPassword, @RequestParam(value = "newPassword") String newPassword) { Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); String username = ((UserDetails) principal).getUsername(); User user = userDetailsService.getUserFromDatabase(username); String password = user.getPassword(); // TODO: throw out more fine grained exceptions try { if (PasswordEncoderUtil.matches(oldPassword, password)) { userDetailsService.updateUserPassword(username, PasswordEncoderUtil.encode(newPassword)); return RestResultUtils.success("Update password success"); } return RestResultUtils.failed(HttpStatus.UNAUTHORIZED.value(), "Old password is invalid"); } catch (Exception e) { return RestResultUtils.failed(HttpStatus.INTERNAL_SERVER_ERROR.value(), "Update userpassword failed"); } } /** * Fuzzy matching username. * * @param username username * @return Matched username */ @GetMapping("/search") @Secured(resource = NacosAuthConfig.CONSOLE_RESOURCE_NAME_PREFIX + "users", action = ActionTypes.WRITE) public List<String> searchUsersLikeUsername(@RequestParam String username) { return userDetailsService.findUserLikeUsername(username); } }

源码编译

  1. 前端编译

使用vscode打开目录: console-ui
cnpm install
cnpm run build
打包完成之后会生成dist文件夹,把dist文件夹下的内容拷贝到上一层目录。

nacos源码修改编译(亲测)_第1张图片

  1. 后端编译

打开目录: nacos-2.0.4
打包命令:mvn -Prelease-nacos -Dmaven.test.skip=true -Dcheckstyle.skip=true -Drat.skip=true -Dpmd.skip=true clean install -U
打包完成之后会在distribution目录下生成target目录,里面的内容就是打包之后的内容。

nacos源码修改编译(亲测)_第2张图片

测试

将打包之后的文件上传到Linux服务器上,进入bin目录执行启动命令:sh startup.sh -m standalone
访问:http://ip:8848/nacos/#/login 输入默认账号密码:nacos,nacos
建议登陆之后及时修改密码,注意密码强度。

nacos源码修改编译(亲测)_第3张图片

以上就是本章节的内容,欢迎各位批评指教。如果需要编译好的文件可以直接访问此链接进行下载:nacos2.0.4版本使用RSA算法加密之后的源码,可以直接使用 。

你可能感兴趣的:(linux,linux)