mirror of
https://github.com/exzork/GCAuth.git
synced 2024-11-24 00:23:58 +00:00
Implement access control
This commit is contained in:
parent
4f4c722b8c
commit
b06d249224
10
README.md
10
README.md
@ -1,22 +1,25 @@
|
|||||||
# GCAuth
|
# GCAuth
|
||||||
|
|
||||||
Grasscutter Authentication System
|
Grasscutter Authentication System
|
||||||
|
|
||||||
### Usage :
|
### Usage :
|
||||||
- Place jar inside plugins folder of Grasscutter.
|
- Place jar inside plugins folder of Grasscutter.
|
||||||
- To change hash algorithm change `Hash` in config.json inside plugins/GCAuth (Only Bcrypt and Scrypt is supported)
|
- To change hash algorithm change `Hash` in config.json inside plugins/GCAuth (Only Bcrypt and Scrypt is supported)
|
||||||
|
- To use access control, you need set the `ACCESS_KEY` in config.json inside plugins/GCAuth. (Optional)
|
||||||
- All payload must be send with `application/json` and Compact JSON format ( without unnecessary spaces )
|
- All payload must be send with `application/json` and Compact JSON format ( without unnecessary spaces )
|
||||||
- Auth endpoint is:
|
- Auth endpoint is:
|
||||||
- Authentication Checking : `/authentication/type` (GET) , it'll return `me.exzork.gcauth.handler.GCAuthAuthenticationHandler` if GCAuth is loaded and enabled.
|
- Authentication Checking : `/authentication/type` (GET) , it'll return `me.exzork.gcauth.handler.GCAuthAuthenticationHandler` if GCAuth is loaded and enabled.
|
||||||
- Register: `/authentication/register` (POST)
|
- Register: `/authentication/register` (POST)
|
||||||
```
|
```
|
||||||
{"username":"username","password":"password","password_confirmation":"password_confirmation"}
|
{"username":"username","password":"password","password_confirmation":"password_confirmation","access_key":"access_key"}
|
||||||
```
|
```
|
||||||
- Login: `/authentication/login` (POST)
|
- Login: `/authentication/login` (POST)
|
||||||
```
|
```
|
||||||
{"username":"username","password":"password"}
|
{"username":"username","password":"password","access_key":"access_key"}
|
||||||
```
|
```
|
||||||
- Change password: `/authentication/change_password` (POST)
|
- Change password: `/authentication/change_password` (POST)
|
||||||
```
|
```
|
||||||
{"username":"username","new_password":"new_password","new_password_confirmation":"new_password_confirmation","old_password":"old_password"}
|
{"username":"username","new_password":"new_password","new_password_confirmation":"new_password_confirmation","old_password":"old_password","access_key":"access_key"}
|
||||||
```
|
```
|
||||||
- Response is `JSON` with following keys:
|
- Response is `JSON` with following keys:
|
||||||
- `status` : `success` or `error`
|
- `status` : `success` or `error`
|
||||||
@ -29,6 +32,7 @@ Grasscutter Authentication System
|
|||||||
- UNKNOWN : Unknown error
|
- UNKNOWN : Unknown error
|
||||||
- INVALID_ACCOUNT : Username or password is invalid
|
- INVALID_ACCOUNT : Username or password is invalid
|
||||||
- NO_PASSWORD : Password is not set, please set password first by resetting it (change password)
|
- NO_PASSWORD : Password is not set, please set password first by resetting it (change password)
|
||||||
|
- ERROR_ACCESS_KEY : Access key is invalid (if access control is enabled)
|
||||||
- `jwt` : JWT token if success with body :
|
- `jwt` : JWT token if success with body :
|
||||||
- `token` : Token used for authentication, paste it in username field of client.
|
- `token` : Token used for authentication, paste it in username field of client.
|
||||||
- `username` : Username of the user.
|
- `username` : Username of the user.
|
||||||
|
@ -5,4 +5,5 @@ import me.exzork.gcauth.utils.Authentication;
|
|||||||
public final class Config {
|
public final class Config {
|
||||||
public String Hash = "BCRYPT";
|
public String Hash = "BCRYPT";
|
||||||
public String jwtSecret = Authentication.generateRandomString(32);
|
public String jwtSecret = Authentication.generateRandomString(32);
|
||||||
|
public String ACCESS_KEY = "";
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import emu.grasscutter.game.Account;
|
|||||||
import express.http.HttpContextHandler;
|
import express.http.HttpContextHandler;
|
||||||
import express.http.Request;
|
import express.http.Request;
|
||||||
import express.http.Response;
|
import express.http.Response;
|
||||||
|
import me.exzork.gcauth.GCAuth;
|
||||||
import me.exzork.gcauth.json.AuthResponseJson;
|
import me.exzork.gcauth.json.AuthResponseJson;
|
||||||
import me.exzork.gcauth.json.ChangePasswordAccount;
|
import me.exzork.gcauth.json.ChangePasswordAccount;
|
||||||
import me.exzork.gcauth.utils.Authentication;
|
import me.exzork.gcauth.utils.Authentication;
|
||||||
@ -25,30 +26,36 @@ public class ChangePasswordHandler implements HttpContextHandler {
|
|||||||
authResponse.jwt = "";
|
authResponse.jwt = "";
|
||||||
} else {
|
} else {
|
||||||
ChangePasswordAccount changePasswordAccount = new Gson().fromJson(requestBody, ChangePasswordAccount.class);
|
ChangePasswordAccount changePasswordAccount = new Gson().fromJson(requestBody, ChangePasswordAccount.class);
|
||||||
if (changePasswordAccount.new_password.equals(changePasswordAccount.new_password_confirmation)) {
|
if (!GCAuth.getConfigStatic().ACCESS_KEY.isEmpty() && !GCAuth.getConfigStatic().ACCESS_KEY.equals(changePasswordAccount.access_key)){
|
||||||
Account account = Authentication.getAccountByUsernameAndPassword(changePasswordAccount.username, changePasswordAccount.old_password);
|
authResponse.success = false;
|
||||||
if (account == null) {
|
authResponse.message = "ERROR_ACCESS_KEY"; // ENG = "Error access key was sent with the request"
|
||||||
authResponse.success = false;
|
authResponse.jwt = "";
|
||||||
authResponse.message = "INVALID_ACCOUNT"; // ENG = "Invalid username or password"
|
} else {
|
||||||
authResponse.jwt = "";
|
if (changePasswordAccount.new_password.equals(changePasswordAccount.new_password_confirmation)) {
|
||||||
} else {
|
Account account = Authentication.getAccountByUsernameAndPassword(changePasswordAccount.username, changePasswordAccount.old_password);
|
||||||
if (changePasswordAccount.new_password.length() >= 8) {
|
if (account == null) {
|
||||||
String newPassword = Authentication.generateHash(changePasswordAccount.new_password);
|
authResponse.success = false;
|
||||||
account.setPassword(newPassword);
|
authResponse.message = "INVALID_ACCOUNT"; // ENG = "Invalid username or password"
|
||||||
account.save();
|
|
||||||
authResponse.success = true;
|
|
||||||
authResponse.message = "";
|
|
||||||
authResponse.jwt = "";
|
authResponse.jwt = "";
|
||||||
} else {
|
} else {
|
||||||
authResponse.success = false;
|
if (changePasswordAccount.new_password.length() >= 8) {
|
||||||
authResponse.message = "PASSWORD_INVALID"; // ENG = "Password must be at least 8 characters long"
|
String newPassword = Authentication.generateHash(changePasswordAccount.new_password);
|
||||||
authResponse.jwt = "";
|
account.setPassword(newPassword);
|
||||||
|
account.save();
|
||||||
|
authResponse.success = true;
|
||||||
|
authResponse.message = "";
|
||||||
|
authResponse.jwt = "";
|
||||||
|
} else {
|
||||||
|
authResponse.success = false;
|
||||||
|
authResponse.message = "PASSWORD_INVALID"; // ENG = "Password must be at least 8 characters long"
|
||||||
|
authResponse.jwt = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
authResponse.success = false;
|
||||||
|
authResponse.message = "PASSWORD_MISMATCH"; // ENG = "Passwords do not match."
|
||||||
|
authResponse.jwt = "";
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
authResponse.success = false;
|
|
||||||
authResponse.message = "PASSWORD_MISMATCH"; // ENG = "Passwords do not match."
|
|
||||||
authResponse.jwt = "";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -44,6 +44,11 @@ public class GCAuthAuthenticationHandler implements AuthenticationHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean verifyUser(String details) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public LoginResultJson handleGameLogin(Request request, LoginAccountRequestJson requestData) {
|
public LoginResultJson handleGameLogin(Request request, LoginAccountRequestJson requestData) {
|
||||||
LoginResultJson responseData = new LoginResultJson();
|
LoginResultJson responseData = new LoginResultJson();
|
||||||
|
@ -6,6 +6,7 @@ import emu.grasscutter.game.Account;
|
|||||||
import express.http.HttpContextHandler;
|
import express.http.HttpContextHandler;
|
||||||
import express.http.Request;
|
import express.http.Request;
|
||||||
import express.http.Response;
|
import express.http.Response;
|
||||||
|
import me.exzork.gcauth.GCAuth;
|
||||||
import me.exzork.gcauth.json.AuthResponseJson;
|
import me.exzork.gcauth.json.AuthResponseJson;
|
||||||
import me.exzork.gcauth.json.LoginGenerateToken;
|
import me.exzork.gcauth.json.LoginGenerateToken;
|
||||||
import me.exzork.gcauth.utils.Authentication;
|
import me.exzork.gcauth.utils.Authentication;
|
||||||
@ -26,20 +27,26 @@ public class LoginHandler implements HttpContextHandler {
|
|||||||
authResponse.jwt = "";
|
authResponse.jwt = "";
|
||||||
} else {
|
} else {
|
||||||
LoginGenerateToken loginGenerateToken = new Gson().fromJson(requestBody, LoginGenerateToken.class);
|
LoginGenerateToken loginGenerateToken = new Gson().fromJson(requestBody, LoginGenerateToken.class);
|
||||||
Account account = Authentication.getAccountByUsernameAndPassword(loginGenerateToken.username, loginGenerateToken.password);
|
if (!GCAuth.getConfigStatic().ACCESS_KEY.isEmpty() && !GCAuth.getConfigStatic().ACCESS_KEY.equals(loginGenerateToken.access_key)){
|
||||||
if (account == null) {
|
|
||||||
authResponse.success = false;
|
authResponse.success = false;
|
||||||
authResponse.message = "INVALID_ACCOUNT"; // ENG = "Invalid username or password"
|
authResponse.message = "ERROR_ACCESS_KEY"; // ENG = "Error access key was sent with the request"
|
||||||
authResponse.jwt = "";
|
authResponse.jwt = "";
|
||||||
} else {
|
} else {
|
||||||
if (account.getPassword() != null && !account.getPassword().isEmpty()) {
|
Account account = Authentication.getAccountByUsernameAndPassword(loginGenerateToken.username, loginGenerateToken.password);
|
||||||
authResponse.success = true;
|
if (account == null) {
|
||||||
authResponse.message = "";
|
|
||||||
authResponse.jwt = Authentication.generateJwt(account);
|
|
||||||
} else {
|
|
||||||
authResponse.success = false;
|
authResponse.success = false;
|
||||||
authResponse.message = "NO_PASSWORD"; // ENG = "There is no account password set. Please create a password by resetting it."
|
authResponse.message = "INVALID_ACCOUNT"; // ENG = "Invalid username or password"
|
||||||
authResponse.jwt = "";
|
authResponse.jwt = "";
|
||||||
|
} else {
|
||||||
|
if (account.getPassword() != null && !account.getPassword().isEmpty()) {
|
||||||
|
authResponse.success = true;
|
||||||
|
authResponse.message = "";
|
||||||
|
authResponse.jwt = Authentication.generateJwt(account);
|
||||||
|
} else {
|
||||||
|
authResponse.success = false;
|
||||||
|
authResponse.message = "NO_PASSWORD"; // ENG = "There is no account password set. Please create a password by resetting it."
|
||||||
|
authResponse.jwt = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ import emu.grasscutter.game.Account;
|
|||||||
import express.http.HttpContextHandler;
|
import express.http.HttpContextHandler;
|
||||||
import express.http.Request;
|
import express.http.Request;
|
||||||
import express.http.Response;
|
import express.http.Response;
|
||||||
|
import me.exzork.gcauth.GCAuth;
|
||||||
import me.exzork.gcauth.json.AuthResponseJson;
|
import me.exzork.gcauth.json.AuthResponseJson;
|
||||||
import me.exzork.gcauth.json.RegisterAccount;
|
import me.exzork.gcauth.json.RegisterAccount;
|
||||||
import me.exzork.gcauth.utils.Authentication;
|
import me.exzork.gcauth.utils.Authentication;
|
||||||
@ -26,43 +27,49 @@ public class RegisterHandler implements HttpContextHandler {
|
|||||||
authResponse.jwt = "";
|
authResponse.jwt = "";
|
||||||
} else {
|
} else {
|
||||||
RegisterAccount registerAccount = new Gson().fromJson(requestBody, RegisterAccount.class);
|
RegisterAccount registerAccount = new Gson().fromJson(requestBody, RegisterAccount.class);
|
||||||
if (registerAccount.password.equals(registerAccount.password_confirmation)) {
|
if (!GCAuth.getConfigStatic().ACCESS_KEY.isEmpty() && !GCAuth.getConfigStatic().ACCESS_KEY.equals(registerAccount.access_key)){
|
||||||
if (registerAccount.password.length() >= 8) {
|
authResponse.success = false;
|
||||||
String password = Authentication.generateHash(registerAccount.password);
|
authResponse.message = "ERROR_ACCESS_KEY"; // ENG = "Error access key was sent with the request"
|
||||||
try{
|
authResponse.jwt = "";
|
||||||
Account account = Authentication.getAccountByUsernameAndPassword(registerAccount.username, "");
|
} else {
|
||||||
if (account != null) {
|
if (registerAccount.password.equals(registerAccount.password_confirmation)) {
|
||||||
account.setPassword(password);
|
if (registerAccount.password.length() >= 8) {
|
||||||
account.save();
|
String password = Authentication.generateHash(registerAccount.password);
|
||||||
authResponse.success = true;
|
try{
|
||||||
authResponse.message = "";
|
Account account = Authentication.getAccountByUsernameAndPassword(registerAccount.username, "");
|
||||||
authResponse.jwt = "";
|
if (account != null) {
|
||||||
} else {
|
account.setPassword(password);
|
||||||
account = DatabaseHelper.createAccountWithPassword(registerAccount.username, password);
|
account.save();
|
||||||
if (account == null) {
|
|
||||||
authResponse.success = false;
|
|
||||||
authResponse.message = "USERNAME_TAKEN"; // ENG = "Username has already been taken by another user."
|
|
||||||
authResponse.jwt = "";
|
|
||||||
} else {
|
|
||||||
authResponse.success = true;
|
authResponse.success = true;
|
||||||
authResponse.message = "";
|
authResponse.message = "";
|
||||||
authResponse.jwt = "";
|
authResponse.jwt = "";
|
||||||
|
} else {
|
||||||
|
account = DatabaseHelper.createAccountWithPassword(registerAccount.username, password);
|
||||||
|
if (account == null) {
|
||||||
|
authResponse.success = false;
|
||||||
|
authResponse.message = "USERNAME_TAKEN"; // ENG = "Username has already been taken by another user."
|
||||||
|
authResponse.jwt = "";
|
||||||
|
} else {
|
||||||
|
authResponse.success = true;
|
||||||
|
authResponse.message = "";
|
||||||
|
authResponse.jwt = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}catch (Exception ignored){
|
||||||
|
authResponse.success = false;
|
||||||
|
authResponse.message = "UNKNOWN"; // ENG = "Username has already been taken by another user."
|
||||||
|
authResponse.jwt = "";
|
||||||
}
|
}
|
||||||
}catch (Exception ignored){
|
} else {
|
||||||
authResponse.success = false;
|
authResponse.success = false;
|
||||||
authResponse.message = "UNKNOWN"; // ENG = "Username has already been taken by another user."
|
authResponse.message = "PASSWORD_INVALID"; // ENG = "Password must be at least 8 characters long"
|
||||||
authResponse.jwt = "";
|
authResponse.jwt = "";
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
authResponse.success = false;
|
authResponse.success = false;
|
||||||
authResponse.message = "PASSWORD_INVALID"; // ENG = "Password must be at least 8 characters long"
|
authResponse.message = "PASSWORD_MISMATCH"; // ENG = "Passwords do not match."
|
||||||
authResponse.jwt = "";
|
authResponse.jwt = "";
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
authResponse.success = false;
|
|
||||||
authResponse.message = "PASSWORD_MISMATCH"; // ENG = "Passwords do not match."
|
|
||||||
authResponse.jwt = "";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
@ -5,4 +5,5 @@ public class ChangePasswordAccount {
|
|||||||
public String new_password;
|
public String new_password;
|
||||||
public String new_password_confirmation;
|
public String new_password_confirmation;
|
||||||
public String old_password;
|
public String old_password;
|
||||||
|
public String access_key;
|
||||||
}
|
}
|
||||||
|
@ -3,4 +3,5 @@ package me.exzork.gcauth.json;
|
|||||||
public class LoginGenerateToken {
|
public class LoginGenerateToken {
|
||||||
public String username;
|
public String username;
|
||||||
public String password;
|
public String password;
|
||||||
|
public String access_key;
|
||||||
}
|
}
|
||||||
|
@ -4,4 +4,5 @@ public class RegisterAccount {
|
|||||||
public String username;
|
public String username;
|
||||||
public String password;
|
public String password;
|
||||||
public String password_confirmation;
|
public String password_confirmation;
|
||||||
|
public String access_key;
|
||||||
}
|
}
|
||||||
|
@ -49,12 +49,11 @@ public final class Authentication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static String generateJwt(Account account) {
|
public static String generateJwt(Account account) {
|
||||||
String jws = JWT.create()
|
return JWT.create()
|
||||||
.withClaim("token",generateOneTimeToken(account))
|
.withClaim("token",generateOneTimeToken(account))
|
||||||
.withClaim("username",account.getUsername())
|
.withClaim("username",account.getUsername())
|
||||||
.withClaim("uid",account.getPlayerUid())
|
.withClaim("uid",account.getPlayerUid())
|
||||||
.sign(key);
|
.sign(key);
|
||||||
return jws;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String generateHash(String password) {
|
public static String generateHash(String password) {
|
||||||
|
Loading…
Reference in New Issue
Block a user