Skip to content

Commit

Permalink
Merge branch 'develop' into feature_multi_tenant
Browse files Browse the repository at this point in the history
  • Loading branch information
nkorange committed Jan 15, 2019
2 parents 705a47e + 420141f commit e9811c8
Show file tree
Hide file tree
Showing 37 changed files with 1,186 additions and 50 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* 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.config.server.model;

/**
* user info
*
* @author wfnuser
*/
public class User {
private String username;
private String password;

public String getPassword() {
return password;
}

public void setPassword(String password) {
this.password = password;
}

public String getUsername() {
return username;
}

public void setUsername(String username) {
this.username = username;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

import javax.annotation.PostConstruct;

import com.alibaba.nacos.config.server.model.*;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
Expand All @@ -53,19 +54,6 @@
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.CollectionUtils;
import com.alibaba.nacos.config.server.model.ConfigAdvanceInfo;
import com.alibaba.nacos.config.server.model.ConfigAllInfo;
import com.alibaba.nacos.config.server.model.ConfigHistoryInfo;
import com.alibaba.nacos.config.server.model.ConfigInfo;
import com.alibaba.nacos.config.server.model.ConfigInfo4Beta;
import com.alibaba.nacos.config.server.model.ConfigInfo4Tag;
import com.alibaba.nacos.config.server.model.ConfigInfoAggr;
import com.alibaba.nacos.config.server.model.ConfigInfoBase;
import com.alibaba.nacos.config.server.model.ConfigInfoChanged;
import com.alibaba.nacos.config.server.model.ConfigKey;
import com.alibaba.nacos.config.server.model.Page;
import com.alibaba.nacos.config.server.model.SubInfo;
import com.alibaba.nacos.config.server.model.TenantInfo;
import com.alibaba.nacos.config.server.utils.LogUtil;
import com.alibaba.nacos.config.server.utils.MD5;
import com.alibaba.nacos.config.server.utils.PaginationHelper;
Expand Down Expand Up @@ -455,6 +443,15 @@ public TenantInfo mapRow(ResultSet rs, int rowNum) throws SQLException {
}
}

static final class UserRowMapper implements RowMapper<User> {
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
user.setUsername(rs.getString("username"));
user.setPassword(rs.getString("password"));
return user;
}
}

public synchronized void reload() throws IOException {
this.dataSourceService.reload();
}
Expand Down Expand Up @@ -3113,6 +3110,22 @@ public void removeTenantInfoAtomic(final String kp, final String tenantId) {
}
}

public User findUserByUsername(String username) {
String sql = "SELECT username,password FROM users WHERE username=? ";
try {
return this.jt.queryForObject(sql, new Object[] {username}, USER_ROW_MAPPER);
} catch (CannotGetJdbcConnectionException e) {
fatalLog.error("[db-error] " + e.toString(), e);
throw e;
} catch (EmptyResultDataAccessException e) {
return null;
} catch (Exception e) {
fatalLog.error("[db-other-error]" + e.getMessage(), e);
throw new RuntimeException(e);
}
}


private List<ConfigInfo> convertDeletedConfig(List<Map<String, Object>> list) {
List<ConfigInfo> configs = new ArrayList<ConfigInfo>();
for (Map<String, Object> map : list) {
Expand Down Expand Up @@ -3265,6 +3278,8 @@ public Boolean completeMd5() {

static final TenantInfoRowMapper TENANT_INFO_ROW_MAPPER = new TenantInfoRowMapper();

static final UserRowMapper USER_ROW_MAPPER = new UserRowMapper();

static final ConfigInfoWrapperRowMapper CONFIG_INFO_WRAPPER_ROW_MAPPER = new ConfigInfoWrapperRowMapper();

static final ConfigKeyRowMapper CONFIG_KEY_ROW_MAPPER = new ConfigKeyRowMapper();
Expand Down
17 changes: 16 additions & 1 deletion config/src/main/resources/META-INF/nacos-db.sql
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,19 @@ CREATE TABLE `tenant_info` (
PRIMARY KEY (`id`),
UNIQUE KEY `uk_tenant_info_kptenantid` (`kp`,`tenant_id`),
KEY `idx_tenant_id` (`tenant_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='tenant_info';

CREATE TABLE users (
username varchar(50) NOT NULL PRIMARY KEY,
password varchar(500) NOT NULL,
enabled boolean NOT NULL
);

CREATE TABLE roles (
username varchar(50) NOT NULL,
role varchar(50) NOT NULL
);

INSERT INTO users (username, password, enabled) VALUES ('admin', '$2a$10$HxtJtd59imujvbux.i55zOGewhnJiLVXX8D9AETDMV.XtBLDGOXtW', TRUE);

INSERT INTO roles (username, role) VALUES ('admin', 'ROLE_ADMIN');
14 changes: 14 additions & 0 deletions config/src/main/resources/META-INF/schema.sql
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,17 @@ CREATE TABLE tenant_info (
CREATE INDEX tenant_info_tenant_id_idx ON tenant_info(tenant_id);


CREATE TABLE users (
username varchar(50) NOT NULL PRIMARY KEY,
password varchar(500) NOT NULL,
enabled boolean NOT NULL
);

CREATE TABLE roles (
username varchar(50) NOT NULL,
role varchar(50) NOT NULL
);

INSERT INTO users (username, password, enabled) VALUES ('admin', '$2a$10$HxtJtd59imujvbux.i55zOGewhnJiLVXX8D9AETDMV.XtBLDGOXtW', TRUE);

INSERT INTO roles (username, role) VALUES ('admin', 'ROLE_ADMIN');
19 changes: 19 additions & 0 deletions console/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,29 @@
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
</dependencies>
<build>
<finalName>nacos-server</finalName>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* 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.config;

import com.alibaba.nacos.console.filter.JwtAuthenticationTokenFilter;
import com.alibaba.nacos.console.security.CustomUserDetailsServiceImpl;
import com.alibaba.nacos.console.security.JwtAuthenticationEntryPoint;
import com.alibaba.nacos.console.utils.JwtTokenUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
* Spring security config
*
* @author Nacos
*/
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

public static final String AUTHORIZATION_HEADER = "Authorization";

public static final String AUTHORIZATION_TOKEN = "access_token";

public static final String SECURITY_IGNORE_URLS_SPILT_CHAR = ",";

@Autowired
private CustomUserDetailsServiceImpl userDetailsService;

@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;

@Autowired
private JwtTokenUtils tokenProvider;

@Autowired
private Environment env;

@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}

@Override
public void configure(WebSecurity web) {
String ignoreURLs = env.getProperty("nacos.security.ignore.urls", "/**");
for (String ignoreURL : ignoreURLs.trim().split(SECURITY_IGNORE_URLS_SPILT_CHAR)) {
web.ignoring().antMatchers(ignoreURL.trim());
}
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated().and()
// custom token authorize exception handler
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler).and()
// since we use jwt, session is not necessary
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
// since we use jwt, csrf is not necessary
.csrf().disable();
http.addFilterBefore(new JwtAuthenticationTokenFilter(tokenProvider), UsernamePasswordAuthenticationFilter.class);

// disable cache
http.headers().cacheControl();
}

@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* 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.console.config.WebSecurityConfig;
import com.alibaba.nacos.config.server.model.RestResult;
import com.alibaba.nacos.console.utils.JwtTokenUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* auth
*
* @author wfnuser
*/
@RestController("auth")
@RequestMapping("/v1/auth")
public class AuthController {

@Autowired
private JwtTokenUtils jwtTokenUtils;
@Autowired
private AuthenticationManager authenticationManager;

/**
* Whether the Nacos is in broken states or not, and cannot recover except by being restarted
*
* @return HTTP code equal to 200 indicates that Nacos is in right states. HTTP code equal to 500 indicates that
* Nacos is in broken states.
*/

@ResponseBody
@RequestMapping(value = "login", method = RequestMethod.POST)
public RestResult<String> login(HttpServletRequest request, HttpServletResponse response) throws Exception {
String username = request.getParameter("username");
String password = request.getParameter("password");

// 通过用户名和密码创建一个 Authentication 认证对象,实现类为 UsernamePasswordAuthenticationToken
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
RestResult<String> rr = new RestResult<String>();

try {
//通过 AuthenticationManager(默认实现为ProviderManager)的authenticate方法验证 Authentication 对象
Authentication authentication = authenticationManager.authenticate(authenticationToken);
//将 Authentication 绑定到 SecurityContext
SecurityContextHolder.getContext().setAuthentication(authentication);
//生成Token
String token = jwtTokenUtils.createToken(authentication);
//将Token写入到Http头部
response.addHeader(WebSecurityConfig.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;
}
}
}
Loading

0 comments on commit e9811c8

Please sign in to comment.