-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 7e4d7e4
Showing
85 changed files
with
4,819 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
# Output Directory | ||
target/ | ||
|
||
# C pre-compile | ||
*.gch | ||
*.pch | ||
|
||
# C compile | ||
*.a | ||
*.o | ||
*.ko | ||
*.la | ||
*.lo | ||
*.obj | ||
*.elf | ||
*.so | ||
*.so.* | ||
*.dylib | ||
*.exe | ||
*.lib | ||
*.dll | ||
*.out | ||
*.app | ||
*.hex | ||
|
||
# Debug files | ||
*.dSYM/ | ||
|
||
# Java | ||
*.class | ||
|
||
# Java Package Files | ||
*.jar | ||
*.war | ||
*.ear | ||
|
||
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml | ||
hs_err_pid* | ||
|
||
# Zip Files | ||
*.rar | ||
*.zip | ||
*.7z | ||
*.tar | ||
*.gz | ||
|
||
# Ant | ||
build/ | ||
|
||
# Compiled Python | ||
__pycache__/ | ||
*.py[cod] | ||
*py.class | ||
|
||
# Eclipse | ||
.settings/ | ||
.classpath | ||
.project | ||
|
||
# IntelliJ, based on http://devnet.jetbrains.net/docs/DOC-1186 | ||
.idea/ | ||
*.iml | ||
*.ipr | ||
*.iws | ||
|
||
# logs and trace | ||
*.log | ||
*.trace | ||
*.dat | ||
|
||
# vi swap | ||
*.swp | ||
|
||
# Backup Files | ||
*.bak | ||
*.old | ||
|
||
# SVN metadata | ||
.svn/ | ||
|
||
# Mac | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
This project demonstrates authentications and authorizations based on JWT/OAuth2. Projct names follow OAuth2 architecture. | ||
|
||
## Implementations | ||
|
||
This project uses spring security API and mainly designed for ServiceComb architecture. | ||
|
||
* User Management | ||
|
||
1. UserDetailsService: load users information | ||
2. UserDetails: User information | ||
3. GrantedAuthority: authorities | ||
4. PasswordEncoder: encode or verify user password | ||
|
||
## Project | ||
|
||
* AuthenticationServer | ||
|
||
Authentication server implementation. Provides APIs to login, and query roles, etc. | ||
|
||
|
||
* Gateway | ||
|
||
Check if users are authenticated and dispatch HTTP request. | ||
|
||
* Client | ||
|
||
Demonstrates how client uses this project. Integration tests are provided. | ||
|
||
|
||
* Api | ||
Reusable part. | ||
|
||
* For testing | ||
|
||
Run AuthenticationServer、Gateway、Client、ResourceServer and call | ||
|
||
``` | ||
http://localhost:9093/v1/test/start | ||
``` | ||
|
||
see AuthenticationTestCase for details. | ||
|
||
|
||
本项目提供认证鉴权服务的实现,主要提供了基于角色的权限管理,和基于JWT的微服务授权模式。微服务的命名参考了OAuth2协议里面的命名方式。可以参考[OAuth2.0原理和验证流程分析](https://www.jianshu.com/p/d74ce6ca0c33)对于OAuth2认证过程的介绍,本项目的认证过程非常类似OAuth2的密码模式。 | ||
|
||
项目的目标是提供一个商业可用的鉴权实现,对于项目代码实现的问题可以提交issue,本项目也接纳PR,共同完善。 | ||
|
||
|
||
|
||
## 实现说明 | ||
|
||
* 用户管理 | ||
用户管理采用了org.springframework.security.core.userdetails的模型,包括: | ||
1. UserDetailsService:加载用户信息。 | ||
2. UserDetails:用户信息。 | ||
3. GrantedAuthority:角色信息。 | ||
4. PasswordEncoder:用户密码加密和匹配。 | ||
|
||
|
||
## 项目结构介绍 | ||
|
||
* AuthenticationServer | ||
|
||
认证鉴权服务。提供用户管理、角色管理。并提供登录认证、权限查询等接口。鉴权服务及相关API是核心交付件,也是能够被重用的部分。开发者可以基于这个项目开发认证鉴权服务。 | ||
|
||
* Gateway | ||
提供请求拦截,校验用户是否已经经过认证。一方面演示网关如何和配套鉴权服务完成开发,本项目也是自动化测试的组成部分。 | ||
|
||
* Client | ||
Client模拟的是使用使用者。一方面演示客户端如何获取Token,本项目也是自动化测试的组成部分。 | ||
|
||
* ResourceServer | ||
ResourceServer模拟的是业务服务。一方面演示业务服务如何进行权限配置,本项目也是自动化测试的组成部分。 | ||
|
||
* Api | ||
认证鉴权提取的公共功能,作为复用单元。目前项目处于初始阶段,很多复用代码分散在其他项目中。 | ||
|
||
|
||
* 测试介绍 | ||
|
||
本项目实现了微服务架构的自动化测试。启动AuthenticationServer、Gateway、Client、ResourceServer后,可以提供 | ||
|
||
``` | ||
http://localhost:9093/v1/test/start | ||
``` | ||
触发测试用例的执行。 所有的测试用例放到Client微服务里面, 这个微服务实现了简单的测试框架帮助书写测试用例,对测试结果进行检查等功能。 | ||
|
||
测试项目同时展示了这个项目的功能,比如: AuthenticationTestCase 的测试逻辑展示了基本的认证功能,从登陆,到接口的权限检查。 | ||
|
||
# TODO LIST | ||
1. provide TLS for authentication server & edge service | ||
2. grant scope for INTERNAL access & EXTERNAL access | ||
3. access token support: a. use access token to get optional scope or roles token. 这个可以解决角色过多的时候, token过大的一些问题 | ||
4. 实现注销逻辑(会话管理) | ||
5. 支持分层的角色机制 | ||
|
||
ROLE_LEVEL1 | ||
/ \ | ||
ROLE_LEVEL2 ROLE_LEVEL2 | ||
|
||
TOKEN里面只返回ROLE_LEVEL1,设置为ROLE_LEVEL2访问的操作,也可以访问。 | ||
|
||
6. REFRESH_TOKEN可以用来实现申请不同SCOPE的TOKEN。 | ||
7. 设计目标:无状态。认证服务器和资源服务器均可以多实例部署,每个实例之间不共享状态。在实现很多功能的时候,都遵循这个约束。包括通过refresh token获取新的access token的时候。遵循这个约束,意味着请求需要同时传递refresh token和access token。 | ||
8, 重新设计TOKEN(代码重构、支持会话管理),支持OpenID Connect。 | ||
|
||
OAUTH的不好的地方:TOKEN在有效期内,容易被利用,无法注销;TOKEN过期后,必须重新认证,和用户是否在一直操作无关,体验不好,虽然可以通过refresh_token获取新的token提升体验,但是refresh_token有效期如果设置的太长,会降低安全性。Token在有效期内,如果修改了权限等信息,无法及时感知,需要重新登录。 | ||
OAUTH的好的地方:TOKEN签发、认证都可以由微服务实例独自完成,不需要共用的数据存储,比如数据库、Redis等,效率更高,弹性扩容。 | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<!-- | ||
~ Licensed to the Apache Software Foundation (ASF) under one or more | ||
~ contributor license agreements. See the NOTICE file distributed with | ||
~ this work for additional information regarding copyright ownership. | ||
~ The ASF licenses this file to You 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. | ||
--> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>org.apache.servicecomb.authentication</groupId> | ||
<artifactId>authentication-server-api</artifactId> | ||
<version>0.0.1-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>authentication-server-api-endpoint</artifactId> | ||
<packaging>jar</packaging> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>org.apache.servicecomb.authentication</groupId> | ||
<artifactId>authentication-server-api-service</artifactId> | ||
<version>${project.parent.version}</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.apache.servicecomb.authentication</groupId> | ||
<artifactId>authentication-common-api-service</artifactId> | ||
<version>${project.parent.version}</version> | ||
</dependency> | ||
</dependencies> | ||
</project> |
100 changes: 100 additions & 0 deletions
100
...oint/src/main/java/org/apache/servicecomb/authentication/server/PasswordTokenGranter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You 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 org.apache.servicecomb.authentication.server; | ||
|
||
import java.util.Map; | ||
import java.util.UUID; | ||
|
||
import org.apache.servicecomb.authentication.jwt.JWTClaims; | ||
import org.apache.servicecomb.authentication.jwt.JsonParser; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import org.springframework.beans.factory.annotation.Qualifier; | ||
import org.springframework.security.core.userdetails.UserDetails; | ||
import org.springframework.security.core.userdetails.UserDetailsService; | ||
import org.springframework.security.crypto.password.PasswordEncoder; | ||
import org.springframework.security.jwt.Jwt; | ||
import org.springframework.security.jwt.JwtHelper; | ||
import org.springframework.security.jwt.crypto.sign.Signer; | ||
import org.springframework.stereotype.Component; | ||
|
||
import com.netflix.config.DynamicPropertyFactory; | ||
|
||
@Component(value = "passwordTokenGranter") | ||
public class PasswordTokenGranter implements TokenGranter { | ||
@Autowired | ||
@Qualifier("authUserDetailsService") | ||
private UserDetailsService userDetailsService; | ||
|
||
@Autowired | ||
@Qualifier("authPasswordEncoder") | ||
private PasswordEncoder passwordEncoder; | ||
|
||
@Autowired | ||
@Qualifier("authSigner") | ||
private Signer signer; | ||
|
||
@Override | ||
public Token grant(Map<String, String> parameters) { | ||
String username = parameters.get(TokenConst.PARAM_USERNAME); | ||
String password = parameters.get(TokenConst.PARAM_PASSWORD); | ||
|
||
UserDetails userDetails = userDetailsService.loadUserByUsername(username); | ||
if (passwordEncoder.matches(password, userDetails.getPassword())) { | ||
JWTClaims claims = new JWTClaims(); | ||
if (userDetails.getAuthorities() != null) { | ||
userDetails.getAuthorities().forEach(authority -> claims.addAuthority(authority.getAuthority())); | ||
} | ||
claims.setJti(UUID.randomUUID().toString()); | ||
claims.setIat(System.currentTimeMillis()); | ||
claims.setExp(5 * 60); | ||
|
||
String content = JsonParser.unparse(claims); | ||
Jwt accessToken = JwtHelper.encode(content, signer); | ||
|
||
Token token = new Token(); | ||
token.setScope(claims.getScope()); | ||
token.setExpires_in(10 * 60); | ||
token.setToken_type("bearer"); | ||
token.setAccess_token(accessToken.getEncoded()); | ||
|
||
JWTClaims accessTokenClaims = new JWTClaims(); | ||
accessTokenClaims.setJti(UUID.randomUUID().toString()); | ||
accessTokenClaims.setIat(System.currentTimeMillis()); | ||
accessTokenClaims.setExp(60 * 60); | ||
Jwt refreshToken = JwtHelper.encode(JsonParser.unparse(claims), signer); | ||
token.setRefresh_token(refreshToken.getEncoded()); | ||
|
||
return token; | ||
} else { | ||
return null; | ||
} | ||
} | ||
|
||
@Override | ||
public String grantType() { | ||
return TokenConst.GRANT_TYPE_PASSWORD; | ||
} | ||
|
||
@Override | ||
public boolean enabled() { | ||
return DynamicPropertyFactory.getInstance() | ||
.getBooleanProperty("servicecomb.authentication.granter.password.enabled", true) | ||
.get(); | ||
} | ||
|
||
} |
Oops, something went wrong.