[home]开源官网初始化
This commit is contained in:
@@ -0,0 +1,14 @@
|
||||
---
|
||||
id: sample-bootstrap
|
||||
title: Springboot项目集成-配置文件方案
|
||||
sidebar_label: Springboot项目集成-配置文件方案
|
||||
---
|
||||
|
||||
[Springboot项目集成-配置文件方案代码仓库地址](https://github.com/tomsun28/sureness/tree/master/sample-bootstrap)
|
||||
|
||||
- 基于`springboot`
|
||||
- 从默认的配置文件`sureness.yml`加载账户信息,资源角色,过滤资源等信息
|
||||
- 使用默认的`sureness-config`
|
||||
- 使用默认的`JWT, Basic Auth, Digest Auth`方式认证鉴权
|
||||
- 保护入口: `SurenessFilterExample`
|
||||
- 推荐使用`postman`测试,测试样例为`sample-bootstrap-postman.json`,导入`postman`即可
|
||||
@@ -0,0 +1,296 @@
|
||||
---
|
||||
id: sample-javalin
|
||||
title: Javalin项目集成
|
||||
sidebar_label: Javalin项目集成
|
||||
---
|
||||
|
||||
|
||||
# Using Sureness to protect the security of Javalin REST API
|
||||
|
||||
[javalin-sureness sample repository](https://github.com/tomsun28/sureness/tree/master/samples/javalin-sureness)
|
||||
|
||||
Using Sureness to secure Javalin REST API by providing authentication(JWT,Basic,Digest) and authorization(RBAC)
|
||||
|
||||
|
||||
## What You Will Learn
|
||||
|
||||
* Creating a simple REST API using Javalin
|
||||
* Learn how to integrate Sureness into a Javalin application
|
||||
* Learn how to issue a JWT
|
||||
* Test API authentication - use JWT Auth, Basic Auth, Digest Auth to test the security of the REST API
|
||||
* Test API authorization - use different users to verify that they can access the REST API
|
||||
|
||||
|
||||
The tutorial assumes that you know what JWT, Basic Auth, Digest Auth, RBAC are. If you
|
||||
do not, then you can check [jwt](https://jwt.io/introduction/), [basic auth](https://docs.oracle.com/cd/E50612_01/doc.11122/user_guide/content/authn_http_basic.html) , [digest auth](https://docs.oracle.com/cd/E50612_01/doc.11122/user_guide/content/authn_http_digest.html), [rbac](https://en.wikipedia.org/wiki/Role-based_access_control) for an introduction.
|
||||
|
||||
## Setting Up Dependencies
|
||||
|
||||
First, you will need to create a maven project and add Javalin, Sureness dependencies coordinate
|
||||
|
||||
````
|
||||
<dependency>
|
||||
<groupId>io.javalin</groupId>
|
||||
<artifactId>javalin</artifactId>
|
||||
<version>{{site.javalinversion}}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usthe.sureness</groupId>
|
||||
<artifactId>sureness-core</artifactId>
|
||||
<version>1.0.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<version>1.7.30</version>
|
||||
</dependency>
|
||||
````
|
||||
|
||||
|
||||
## Setting Up Javalin and Create REST API
|
||||
|
||||
We need to create a simple Javalin app and provide some REST API for test.
|
||||
|
||||
```
|
||||
// init javalin
|
||||
Javalin app = Javalin.create().start(8088);
|
||||
```
|
||||
|
||||
```
|
||||
// create simple rest api
|
||||
// simple rest api
|
||||
app.routes(() ->
|
||||
path("api", () -> {
|
||||
path("v3", () -> {
|
||||
get("host", ctx -> ctx.result("get /api/v3/host success"));
|
||||
put("book", ctx -> ctx.result("put /api/v3/book success"));
|
||||
});
|
||||
path("v2", () -> {
|
||||
path("host", () -> {
|
||||
get(ctx -> ctx.result("get /api/v2/host success"));
|
||||
post(ctx -> ctx.result("post /api/v2/host success"));
|
||||
put(ctx -> ctx.result("put /api/v2/host success"));
|
||||
delete(ctx -> ctx.result("delete /api/v2/host success"));
|
||||
});
|
||||
});
|
||||
path("v1", () -> {
|
||||
path("source1", () -> {
|
||||
get(ctx -> ctx.result("get /api/v1/source1 success"));
|
||||
post(ctx -> ctx.result("post /api/v1/source1 success"));
|
||||
put(ctx -> ctx.result("put /api/v1/source1 success"));
|
||||
delete(ctx -> ctx.result("delete /api/v1/source1 success"));
|
||||
});
|
||||
});
|
||||
}));
|
||||
```
|
||||
|
||||
|
||||
## Setting Up Sureness
|
||||
|
||||
#### 1. Use the Default Configuration to Configure Sureness
|
||||
|
||||
The default configuration -`DefaultSurenessConfig` uses the document datasource `sureness.yml` as the auth datasource.
|
||||
It supports JWT, Basic Auth, Digest Auth authentication.
|
||||
```
|
||||
public static void main(String[] args) {
|
||||
// init sureness default config
|
||||
new DefaultSurenessConfig();
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. Config Document Datasource - `sureness.yml`
|
||||
|
||||
Sureness authentication requires us to provide our own account data, role permission data. These data may come from document, databases,, annotations, etc. When we use sureness default configuration above, the datasource is document - `sureness.yml`.
|
||||
|
||||
Create a file named `sureness.yml` in the `resource` directory. Configure account data, role permission data in the `sureness.yml`. eg:
|
||||
|
||||
````yaml
|
||||
## -- sureness.yml document dataSource-- ##
|
||||
|
||||
# load api resource which need be protected, config role who can access these resource.
|
||||
# resources that are not configured are also authenticated and protected by default, but not authorized
|
||||
# eg: /api/v2/host===post===[role2,role3] means /api/v2/host===post can be access by role2,role3
|
||||
# eg: /api/v1/source2===get===[] means /api/v1/source2===get can not be access by any role
|
||||
resourceRole:
|
||||
- /api/v1/source1===get===[role2]
|
||||
- /api/v1/source1===post===[role1]
|
||||
- /api/v1/source1===delete===[role3]
|
||||
- /api/v1/source1===put===[role1,role2]
|
||||
- /api/v1/source2===get===[]
|
||||
- /api/v2/host===post===[role2,role3]
|
||||
- /api/v2/host===get===[role2,role3]
|
||||
- /api/v2/host===delete===[role2,role3]
|
||||
- /api/v2/host===put===[role2,role3]
|
||||
- /api/v3/*===*===[role1,role2,role3]
|
||||
|
||||
# load api resource which do not need be protected, means them need be excluded.
|
||||
# these api resource can be access by everyone
|
||||
excludedResource:
|
||||
- /api/v3/host===get
|
||||
- /**/*.html===get
|
||||
- /**/*.js===get
|
||||
- /**/*.css===get
|
||||
- /**/*.ico===get
|
||||
|
||||
# account info
|
||||
# there are three account: admin, root, tom
|
||||
# eg: admin has [role1,role2] ROLE, unencrypted password is admin, encrypted password is 0192023A7BBD73250516F069DF18B500
|
||||
# eg: root has role1, unencrypted password is 23456
|
||||
# eg: tom has role3, unencrypted password is 32113
|
||||
account:
|
||||
- appId: admin
|
||||
# if add salt, the password is encrypted password - the result: MD5(password+salt)
|
||||
# digest auth not support encrypted password
|
||||
# if no salt, the password is unencrypted password
|
||||
credential: 0192023A7BBD73250516F069DF18B500
|
||||
salt: 123
|
||||
role: [role1,role2]
|
||||
- appId: root
|
||||
credential: 23456
|
||||
role: [role1,role2]
|
||||
- appId: tom
|
||||
credential: 32113
|
||||
role: [role3]
|
||||
|
||||
````
|
||||
|
||||
|
||||
|
||||
#### 3. Add an Interceptor Intercepting All Requests
|
||||
|
||||
The essence of sureness is to intercept all rest requests for authenticating and authorizing. The interceptor can be a filter or interceptor, it intercepts all request to check them. In Javalin, we use `app.before()`.
|
||||
|
||||
```
|
||||
// intercept all rest requests for authenticating and authorizing
|
||||
app.before(ctx -> {
|
||||
SubjectSum subject = SurenessSecurityManager.getInstance().checkIn(ctx.req);
|
||||
// when auth error , the exception throw, you should use app.exception() catch it and define return
|
||||
if (subject != null) {
|
||||
SurenessContextHolder.bindSubject(subject);
|
||||
}
|
||||
});
|
||||
|
||||
app.after(ctx -> SurenessContextHolder.unbindSubject());
|
||||
|
||||
```
|
||||
|
||||
#### 4. Last, Implement Auth Exception Handling Process
|
||||
|
||||
Sureness uses exception handling process:
|
||||
|
||||
- If auth success, method - `checkIn()` will return a `SubjectSum` object containing user information.
|
||||
- If auth failure, method - `checkIn()` will throw different types of auth exceptions.
|
||||
|
||||
We need to continue the subsequent process based on these exceptions.(eg: return the request response)
|
||||
|
||||
Here we need to customize the exceptions thrown by `checkIn`, passed directly when auth success, catch exception when auth failure and do something:
|
||||
|
||||
````
|
||||
// when auth error , the exception throw, you should use app.exception() catch it and define return
|
||||
app.exception(UnknownAccountException.class, (e, ctx) -> {
|
||||
log.debug("this request user account not exist");
|
||||
ctx.status(401).result(e.getMessage());
|
||||
}).exception(IncorrectCredentialsException.class, (e, ctx) -> {
|
||||
log.debug("this account credential is incorrect");
|
||||
ctx.status(401).result(e.getMessage());
|
||||
}).exception(ExpiredCredentialsException.class, (e, ctx) -> {
|
||||
log.debug("this account credential expired");
|
||||
ctx.status(401).result(e.getMessage());
|
||||
}).exception(NeedDigestInfoException.class, (e, ctx) -> {
|
||||
log.debug("you should try once again with digest auth information");
|
||||
ctx.status(401).header("WWW-Authenticate", e.getAuthenticate());
|
||||
}).exception(UnauthorizedException.class, (e, ctx) -> {
|
||||
log.debug("this account can not access this resource");
|
||||
ctx.status(403).result(e.getMessage());
|
||||
}).exception(Exception.class, (e, ctx) -> {
|
||||
log.error("other exception happen: ", e);
|
||||
ctx.status(500).result(e.getMessage());
|
||||
});
|
||||
|
||||
````
|
||||
|
||||
|
||||
## Provide an Issue JWT Api
|
||||
|
||||
Now we provide a REST API to issue JWT. We can use this JWT to test JWT auth.
|
||||
|
||||
````
|
||||
// issue jwt rest api
|
||||
app.get("/auth/token", ctx -> {
|
||||
SubjectSum subjectSum = SurenessContextHolder.getBindSubject();
|
||||
if (subjectSum == null) {
|
||||
ctx.result("Please auth!");
|
||||
} else {
|
||||
String principal = (String) subjectSum.getPrincipal();
|
||||
List<String> roles = (List<String>) subjectSum.getRoles();
|
||||
// issue jwt
|
||||
String jwt = JsonWebTokenUtil.issueJwt(UUID.randomUUID().toString(), principal,
|
||||
"token-server", 3600L, roles);
|
||||
ctx.result(jwt);
|
||||
}
|
||||
});
|
||||
````
|
||||
|
||||
**All done, we can test now!**
|
||||
|
||||
## Test
|
||||
|
||||
Through the above steps, a complete auth function project is completed. Someone maybe think that with only these few steps, where is its complete function and what can it support?
|
||||
This built project is based on the RBAC permission model and supports Baisc authentication, Digest authentication and JWT authentication. It can fine-grained control the user's access to the restful api provided by the Javalin. That is to control which users can access which api.
|
||||
|
||||
Let's test it. (we use postman and chrome to test.)
|
||||
|
||||
### Test Authentication
|
||||
|
||||
#### 1. Basic Auth Test
|
||||
|
||||
Use postman Basic auth, as shown below:
|
||||
|
||||
* success - input username: admin, password: admin
|
||||
|
||||

|
||||
|
||||
|
||||
* fail - input username: admin, password: 12345
|
||||
|
||||

|
||||
|
||||
#### 2. Digest Auth Test
|
||||
|
||||
Note: If password has been encrypted, Digest auth not support.(So the account admin not support Digest auth).
|
||||
Use chrome to Digest auth, as shown below:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
#### 3. JWT Auth Test
|
||||
|
||||
First, we should access **[GET /auth/token]** api to get a JWT to use, as shown below:
|
||||
|
||||

|
||||
|
||||
Then, use the JWT as Bearer Token to access REST API, as shown below:
|
||||
|
||||

|
||||
|
||||
|
||||
### Test Authorization
|
||||
|
||||
* success - user **tom** has role **role3**, the api **[DELETE - /api/v2/host]** support **role3** access, so **tom** can access api **[DELETE - /api/v2/host]** success, as shown below:
|
||||
|
||||

|
||||
|
||||
|
||||
* fail - user **tom** only has role **role3**, the api **[GET - /api/v1/source1]** only support **role2** access, not support **role3**, so **tom** can not access api **[GET - /api/v1/source1]**, as shown below:
|
||||
|
||||

|
||||
|
||||
|
||||
## Conclusion
|
||||
|
||||
Javalin is a framework dedicated to simplicity and ease of use, and so is Sureness.
|
||||
We hope you enjoy this tutorial. Of course, the tutorial only introduces a simple introduction. Our account data, role permission data can not only be written in `sureness.yml`, but also loaded and obtained from the database and annotations. We can also customize the authentication method, data source, etc.
|
||||
Finally, thank you again for reading.
|
||||
|
||||
[DEMO SOURCE CODE ON GITHUB](https://github.com/usthe/sureness/tree/master/samples/javalin-sureness)
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
id: sample-ktor
|
||||
title: Ktor项目集成
|
||||
sidebar_label: Ktor项目集成
|
||||
---
|
||||
|
||||
[ktor-sureness例子项目仓库地址](https://github.com/tomsun28/sureness/tree/master/samples/ktor-sureness)
|
||||
|
||||
- 基于`ktor, servlet`
|
||||
- 从默认的配置文件`sureness.yml`加载账户信息,资源角色,过滤资源等信息
|
||||
- 使用默认的`sureness-config`
|
||||
- 使用默认的`JWT, Basic Auth, Digest Auth`方式认证鉴权
|
||||
- 例子中包含`REST API`
|
||||
- 保护入口: `Application.kt`
|
||||
- 推荐使用`postman`测试
|
||||
|
||||
|
||||
@@ -0,0 +1,423 @@
|
||||
---
|
||||
id: sample-micronaut
|
||||
title: Micronaut项目集成
|
||||
sidebar_label: Micronaut项目集成
|
||||
---
|
||||
|
||||
Using Sureness to secure micronaut REST API by providing authentication(JWT,Basic,Digest) and authorization(RBAC)
|
||||
|
||||
|
||||
## What You Will Learn
|
||||
|
||||
* Creating a simple REST API using micronaut
|
||||
* Learn how to integrate Sureness into a micronaut application
|
||||
* Test API authentication - use JWT Auth, Basic Auth, Digest Auth to test the security of the REST API
|
||||
* Test API authorization - use different users to verify that they can access the REST API
|
||||
|
||||
|
||||
The tutorial assumes that you know what JWT, Basic Auth, Digest Auth, RBAC are. If you
|
||||
do not, then you can check [jwt](https://jwt.io/introduction/), [basic auth](https://docs.oracle.com/cd/E50612_01/doc.11122/user_guide/content/authn_http_basic.html) , [digest auth](https://docs.oracle.com/cd/E50612_01/doc.11122/user_guide/content/authn_http_digest.html), [rbac](https://en.wikipedia.org/wiki/Role-based_access_control) for an introduction.
|
||||
|
||||
## Setting Up Dependencies
|
||||
|
||||
First, you will need to create a maven project and add micronautn, Sureness dependencies coordinate
|
||||
|
||||
````
|
||||
|
||||
<properties>
|
||||
<release.version>8</release.version>
|
||||
<maven.compiler.source>1.8</maven.compiler.source>
|
||||
<maven.compiler.target>1.8</maven.compiler.target>
|
||||
<packaging>jar</packaging>
|
||||
<jdk.version>1.8</jdk.version>
|
||||
<micronaut.version>2.4.3</micronaut.version>
|
||||
<micronaut-maven-plugin.version>1.1.8</micronaut-maven-plugin.version>
|
||||
<maven-compiler-plugin.version>3.8.1</maven-compiler-plugin.version>
|
||||
<exec.mainClass>com.usthe.sureness.micronaut.Application</exec.mainClass>
|
||||
<micronaut.runtime>netty</micronaut.runtime>
|
||||
</properties>
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-bom</artifactId>
|
||||
<version>${micronaut.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</dependencyManagement>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
<version>1.7.30</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.usthe.sureness</groupId>
|
||||
<artifactId>sureness-core</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-inject</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-validation</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micronaut.test</groupId>
|
||||
<artifactId>micronaut-test-junit5</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-http-client</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-http-server-netty</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-runtime</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>io.micronaut.build</groupId>
|
||||
<artifactId>micronaut-maven-plugin</artifactId>
|
||||
<version>${micronaut-maven-plugin.version}</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>${maven-compiler-plugin.version}</version>
|
||||
<configuration>
|
||||
<annotationProcessorPaths combine.children="append">
|
||||
<path>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-inject-java</artifactId>
|
||||
<version>${micronaut.version}</version>
|
||||
</path>
|
||||
<path>
|
||||
<groupId>io.micronaut</groupId>
|
||||
<artifactId>micronaut-validation</artifactId>
|
||||
<version>${micronaut.version}</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
<compilerArgs>
|
||||
<arg>-Amicronaut.processing.group=com.usthe.sureness</arg>
|
||||
<arg>-Amicronaut.processing.module=micronaut-sureness</arg>
|
||||
</compilerArgs>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
|
||||
````
|
||||
|
||||
|
||||
- [User Guide](https://docs.micronaut.io/2.4.3/guide/index.html)
|
||||
- [API Reference](https://docs.micronaut.io/2.4.3/api/index.html)
|
||||
- [Configuration Reference](https://docs.micronaut.io/2.4.3/guide/configurationreference.html)
|
||||
- [Micronaut Guides](https://guides.micronaut.io/index.html)
|
||||
|
||||
We need to create a simple micronautn app and provide some REST API for test.
|
||||
|
||||
|
||||
|
||||
## Setting Up Sureness
|
||||
|
||||
#### 1.Run Micronaut Application
|
||||
|
||||
```
|
||||
|
||||
import io.micronaut.runtime.Micronaut;
|
||||
|
||||
|
||||
public class Application{
|
||||
|
||||
public static void main(String[] args) {
|
||||
Micronaut.run(Application.class, args);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### 2. Config Document Datasource - `sureness.yml`
|
||||
|
||||
Sureness authentication requires us to provide our own account data, role permission data. These data may come from document, databases,, annotations, etc. When we use sureness default configuration above, the datasource is document - `sureness.yml`.
|
||||
|
||||
Create a file named `sureness.yml` in the `resource` directory. Configure account data, role permission data in the `sureness.yml`. eg:
|
||||
|
||||
````yaml
|
||||
## -- sureness.yml document dataSource-- ##
|
||||
|
||||
# load api resource which need be protected, config role who can access these resource.
|
||||
# resources that are not configured are also authenticated and protected by default, but not authorized
|
||||
# eg: /api/v2/host===post===[role2,role3] means /api/v2/host===post can be access by role2,role3
|
||||
# eg: /api/v1/source2===get===[] means /api/v1/source2===get can not be access by any role
|
||||
resourceRole:
|
||||
- /api/v1/source1===get===[role2]
|
||||
- /api/v1/source1===post===[role1]
|
||||
- /api/v1/source1===delete===[role3]
|
||||
- /api/v1/source1===put===[role1,role2]
|
||||
- /api/v1/source2===get===[]
|
||||
- /api/v2/host===post===[role2,role3]
|
||||
- /api/v2/host===get===[role2,role3]
|
||||
- /api/v2/host===delete===[role2,role3]
|
||||
- /api/v2/host===put===[role2,role3]
|
||||
- /api/v3/*===*===[role1,role2,role3]
|
||||
|
||||
# load api resource which do not need be protected, means them need be excluded.
|
||||
# these api resource can be access by everyone
|
||||
excludedResource:
|
||||
- /api/v3/host===get
|
||||
- /**/*.html===get
|
||||
- /**/*.js===get
|
||||
- /**/*.css===get
|
||||
- /**/*.ico===get
|
||||
|
||||
# account info
|
||||
# there are three account: admin, root, tom
|
||||
# eg: admin has [role1,role2] ROLE, unencrypted password is admin, encrypted password is 0192023A7BBD73250516F069DF18B500
|
||||
# eg: root has role1, unencrypted password is 23456
|
||||
# eg: tom has role3, unencrypted password is 32113
|
||||
account:
|
||||
- appId: admin
|
||||
# if add salt, the password is encrypted password - the result: MD5(password+salt)
|
||||
# digest auth not support encrypted password
|
||||
# if no salt, the password is unencrypted password
|
||||
credential: 0192023A7BBD73250516F069DF18B500
|
||||
salt: 123
|
||||
role: [role1,role2]
|
||||
- appId: root
|
||||
credential: 23456
|
||||
role: [role1,role2]
|
||||
- appId: tom
|
||||
credential: 32113
|
||||
role: [role3]
|
||||
|
||||
````
|
||||
|
||||
|
||||
|
||||
#### 3. Add an Interceptor Intercepting All Requests
|
||||
|
||||
The essence of sureness is to intercept all rest requests for authenticating and authorizing. The interceptor can be a filter or interceptor, it intercepts all request to check them. In Micronaut, we use Filter
|
||||
```java
|
||||
@Filter("/**")
|
||||
public class MicronautSurenessFilterExample implements HttpServerFilter {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(MicronautSurenessFilterExample.class);
|
||||
|
||||
@Inject
|
||||
private SurenessSecurityManager securityManager ;
|
||||
|
||||
|
||||
@Override
|
||||
public Publisher<MutableHttpResponse<?>> doFilter(HttpRequest<?> request,
|
||||
ServerFilterChain chain) {
|
||||
Integer statusCode = null;
|
||||
String errorMsg = null;
|
||||
try {
|
||||
SubjectSum subject =securityManager.checkIn(request);
|
||||
if (subject != null) {
|
||||
SurenessContextHolder.bindSubject(subject);
|
||||
}
|
||||
} catch (ProcessorNotFoundException | UnknownAccountException | UnsupportedSubjectException e4) {
|
||||
logger.debug("this request is illegal");
|
||||
statusCode = HttpStatus.BAD_REQUEST.getCode();
|
||||
errorMsg = e4.getMessage();
|
||||
} catch (DisabledAccountException | ExcessiveAttemptsException e2 ) {
|
||||
logger.debug("the account is disabled");
|
||||
statusCode = HttpStatus.FORBIDDEN.getCode();
|
||||
errorMsg = e2.getMessage();
|
||||
} catch (IncorrectCredentialsException | ExpiredCredentialsException e3) {
|
||||
logger.debug("this account credential is incorrect or expired");
|
||||
statusCode = HttpStatus.FORBIDDEN.getCode();
|
||||
errorMsg = e3.getMessage();
|
||||
} catch (UnauthorizedException e5) {
|
||||
logger.debug("this account can not access this resource");
|
||||
statusCode = HttpStatus.FORBIDDEN.getCode();
|
||||
errorMsg = e5.getMessage();
|
||||
} catch (RuntimeException e) {
|
||||
logger.error("other exception happen: ", e);
|
||||
statusCode = HttpStatus.FORBIDDEN.getCode();
|
||||
errorMsg = e.getMessage();
|
||||
}
|
||||
if (statusCode != null && errorMsg != null) {
|
||||
String finalErrorMsg = errorMsg;
|
||||
Integer finalStatusCode = statusCode;
|
||||
logger.info(statusCode+"--->"+errorMsg);
|
||||
try {
|
||||
URI location = new URI("/auth/error");
|
||||
request = request.mutate().headers(httpHeaders -> {
|
||||
httpHeaders.add("statusCode", String.valueOf(finalStatusCode));
|
||||
httpHeaders.add("errorMsg", finalErrorMsg);
|
||||
}).uri(location);
|
||||
}catch (URISyntaxException e){
|
||||
logger.error("uri error");
|
||||
}
|
||||
}
|
||||
return chain.proceed(request);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return ServerFilterPhase.SECURITY.order();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
```
|
||||
SurenessSecurityManager configuration
|
||||
|
||||
```java
|
||||
import io.micronaut.context.annotation.Factory;
|
||||
|
||||
@Factory
|
||||
public class SurenessConfiguration {
|
||||
private static final Logger logger = LoggerFactory.getLogger(SurenessConfiguration.class);
|
||||
|
||||
@Factory
|
||||
public SurenessSecurityManager init() {
|
||||
SurenessAccountProvider accountProvider = new DocumentAccountProvider();
|
||||
List<Processor> processorList = new LinkedList<>();
|
||||
NoneProcessor noneProcessor = new NoneProcessor();
|
||||
processorList.add(noneProcessor);
|
||||
PasswordProcessor passwordProcessor = new PasswordProcessor();
|
||||
passwordProcessor.setAccountProvider(accountProvider);
|
||||
processorList.add(passwordProcessor);
|
||||
DefaultProcessorManager processorManager = new DefaultProcessorManager(processorList);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("DefaultProcessorManager init");
|
||||
}
|
||||
PathTreeProvider pathTreeProvider = new DocumentPathTreeProvider();
|
||||
DefaultPathRoleMatcher pathRoleMatcher = new DefaultPathRoleMatcher();
|
||||
pathRoleMatcher.setPathTreeProvider(pathTreeProvider);
|
||||
pathRoleMatcher.buildTree();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("DefaultPathRoleMatcher init");
|
||||
}
|
||||
|
||||
// SubjectFactory init
|
||||
SubjectFactory subjectFactory = new SurenessSubjectFactory();
|
||||
List<SubjectCreate> subjectCreates = Arrays.asList(
|
||||
new NoneSubjectReactiveCreator(),
|
||||
new BasicSubjectReactiveCreator());
|
||||
subjectFactory.registerSubjectCreator(subjectCreates);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("SurenessSubjectFactory init");
|
||||
}
|
||||
|
||||
// surenessSecurityManager init
|
||||
SurenessSecurityManager securityManager = SurenessSecurityManager.getInstance();
|
||||
securityManager.setPathRoleMatcher(pathRoleMatcher);
|
||||
securityManager.setSubjectFactory(subjectFactory);
|
||||
securityManager.setProcessorManager(processorManager);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("SurenessSecurityManager init");
|
||||
}
|
||||
return securityManager;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
#### 4. Last, Implement Auth Exception Handling Process
|
||||
|
||||
Sureness uses exception handling process:
|
||||
|
||||
- If auth success, method - `checkIn()` will return a `SubjectSum` object containing user information.
|
||||
- If auth failure, method - `checkIn()` will throw different types of auth exceptions.
|
||||
|
||||
We need to continue the subsequent process based on these exceptions.(eg: return the request response)
|
||||
|
||||
Here we need to customize the exceptions thrown by `checkIn`, passed directly when auth success, catch exception when auth failure and do something:
|
||||
|
||||
````
|
||||
// when auth error , add error msg to HttpRequest
|
||||
if (statusCode != null && errorMsg != null) {
|
||||
String finalErrorMsg = errorMsg;
|
||||
Integer finalStatusCode = statusCode;
|
||||
logger.info(statusCode+"--->"+errorMsg);
|
||||
try {
|
||||
URI location = new URI("/auth/error");
|
||||
request = request.mutate().headers(httpHeaders -> {
|
||||
httpHeaders.add("statusCode", String.valueOf(finalStatusCode));
|
||||
httpHeaders.add("errorMsg", finalErrorMsg);
|
||||
}).uri(location);
|
||||
}catch (URISyntaxException e){
|
||||
logger.error("uri error");
|
||||
}
|
||||
}
|
||||
|
||||
````
|
||||
|
||||
|
||||
**All done, we can test now!**
|
||||
|
||||
## Test
|
||||
|
||||
Through the above steps, a complete auth function project is completed. Someone maybe think that with only these few steps, where is its complete function and what can it support?
|
||||
This built project is based on the RBAC permission model and supports Baisc authentication, Digest authentication and JWT authentication. It can fine-grained control the user's access to the restful api provided by the Javalin. That is to control which users can access which api.
|
||||
|
||||
Let's test it. (we use postman and chrome to test.)
|
||||
|
||||
### Test Authentication
|
||||
|
||||
#### 1. Basic Auth Test
|
||||
|
||||
Use postman Basic auth, as shown below:
|
||||
|
||||
* success - input username: admin, password: admin
|
||||
|
||||

|
||||
|
||||
|
||||
* fail - input username: admin, password: admin1234
|
||||
|
||||

|
||||
|
||||
|
||||
## Conclusion
|
||||
|
||||
micronaut is a framework dedicated to simplicity and ease of use, and so is Sureness.
|
||||
We hope you enjoy this tutorial. Of course, the tutorial only introduces a simple introduction. Our account data, role permission data can not only be written in `sureness.yml`, but also loaded and obtained from the database and annotations. We can also customize the authentication method, data source, etc.
|
||||
Finally, thank you again for reading.
|
||||
|
||||
[DEMO SOURCE CODE ON GITHUB](https://github.com/usthe/sureness/tree/master/samples/javalin-sureness)
|
||||
@@ -0,0 +1,16 @@
|
||||
---
|
||||
id: sample-quarkus
|
||||
title: Quarkus项目集成
|
||||
sidebar_label: Quarkus项目集成
|
||||
---
|
||||
|
||||
[quarkus-sureness例子项目仓库地址](https://github.com/tomsun28/sureness/tree/master/samples/quarkus-sureness)
|
||||
|
||||
- 基于`quarkus, jax-rs`
|
||||
- 从默认的配置文件`sureness.yml`加载账户信息,资源角色,过滤资源等信息
|
||||
- 使用默认的`sureness-config`
|
||||
- 使用默认的`JWT, Basic Auth, Digest Auth`方式认证鉴权
|
||||
- 例子中包含`REST API`
|
||||
- 保护入口: `SurenessFilterExample`
|
||||
- 推荐使用`postman`测试
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
id: sample-spring-webflux
|
||||
title: Spring-Webflux项目集成
|
||||
sidebar_label: Spring-Webflux项目集成
|
||||
---
|
||||
|
||||
[spring-webflux-sureness例子项目仓库地址](https://github.com/tomsun28/sureness/tree/master/samples/spring-webflux-sureness)
|
||||
|
||||
- 基于`spring-webflux`
|
||||
- 自定义 `subject creator (BasicSubjectReactiveCreator, JwtSubjectReactiveCreator, NoneSubjectReactiveCreator)` 适配 `ServerHttpRequest` 请求体
|
||||
- 从默认的配置文件`sureness.yml`加载账户信息,资源角色,过滤资源等信息
|
||||
- 使用默认的`JWT, Basic Auth`方式认证鉴权
|
||||
- 例子中包含`REST API`
|
||||
- 保护入口: `SurenessFilterExample`
|
||||
- 推荐使用`postman`测试
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
id: sample-tom
|
||||
title: Springboot项目集成-数据库方案
|
||||
sidebar_label: Springboot项目集成-数据库方案
|
||||
---
|
||||
|
||||
[Springboot项目集成-数据库方案代码仓库地址](https://github.com/tomsun28/sureness/tree/master/sample-tom)
|
||||
|
||||
- 基于`springboot,jpa...`
|
||||
- 自定义数据源,使用从数据库加载账户信息,资源角色,过滤资源等信息,这样便于动态调整(见`AccountProvider ResourceProvider`)
|
||||
- 除了使用了默认的`JWT, Basic Auth`方式认证鉴权,新增自定义认证鉴权(自定义`subject subjectCreator processor...`)
|
||||
- 推荐使用`postman`测试,测试样例为`sample-tom-postman.json`,导入`postman`即可
|
||||
|
||||
样例中包含2种自定义认证鉴权方式:
|
||||
|
||||
1. 自定义了一个单独的`subjectCreator` 见 `CustomPasswdSubjectCreator`
|
||||
演示功能就是自定义的从不同地方获取请求体的账户密码,来创建默认的`PasswordSubject`,走默认的账户密码认证流程
|
||||
|
||||
2. 自定义了一整套流程(包含`subject subjectCreator processor`) 见 `CustomTokenSubject CustomTokenSubjectCreator CustomTokenProcessor`
|
||||
演示功能就是自定义一个简单的`token`作为`subject`对象,对其自定义创建获取方式-`creator`和自定义认证鉴权处理流程-`processor`.
|
||||
此自定义流程也演示了一个简单的`token`刷新流程
|
||||
Reference in New Issue
Block a user