├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src
└── main
└── java
└── com
└── r6lab
└── sparkjava
└── jwt
├── AuthFilter.java
├── BlacklistedTokenRepository.java
├── SparkJwtExample.java
├── TokenService.java
├── controller
├── AbstractTokenController.java
├── AuthController.java
└── UserController.java
└── user
├── Role.java
├── User.java
├── UserPrincipal.java
└── UserService.java
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | *.idea/
3 | *target/
4 |
5 | # Compiled class file
6 | *.class
7 |
8 | # Log file
9 | *.log
10 |
11 | # BlueJ files
12 | *.ctxt
13 |
14 | # Mobile Tools for Java (J2ME)
15 | .mtj.tmp/
16 |
17 | # Package Files #
18 | *.jar
19 | *.war
20 | *.nar
21 | *.ear
22 | *.zip
23 | *.tar.gz
24 | *.rar
25 |
26 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
27 |
28 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 rjozefowicz
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # sparkjava-jwt
2 | Example SparkJava - JWT integration
3 |
4 | # tech
5 | 
6 | 
7 | 
8 |
9 | ## Public available endpoints
10 |
11 | | ENDPOINT | HTTP METHOD | PARAMS | DESCRIPTION |
12 | | ------ | ------ | ------ | ------ |
13 | | /auth/register | POST | JSON body mandatory fields: userName, password. Additional fields firstName, secondName | New user registration |
14 | | /auth/login | POST | JSON body mandatory fields: userName, password | User login |
15 |
16 | ## Additional JWT endpoints
17 |
18 | **HTTP Header:** *Authorization: Bearer JWTToken*
19 |
20 | | ENDPOINT | HTTP METHOD | PARAMS | DESCRIPTION |
21 | | ------ | ------ | ------ | ------ |
22 | | /auth/token | POST | | JWT token refresh |
23 | | /auth/logout | POST | | JWT token revocation |
24 | | /auth/me | GET | | User details |
25 |
26 | ## Roles
27 |
28 | #### Predefined user roles:
29 | * ADMIN
30 | * MANAGER
31 | * DEVELOPER
32 |
33 | #### Endpoints for Role management:
34 |
35 | ENDPOINT | HTTP METHOD | PARAMS | DESCRIPTION |
36 | | ------ | ------ | ------ | ------ |
37 | | /auth/roles | POST | JSON body mandatory fields: userName, role | Add new Role to user |
38 | | /auth/roles | DELETE | JSON body mandatory fields: userName, role | Revoke Role from User |
39 |
40 | ## Admin user
41 |
42 | Predefined Admin user (admin/admin)
43 |
44 | ## Additional
45 |
46 | Cron job (every minute) to clean up revoked JWT Tokens
47 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 |
7 | com.r6lab
8 | sparkjava-jwt
9 | 1.0-SNAPSHOT
10 |
11 |
12 |
13 | org.apache.maven.plugins
14 | maven-compiler-plugin
15 |
16 | 8
17 | 8
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | com.sparkjava
26 | spark-core
27 | 2.7.2
28 |
29 |
30 | io.jsonwebtoken
31 | jjwt
32 | 0.7.0
33 |
34 |
35 | com.google.code.gson
36 | gson
37 | 2.8.5
38 |
39 |
40 | org.mindrot
41 | jbcrypt
42 | 0.4
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/main/java/com/r6lab/sparkjava/jwt/AuthFilter.java:
--------------------------------------------------------------------------------
1 | package com.r6lab.sparkjava.jwt;
2 |
3 | import spark.Filter;
4 | import spark.Request;
5 | import spark.Response;
6 |
7 | import java.util.logging.Logger;
8 |
9 | import static spark.Spark.halt;
10 |
11 | public class AuthFilter implements Filter {
12 |
13 | private static final Logger LOG = Logger.getLogger(AuthFilter.class.getName());
14 |
15 | private static final String TOKEN_PREFIX = "Bearer";
16 | private static final String LOGIN_ENDPOINT = "/login";
17 | private static final String REGISTRATION_ENDPOINT = "/registration";
18 | private static final String HTTP_POST = "POST";
19 |
20 | private final String authEndpointPrefix;
21 |
22 | private TokenService tokenService;
23 |
24 | public AuthFilter(String authEndpointPrefix, TokenService tokenService) {
25 | this.authEndpointPrefix = authEndpointPrefix;
26 | this.tokenService = tokenService;
27 | }
28 |
29 | public void handle(Request request, Response response) {
30 | if (!isLoginRequest(request) && !isRegistrationRequest(request)) {
31 | String authorizationHeader = request.headers("Authorization");
32 | if (authorizationHeader == null) {
33 | LOG.warning("Missing Authorization header");
34 | halt(401);
35 | } else if (!tokenService.validateToken(authorizationHeader.replace(TOKEN_PREFIX, ""))) {
36 | LOG.warning("Expired token " + authorizationHeader);
37 | halt(401);
38 | }
39 | }
40 | }
41 |
42 | private boolean isLoginRequest(Request request) {
43 | return request.uri().equals(authEndpointPrefix + LOGIN_ENDPOINT) && request.requestMethod().equals(HTTP_POST);
44 | }
45 |
46 | private boolean isRegistrationRequest(Request request) {
47 | return request.uri().equals(authEndpointPrefix + REGISTRATION_ENDPOINT) && request.requestMethod().equals(HTTP_POST);
48 | }
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/com/r6lab/sparkjava/jwt/BlacklistedTokenRepository.java:
--------------------------------------------------------------------------------
1 | package com.r6lab.sparkjava.jwt;
2 |
3 | import java.util.List;
4 | import java.util.concurrent.CopyOnWriteArrayList;
5 |
6 | public final class BlacklistedTokenRepository {
7 |
8 | private final List tokens = new CopyOnWriteArrayList<>();
9 |
10 | public void removeExpired() {
11 | final long currentTimestamp = System.currentTimeMillis();
12 | tokens.stream().filter(token -> token.getExpirationDate() < currentTimestamp).forEach(token -> {
13 | System.out.println("Removing token " + token.getToken());
14 | tokens.remove(token);
15 | });
16 | }
17 |
18 | public void addToken(String token, long expirationDate) {
19 | tokens.add(new BlacklistedTokenHolder(token, expirationDate));
20 | }
21 |
22 | public boolean isTokenBlacklisted(String token) {
23 | return tokens.stream().filter(b -> b.getToken().equals(token)).findAny().isPresent();
24 | }
25 |
26 | private final class BlacklistedTokenHolder {
27 |
28 | private final String token;
29 | private final long expirationDate;
30 |
31 | public BlacklistedTokenHolder(String token, long expirationDate) {
32 | this.token = token;
33 | this.expirationDate = expirationDate;
34 | }
35 |
36 | public String getToken() {
37 | return token;
38 | }
39 |
40 | public long getExpirationDate() {
41 | return expirationDate;
42 | }
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/r6lab/sparkjava/jwt/SparkJwtExample.java:
--------------------------------------------------------------------------------
1 | package com.r6lab.sparkjava.jwt;
2 |
3 | import com.google.gson.GsonBuilder;
4 | import com.r6lab.sparkjava.jwt.controller.AuthController;
5 | import com.r6lab.sparkjava.jwt.controller.UserController;
6 | import com.r6lab.sparkjava.jwt.user.UserService;
7 | import spark.Spark;
8 |
9 | import java.util.concurrent.Executors;
10 | import java.util.concurrent.ScheduledExecutorService;
11 | import java.util.concurrent.TimeUnit;
12 |
13 | public final class SparkJwtExample {
14 |
15 | private static final String SECRET_JWT = "secret_jwt";
16 |
17 | private static final ScheduledExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadScheduledExecutor();
18 |
19 | private final TokenService tokenService = new TokenService(SECRET_JWT);
20 |
21 | public void init() {
22 |
23 | new AuthController(new GsonBuilder().create(), new UserService(), tokenService).init();
24 | new UserController(tokenService).init();
25 |
26 | // PERIODIC TOKENS CLEAN UP
27 | EXECUTOR_SERVICE.scheduleAtFixedRate(() -> {
28 | System.out.println("Removing expired tokens");
29 | tokenService.removeExpired();
30 | }, 60, 60, TimeUnit.SECONDS); // every minute
31 |
32 | Spark.exception(Exception.class, (e, request, response) -> {
33 | System.err.println("Exception while processing request");
34 | e.printStackTrace();
35 | });
36 |
37 | }
38 |
39 | // BOOTSTRAP
40 | public static void main(String[] args) {
41 | SparkJwtExample sparkJwtExample = new SparkJwtExample();
42 | sparkJwtExample.init();
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/com/r6lab/sparkjava/jwt/TokenService.java:
--------------------------------------------------------------------------------
1 | package com.r6lab.sparkjava.jwt;
2 |
3 | import com.r6lab.sparkjava.jwt.user.Role;
4 | import com.r6lab.sparkjava.jwt.user.User;
5 | import com.r6lab.sparkjava.jwt.user.UserPrincipal;
6 | import io.jsonwebtoken.Claims;
7 | import io.jsonwebtoken.Jwts;
8 | import io.jsonwebtoken.SignatureAlgorithm;
9 | import io.jsonwebtoken.impl.DefaultClaims;
10 |
11 | import java.util.Date;
12 | import java.util.List;
13 | import java.util.stream.Collectors;
14 |
15 | public final class TokenService {
16 |
17 | private static final long EXPIRATION_TIME = 10 * 60 * 1000l; // 10 minutes
18 | private static final String ROLES = "roles";
19 |
20 | private final String jwtSecretKey;
21 |
22 | private final BlacklistedTokenRepository blacklistedTokenRepository = new BlacklistedTokenRepository();
23 |
24 | public TokenService(String jwtSecretKey) {
25 | this.jwtSecretKey = jwtSecretKey;
26 | }
27 |
28 | public final void removeExpired() {
29 | blacklistedTokenRepository.removeExpired();
30 | }
31 |
32 | public final String newToken(User user) {
33 | DefaultClaims claims = new DefaultClaims();
34 | claims.put(ROLES, user.getRoles());
35 | claims.setSubject(user.getUsername());
36 | return Jwts.builder()
37 | .setClaims(claims)
38 | .setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
39 | .signWith(SignatureAlgorithm.HS512, jwtSecretKey)
40 | .compact();
41 | }
42 |
43 | public final void revokeToken(String token) {
44 | Date expirationDate = Jwts.parser()
45 | .setSigningKey(jwtSecretKey)
46 | .parseClaimsJws(token)
47 | .getBody()
48 | .getExpiration();
49 | blacklistedTokenRepository.addToken(token, expirationDate.getTime());
50 | }
51 |
52 | /**
53 | * throws ExpiredJwtException if token has expired
54 | *
55 | * @param token
56 | * @return
57 | */
58 | public final UserPrincipal getUserPrincipal(String token) {
59 | Claims claims = Jwts.parser()
60 | .setSigningKey(jwtSecretKey)
61 | .parseClaimsJws(token)
62 | .getBody();
63 | List roles = (List) claims.get(ROLES);
64 | return UserPrincipal.of(claims.getSubject(), roles.stream().map(role -> Role.valueOf(role)).collect(Collectors.toList()));
65 | }
66 |
67 | public final boolean isTokenBlacklisted(String token) {
68 | return blacklistedTokenRepository.isTokenBlacklisted(token);
69 | }
70 |
71 | public final boolean validateToken(String token) {
72 | if (!isTokenBlacklisted(token)) {
73 | try {
74 | getUserPrincipal(token);
75 | return true;
76 | } catch (Exception e) {
77 | return false;
78 | }
79 | } else {
80 | return false;
81 | }
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/src/main/java/com/r6lab/sparkjava/jwt/controller/AbstractTokenController.java:
--------------------------------------------------------------------------------
1 | package com.r6lab.sparkjava.jwt.controller;
2 |
3 | import com.r6lab.sparkjava.jwt.TokenService;
4 | import com.r6lab.sparkjava.jwt.user.Role;
5 | import com.r6lab.sparkjava.jwt.user.UserPrincipal;
6 | import spark.Request;
7 |
8 | import java.util.Arrays;
9 | import java.util.List;
10 |
11 | public abstract class AbstractTokenController {
12 |
13 | private static final String TOKEN_PREFIX = "Bearer";
14 |
15 | private final TokenService tokenService;
16 |
17 | public AbstractTokenController(TokenService tokenService) {
18 | this.tokenService = tokenService;
19 | }
20 |
21 | protected UserPrincipal getUserPrincipal(Request request) {
22 | String authorizationHeader = request.headers("Authorization");
23 | String token = authorizationHeader.replace(TOKEN_PREFIX, "");
24 | return tokenService.getUserPrincipal(token);
25 | }
26 |
27 | protected boolean hasRole(Request request, Role[] roles) {
28 | if (roles.length == 0) {
29 | return true;
30 | }
31 | List userRoles = getUserPrincipal(request).getRoles();
32 | return userRoles.stream().filter(Arrays.asList(roles)::contains).findAny().isPresent();
33 | }
34 |
35 | protected String getUserNameFromToken(Request request) {
36 | String authorizationHeader = request.headers("Authorization");
37 | String token = authorizationHeader.replace(TOKEN_PREFIX, "");
38 | return tokenService.getUserPrincipal(token).getUserName();
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/main/java/com/r6lab/sparkjava/jwt/controller/AuthController.java:
--------------------------------------------------------------------------------
1 | package com.r6lab.sparkjava.jwt.controller;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.JsonObject;
5 | import com.r6lab.sparkjava.jwt.AuthFilter;
6 | import com.r6lab.sparkjava.jwt.TokenService;
7 | import com.r6lab.sparkjava.jwt.user.Role;
8 | import com.r6lab.sparkjava.jwt.user.User;
9 | import com.r6lab.sparkjava.jwt.user.UserService;
10 | import org.mindrot.jbcrypt.BCrypt;
11 | import spark.Request;
12 | import spark.Response;
13 | import spark.Spark;
14 |
15 | import java.io.IOException;
16 | import java.util.stream.Collectors;
17 |
18 | import static spark.Spark.before;
19 | import static spark.Spark.get;
20 | import static spark.Spark.halt;
21 | import static spark.Spark.post;
22 |
23 | public class AuthController extends AbstractTokenController {
24 |
25 | private static final String ROLE_PROPERTY = "role";
26 | private static final String TOKEN_PREFIX = "Bearer";
27 | private static final String AUTHORIZATION_HEADER = "Authorization";
28 | private static final String USER_NAME_PROPERTY = "userName";
29 | private static final String FIRST_NAME_PROPERTY = "firstName";
30 | private static final String LAST_NAME_PROPERTY = "lastName";
31 | private static final String PASSWORD_PROPERTY = "password";
32 | private static final String AUTH_ENDPOINT_PREFIX = "/auth";
33 |
34 | private static final String BCRYPT_SALT = BCrypt.gensalt();
35 |
36 | private final Gson gson;
37 | private final UserService userService;
38 | private final TokenService tokenService;
39 |
40 | public AuthController(Gson gson, UserService userService, TokenService tokenService) {
41 | super(tokenService);
42 | this.gson = gson;
43 | this.userService = userService;
44 | this.tokenService = tokenService;
45 | }
46 |
47 | public void init() {
48 | createAdminUser();
49 |
50 | // AUTH FILTER
51 | before(new AuthFilter(AUTH_ENDPOINT_PREFIX, tokenService));
52 |
53 | // REGISTRATION ENDPOINT
54 | post(AUTH_ENDPOINT_PREFIX + "/registration", (request, response) -> register(request, response));
55 |
56 | // LOGIN ENDPOINT
57 | post(AUTH_ENDPOINT_PREFIX + "/login", (request, response) -> login(request, response));
58 |
59 | // LOGOUT ENDPOINT
60 | post(AUTH_ENDPOINT_PREFIX + "/logout", (request, response) -> logout(request));
61 |
62 | // REFRESH ENDPOINT
63 | post(AUTH_ENDPOINT_PREFIX + "/token", (request, response) -> refresh(request, response));
64 |
65 | // ME ENDPOINT
66 | get(AUTH_ENDPOINT_PREFIX + "/me", (request, response) -> me(request, response));
67 |
68 | // ASSIGN ROLE_PROPERTY
69 | post(AUTH_ENDPOINT_PREFIX + "/roles", (request, response) -> assignRole(request));
70 |
71 | // REVOKE ROLE_PROPERTY
72 | Spark.delete(AUTH_ENDPOINT_PREFIX + "/roles", (request, response) -> revokeRole(request));
73 |
74 | }
75 |
76 | private String revokeRole(Request request) throws IOException {
77 | if (hasRole(request, new Role[]{Role.ADMIN})) {
78 | String json = request.raw().getReader().lines().collect(Collectors.joining());
79 | JsonObject jsonRequest = this.gson.fromJson(json, JsonObject.class);
80 | if (jsonRequest.has(USER_NAME_PROPERTY) && jsonRequest.has(ROLE_PROPERTY)) {
81 | Role role = Role.valueOf(jsonRequest.get(ROLE_PROPERTY).getAsString());
82 | if (role != null) {
83 | User user = this.userService.get(jsonRequest.get(USER_NAME_PROPERTY).getAsString());
84 | if (user != null) {
85 | user.revokeRole(role);
86 | this.userService.update(user);
87 | }
88 | }
89 | }
90 | } else {
91 | halt(401);
92 | }
93 |
94 | return "";
95 | }
96 |
97 | private String assignRole(Request request) throws IOException {
98 | if (hasRole(request, new Role[]{Role.ADMIN})) {
99 | String json = request.raw().getReader().lines().collect(Collectors.joining());
100 | JsonObject jsonRequest = gson.fromJson(json, JsonObject.class);
101 | if (jsonRequest.has(USER_NAME_PROPERTY) && jsonRequest.has(ROLE_PROPERTY)) {
102 | Role role = Role.valueOf(jsonRequest.get(ROLE_PROPERTY).getAsString());
103 | if (role != null) {
104 | User user = userService.get(jsonRequest.get(USER_NAME_PROPERTY).getAsString());
105 | if (user != null) {
106 | user.assignRole(role);
107 | userService.update(user);
108 | }
109 | }
110 | }
111 | } else {
112 | halt(401);
113 | }
114 |
115 | return "";
116 | }
117 |
118 | private String me(Request request, Response response) {
119 | response.type("application/json");
120 | String userName = getUserNameFromToken(request);
121 | User user = userService.get(userName);
122 | JsonObject userJson = new JsonObject();
123 | userJson.addProperty(USER_NAME_PROPERTY, user.getUsername());
124 | userJson.addProperty(FIRST_NAME_PROPERTY, user.getFirstName());
125 | userJson.addProperty(LAST_NAME_PROPERTY, user.getLastName());
126 | return userJson.toString();
127 | }
128 |
129 | private String refresh(Request request, Response response) {
130 | String authorizationHeader = request.headers(AUTHORIZATION_HEADER);
131 | String token = authorizationHeader.replace(TOKEN_PREFIX, "");
132 | String userName = getUserNameFromToken(request);
133 | tokenService.revokeToken(token);
134 | String refreshedToken = tokenService.newToken(userService.get(userName));
135 | response.header(AUTHORIZATION_HEADER, TOKEN_PREFIX + " " + refreshedToken);
136 | return "";
137 | }
138 |
139 | private String logout(Request request) {
140 | String authorizationHeader = request.headers(AUTHORIZATION_HEADER);
141 | tokenService.revokeToken(authorizationHeader.replace(TOKEN_PREFIX, ""));
142 | return "";
143 | }
144 |
145 | private String login(Request request, Response response) throws IOException {
146 | String json = request.raw().getReader().lines().collect(Collectors.joining());
147 | JsonObject jsonRequest = gson.fromJson(json, JsonObject.class);
148 | if (validatePost(jsonRequest)) {
149 | try {
150 | String encryptedPassword = BCrypt.hashpw(jsonRequest.get(PASSWORD_PROPERTY).getAsString(), BCRYPT_SALT);
151 | User user = userService.get(jsonRequest.get(USER_NAME_PROPERTY).getAsString());
152 | if (user.getPassword().equals(encryptedPassword)) {
153 | response.header(AUTHORIZATION_HEADER, TOKEN_PREFIX + " " + tokenService.newToken(user));
154 | }
155 | } catch (Exception e) {
156 | response.status(401);
157 | }
158 | }
159 | return "";
160 | }
161 |
162 | private String register(Request request, Response response) throws IOException {
163 | String json = request.raw().getReader().lines().collect(Collectors.joining());
164 | JsonObject jsonRequest = gson.fromJson(json, JsonObject.class);
165 | try {
166 | if (validatePost(jsonRequest)) {
167 | userService.register(jsonRequest.get(USER_NAME_PROPERTY).getAsString(),
168 | BCrypt.hashpw(jsonRequest.get(PASSWORD_PROPERTY).getAsString(), BCRYPT_SALT),
169 | jsonRequest.has(FIRST_NAME_PROPERTY) ? jsonRequest.get(FIRST_NAME_PROPERTY).getAsString() : null,
170 | jsonRequest.has(LAST_NAME_PROPERTY) ? jsonRequest.get(LAST_NAME_PROPERTY).getAsString() : null);
171 | return "";
172 | } else {
173 | response.status(400);
174 | }
175 | } catch (IllegalArgumentException e) {
176 | response.status(400);
177 | }
178 | return "";
179 | }
180 |
181 | private void createAdminUser() {
182 | userService.register("admin", BCrypt.hashpw("admin", BCRYPT_SALT), null, null); //ADMIN USER
183 | User admin = userService.get("admin");
184 | admin.assignRole(Role.ADMIN);
185 | userService.update(admin);
186 | }
187 |
188 | private boolean validatePost(JsonObject jsonRequest) {
189 | return jsonRequest != null && jsonRequest.has(USER_NAME_PROPERTY) && jsonRequest.has(PASSWORD_PROPERTY);
190 | }
191 |
192 | }
193 |
--------------------------------------------------------------------------------
/src/main/java/com/r6lab/sparkjava/jwt/controller/UserController.java:
--------------------------------------------------------------------------------
1 | package com.r6lab.sparkjava.jwt.controller;
2 |
3 | import com.r6lab.sparkjava.jwt.TokenService;
4 | import com.r6lab.sparkjava.jwt.user.Role;
5 |
6 | import static spark.Spark.get;
7 | import static spark.Spark.halt;
8 |
9 | public class UserController extends AbstractTokenController {
10 |
11 | public UserController(TokenService tokenService) {
12 | super(tokenService);
13 | }
14 |
15 | public void init() {
16 | // PROTECTED ENDPOINT FOR DEVELOPER ROLE_PROPERTY
17 | get("/protected/developer", (request, response) -> {
18 | if (hasRole(request, new Role[]{Role.DEVELOPER, Role.ADMIN})) {
19 | return "PROTECTED RESOURCE FOR DEVELOPER";
20 | } else {
21 | halt(401);
22 | return "";
23 | }
24 | });
25 |
26 | // PROTECTED ENDPOINT FOR MANAGER ROLE_PROPERTY
27 | get("/protected/manager", (request, response) -> {
28 | if (hasRole(request, new Role[]{Role.MANAGER, Role.ADMIN})) {
29 | return "PROTECTED RESOURCE FOR MANAGER";
30 | } else {
31 | halt(401);
32 | return "";
33 | }
34 | });
35 |
36 | // PROTECTED ENDPOINT FOR ADMIN ROLE_PROPERTY
37 | get("/protected/admin", (request, response) -> {
38 | if (hasRole(request, new Role[]{Role.ADMIN})) {
39 | return "PROTECTED RESOURCE FOR ADMIN";
40 | } else {
41 | halt(401);
42 | return "";
43 | }
44 | });
45 |
46 | // PROTECTED ENDPOINT FOR ALL ROLES
47 | get("/protected/all", (request, response) -> {
48 | if (hasRole(request, new Role[]{})) {
49 | return "PROTECTED RESOURCE FOR ALL ROLES";
50 | } else {
51 | halt(401);
52 | return "";
53 | }
54 | });
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/r6lab/sparkjava/jwt/user/Role.java:
--------------------------------------------------------------------------------
1 | package com.r6lab.sparkjava.jwt.user;
2 |
3 | public enum Role {
4 | ADMIN, MANAGER, DEVELOPER
5 | }
6 |
--------------------------------------------------------------------------------
/src/main/java/com/r6lab/sparkjava/jwt/user/User.java:
--------------------------------------------------------------------------------
1 | package com.r6lab.sparkjava.jwt.user;
2 |
3 | import java.util.List;
4 |
5 | public final class User {
6 |
7 | private final String username;
8 | private final String password;
9 | private final String firstName;
10 | private final String lastName;
11 | private final List roles;
12 |
13 | private User(String username, String password, String firstName, String lastName, List roles) {
14 | this.username = username;
15 | this.password = password;
16 | this.firstName = firstName;
17 | this.lastName = lastName;
18 | this.roles = roles;
19 | }
20 |
21 | public String getUsername() {
22 | return username;
23 | }
24 |
25 | public String getPassword() {
26 | return password;
27 | }
28 |
29 | public String getFirstName() {
30 | return firstName;
31 | }
32 |
33 | public String getLastName() {
34 | return lastName;
35 | }
36 |
37 | public List getRoles() {
38 | return roles;
39 | }
40 |
41 | public void assignRole(Role role) {
42 | if (!roles.contains(role)) {
43 | roles.add(role);
44 | }
45 | }
46 |
47 | public void revokeRole(Role role) {
48 | if (!roles.contains(role)) {
49 | roles.remove(role);
50 | }
51 | }
52 |
53 | public static final User of(String username, String password, String firstName, String lastName, List roles) {
54 | return new User(username, password, firstName, lastName, roles);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/com/r6lab/sparkjava/jwt/user/UserPrincipal.java:
--------------------------------------------------------------------------------
1 | package com.r6lab.sparkjava.jwt.user;
2 |
3 | import java.util.List;
4 |
5 | public final class UserPrincipal {
6 | private final String userName;
7 | private final List roles;
8 |
9 | private UserPrincipal(String userName, List roles) {
10 | this.userName = userName;
11 | this.roles = roles;
12 | }
13 |
14 | public String getUserName() {
15 | return userName;
16 | }
17 |
18 | public List getRoles() {
19 | return roles;
20 | }
21 |
22 | public static UserPrincipal of(String userName, List roles) {
23 | return new UserPrincipal(userName, roles);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/com/r6lab/sparkjava/jwt/user/UserService.java:
--------------------------------------------------------------------------------
1 | package com.r6lab.sparkjava.jwt.user;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.concurrent.CopyOnWriteArrayList;
6 |
7 | public final class UserService {
8 |
9 | private final List users = new CopyOnWriteArrayList<>();
10 |
11 | public final void register(String userName, String password, String firstName, String lastName) {
12 | if (users.stream().filter(user -> user.getUsername().equals(userName)).findAny().isPresent()) {
13 | throw new IllegalArgumentException("User already exists");
14 | }
15 | users.add(User.of(userName, password, firstName, lastName, new ArrayList<>()));
16 | }
17 |
18 | public final User get(String userName) {
19 | return users
20 | .stream()
21 | .filter(user -> user.getUsername().equals(userName))
22 | .findAny()
23 | .orElseThrow(() -> new IllegalStateException("User does not exist"));
24 | }
25 |
26 | public final void update(User user) {
27 | users.add(user);
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------