1 module hunt.framework.auth.JwtAuthRealm;
2
3 import hunt.framework.auth.AuthRealm;
4 import hunt.framework.auth.Claim;
5 import hunt.framework.auth.ClaimTypes;
6 import hunt.framework.auth.Identity;
7 import hunt.framework.auth.JwtToken;
8 import hunt.framework.auth.JwtUtil;
9 import hunt.framework.auth.principal;
10 import hunt.framework.auth.UserDetails;
11 import hunt.framework.auth.UserService;
12 import hunt.framework.config.AuthUserConfig;
13 import hunt.framework.Init;
14 import hunt.framework.provider.ServiceProvider;
15
16
17 import hunt.collection.ArrayList;
18 import hunt.collection.Collection;
19 import hunt.http.AuthenticationScheme;
20 import hunt.logging;
21 import hunt.shiro;
22 import hunt.String;
23
24 import std.algorithm;
25 import std.range;
26 import std.string;
27
28
29 /**
30 * See_also:
31 * [Springboot Integrate with Apache Shiro](http://www.andrew-programming.com/2019/01/23/springboot-integrate-with-jwt-and-apache-shiro/)
32 * https://stackoverflow.com/questions/13686246/shiro-security-multiple-realms-which-authorization-info-is-taken
33 */
34 class JwtAuthRealm : AuthRealm {
35
36 this(UserService userService) {
37 super(userService);
38 }
39
40 override bool supports(AuthenticationToken token) {
41 version(HUNT_AUTH_DEBUG) tracef("AuthenticationToken: %s", typeid(cast(Object)token));
42
43 JwtToken t = cast(JwtToken)token;
44 return t !is null;
45 }
46
47 // override protected UserService getUserService() {
48 // return serviceContainer().resolve!UserService();
49 // }
50
51 override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
52 string tokenString = token.getPrincipal();
53 string username = JwtUtil.getUsername(tokenString);
54 if (username.empty) {
55 version(HUNT_DEBUG) warning("The username in token is empty.");
56 throw new AuthenticationException("token invalid");
57 }
58
59 UserService userService = getUserService();
60 version(HUNT_AUTH_DEBUG) {
61 infof("username: %s, %s", username, typeid(cast(Object)userService));
62 }
63
64 // To retrieve the user info from username
65 UserDetails user = userService.getByName(username);
66 if(user is null) {
67 throw new AuthenticationException(format("The user [%s] does NOT exist!", username));
68 }
69
70 if(!user.isEnabled)
71 throw new AuthenticationException("The user is disabled!");
72
73 string salt = user.salt; // userService.getSalt(username, "user.password");
74 version(HUNT_AUTH_DEBUG) {
75 infof("tokenString: %s, username: %s, salt: %s", tokenString, username, salt);
76 }
77
78 // Valid the user using JWT
79 if(!JwtUtil.verify(tokenString, username, salt)) {
80 throw new IncorrectCredentialsException("Wrong username or password for " ~ username);
81 }
82
83 version(HUNT_AUTH_DEBUG) infof("Realm: %s", getName());
84 PrincipalCollection pCollection = new SimplePrincipalCollection(user, getName());
85 String credentials = new String(tokenString);
86
87 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(pCollection, credentials);
88 return info;
89 }
90
91 }