Skip to content

Authentication

Xueping edited this page May 29, 2020 · 10 revisions

To implement Role-based authorization with Shiro and JWT. See https://github.com/dicoth/dicoth.

Define a realm for authorization

class AdminCmsRealm : AuthorizingRealm {
    override
    bool supports(AuthenticationToken token) {
        JwtToken jt = cast(JwtToken)token;
        return jt !is null;
    }

    override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
        string tokenString = token.getPrincipal();
        string username = JwtUtil.getUsername(tokenString);

        // To retrieve the user info from username 

        // Valid the user using JWT 
        if(JwtUtil.verify(tokenString, username, userModel.password)) {
                SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(userModel, credentials, getName());
                return info;
        } else {
            throw new WrongPasswordException(username);
        }
    }

    override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {        
        User user = cast(User) principals.getPrimaryPrincipal();
        if(user is null) {
            warning("no principals");
            return null;
        }

        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        // To retrieve all the roles for the user from database
        Role[] userRoles = roleRep.getUserRoles(user.id);
        ....
        // Recording the permissions based on each role
        foreach(Role r; userRoles) {
            // roles
            info.addRole(r.name);

            // permissions
            info.addStringPermission("*");              // for administrator
            info.addStringPermission("permission");     // specific permission
        }
        return info;
    }
}

Add a new AuthServiceProvider

The AuthServiceProvider uses Hunt-Cache to cache all the authorization informations.

class DicothAuthServiceProvider : AuthServiceProvider {
    override void register() {
        serviceContainer().register!(AuthorizingRealm, AdminCmsRealm).newInstance;
    }
}

Register the AuthServiceProvider

The user-defined AuthServiceProvider should be register at the main entrance of the application.

app.register!DicothAuthServiceProvider; 

Login

// Retrieve the user's info from database
User userModel = userRepository.findByEmail(username);

// Generate a JWT token based on the username and password
string checkSalt = generateUserPassword(password, userModel.salt);
string tokenString = JwtUtil.sign(username, checkSalt);

// Set the token to cookie
Cookie sessionCookie = new Cookie("__auth_token__", tokenString, 86400);

Authenticating in a Middleware

override Response onProcess(Request request, Response response) {    
    enum TokenHeader = "Bearer ";
    string tokenString = request.header(HttpHeader.AUTHORIZATION);
    tokenString = tokenString[TokenHeader.length .. $];
    string sessionId = request.cookie("ShiroSessionId");
    if(!sessionId.empty) {
        Subject subject = SecurityUtils.newSubject(sessionId, request.host()); 

        try {
            JwtToken token = new JwtToken(tokenString);
            subject.login(token);
        } catch (AuthenticationException e) {
            warning(e);
        } catch(Exception ex) {
            warning(ex);
        }     
           
        if(subject.isAuthenticated()) {
            // Set the authenticated user to the current request
            request.setAttribute(Subject.DEFAULT_NAME, cast(Object)subject);
            return null;  
        }

        if (subject.hasRole("admin")) {
            // do somthing
        }

        if (subject.isPermitted("delete")) {
            // do somthing
        }

    return new RedirectResponse(request, url("system.user.login", null, "admin"));
} 

Logout

@Action Response logout() {
    string sessionId = request.cookie("ShiroSessionId");
    Subject subject = SecurityUtils.newSubject(sessionId, request.host()); 
    subject.logout();

    Cookie sessionCookieToken = new Cookie("__auth_token__","",0);

    return new RedirectResponse(this.request(), "/")
            .withCookie(sessionCookieToken);
    
}
Clone this wiki locally