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 }