b2b2c system jwt permission source sharing part1

Posted by jrose83 on Mon, 30 Mar 2020 14:52:34 +0200

requirement analysis

Before sharing the source code, the requirements of the permission module in the b2b2c system should be sorted out and clarified to facilitate the understanding of the source code.

Business needs

  • There are three roles of authority in b2b2c e-commerce system: buyer, seller and platform administrator.

  • In the seller's role, there are also clerks, who can set different permissions for clerks to manage (for example, the permissions for goods and orders are assigned to different clerks). In the same way, the platform administrator also needs to manage the above-mentioned fine permissions, and the buyer's permissions are relatively single.

  • If a clerk or administrator is disabled, the user needs to be logged out immediately to ensure data security

Technology demand

  • De centralization

Java shop e-commerce system The decentralized and containerized deployment scheme is adopted. Considering the performance and scalability, the token mode is required for authentication, instead of the centralized session scheme

  • Common capability abstraction

In b2b2c e-commerce system, there are three ends (buyer, seller, and management end). For performance and stability reasons, these three ends are separated in deployment, which are reflected in buyer API, seller API, and management end API. In essence, authority is to intercept API requests of these three ends and perform authentication. The authentication of these three roles has both general logic and personalized logic:

  • Universal: token generation and resolution

  • Personalization: different permission data sources (SecurityMetadataSource)

The specific embodiment is that the source of the binding relationship between roles and permissions is different: the seller's permission setting comes from the seller, and the platform's permission setting comes from the management.

This requires reuse in architecture and code implementation, and separation in separation.

Architectural thinking

Token resolution Architecture Idea:

  • The two interfaces correspond to the analysis of token and the generation of token respectively

  • A jwt implementation class is implemented by default

Security authentication domain model architecture

  • AuthUser is the top-level authenticated user interface

  • User based implementation

  • Buyer, Seller,Admin for specific business implementation

Source code of authority authentication based on JWT

TokenManager

There are two core methods for the business class interface of Token: creating and parsing token, and considering the extensibility, the interface layer does not reflect the dependency of jwt:

/**
 * token Business management interface
 * @author kingapex
 * @version 1.0
 * @since 7.1.0
 * 2019/12/25
 */
public interface TokenManager {

    /**
     * Create token
     * @param user
     * @return
     */
    Token create(AuthUser user);

    /**
     * Parsing token
     * @param token
     * @return User object
     */
    <T>  T parse(Class<T> clz, String token) throws TokenParseException;
}

 

TokenManagerImpl

The token business class is based on the implementation of jwt:

/**
 * token Implementation of management based on twt
 * @author kingapex
 * @version 1.0
 * @since 7.1.0
 * 2019/12/25
 */

@Service
public class TokenManagerImpl implements TokenManager {

    @Autowired
    private JavashopConfig javashopConfig;

    @Override
    public Token create(AuthUser user) {
        JwtTokenCreater tokenCreater = new JwtTokenCreater(javashopConfig.getTokenSecret());
        tokenCreater.setAccessTokenExp(javashopConfig.getAccessTokenTimeout());
        tokenCreater.setRefreshTokenExp(javashopConfig.getRefreshTokenTimeout());
        return tokenCreater.create(user);

    }

    @Override
    public <T> T parse(Class<T> clz, String token) throws TokenParseException {
        JwtTokenParser tokenParser = new JwtTokenParser(javashopConfig.getTokenSecret());
        return tokenParser.parse(clz, token);
    }
} 

Token creation interface

/**
 * Token Create interface
 * @author kingapex
 * @version 1.0
 * @since 7.1.0
 * 2019-06-21
 */
public interface TokenCreater {


    /**
     * Create token
     * @param user user
     * @return token
     */
    Token create(AuthUser user);

}

 

 

Token parser

/**
 * Token Parser
 * @author kingapex
 * @version 1.0
 * @since 7.1.0
 * 2019-06-21
 */
public interface TokenParser {

    /**
     * Parsing token
     * @param token
     * @return User object
     */
    <T>  T parse(Class<T> clz, String token) throws TokenParseException;

}

 

JwtTokenCreater

Based on the creation and implementation of jwt token:

/**
 * Jwt token Create implementation
 *
 * @author kingapex
 * @version 1.0
 * @since 7.1.0
 * 2019-06-21
 */

public class JwtTokenCreater implements TokenCreater {

/**
 * jwt Secret key, which needs to be initialized in the constructor
 */
private String secret;

/**
 * Access the validity period of the token, which is initialized in the constructor, and can be changed through the setter
 */
private int accessTokenExp;

/**
 * Refresh the validity period of the token, which is initialized in the constructor, and can be changed through the setter
 */
private int refreshTokenExp;

/**
 * Initializing parameters and default values in the constructor
 * @param secret
 */
public JwtTokenCreater(String secret) {

    this.secret = secret;

    accessTokenExp=60*60;

    //default session Failure time is 1 hour: 60 seconds x 60 (=1 Minute) * 60 (=1 hour)
    refreshTokenExp = 60 * 60 * 60;
}

@Override
public Token create(AuthUser user) {

    ObjectMapper oMapper = new ObjectMapper();

    Map buyerMap = oMapper.convertValue(user, HashMap.class);

    String accessToken = Jwts.builder()
            .setClaims(buyerMap)
            .setSubject("user")
            .setExpiration( new Date(System.currentTimeMillis() + accessTokenExp * 1000))
            .signWith(SignatureAlgorithm.HS512, secret.getBytes())
            .compact();

    String refreshToken = Jwts.builder()
            .setClaims(buyerMap)
            .setSubject("user")
            .setExpiration( new Date(System.currentTimeMillis() +(accessTokenExp+ refreshTokenExp)  * 1000))
            .signWith(SignatureAlgorithm.HS512, secret.getBytes())
            .compact();

    Token token = new Token();
    token.setAccessToken(accessToken);
    token.setRefreshToken(refreshToken);


    return token;
}


public JwtTokenCreater setSecret(String secret) {
    this.secret = secret;
    return  this;
}

public JwtTokenCreater setAccessTokenExp(int accessTokenExp) {
    this.accessTokenExp = accessTokenExp;
    return  this;
}

public JwtTokenCreater setRefreshTokenExp(int refreshTokenExp) {
    this.refreshTokenExp = refreshTokenExp;
    return  this;
}

 

JwtTokenParser

token parser based on jwt

 /**

 * jwt token Parser
 * @author kingapex
 * @version 1.0
 * @since 7.1.0
 * 2019-06-24
 */

public class JwtTokenParser implements TokenParser {

/**
 * jwt Secret key, which needs to be initialized in the constructor
 */
     private String secret;

    private Claims claims;

    public JwtTokenParser(String secret) {
        this.secret = secret;
    }


    @Override
    public <T> T parse(Class<T> clz, String token) throws TokenParseException {

        try {
            claims
                    = Jwts.parser()
                    .setSigningKey(secret.getBytes())
                    .parseClaimsJws(token).getBody();
            T t = BeanUtil.mapToBean(clz, claims);
            return t;
        } catch (Exception e) {
            throw new TokenParseException(e);
        }

    }

 

 

 

AuthUser

Authentication user interface

/**
 * Authentication user interface
 * @author kingapex
 * @version 1.0
 * @since 7.1.0
 * 2019-06-21
 */
public interface AuthUser {

    List<String> getRoles();

    void setRoles(List<String> roles);
}

 

Implement three roles based on the above interface: Buyer,Seller,Admin

User:

Base class

/**
 * user
 * Created by kingapex on 2018/3/8.
 *
 * @author kingapex
 * @version 1.0
 * @since 6.4.0
 * 2018/3/8
 */
public class User implements AuthUser {

    /**
     * Member id
     */
    private Integer uid;

    /**
     * Unique identification
     */
    private String uuid;

    /**
     * User name
     */
    private String username;
    /**
     * role
     */
    private List<String> roles;

    public User() {
        roles = new ArrayList<>();
    }

    /**
     * Define roles for users
     *
     * @param roles Role set
     */
    public void add(String... roles) {
        for (String role : roles) {
            this.roles.add(role);
        }
    }

//getter setter Ignore...
}

 

 

/**
 * Buyer
 * Created by kingapex on 2018/3/11.
 *
 * @author kingapex
 * @version 1.0
 * @since 7.0.0
 * 2018/3/11
 */
public class Buyer extends User {

    /**
     * Define buyer's role
     */
    public Buyer() {
        this.add(Role.BUYER.name());
    }


}

public class Seller extends  Buyer {

    /**
     * Seller id
     */
    private  Integer sellerId;

    /**
     * Seller's shop name
     */
    private String sellerName;
    
    /**
     * Is it self operated 0 or not 1 yes
     */
    private Integer selfOperated;


    public Seller() {
         //seller There are buyers and sellers
         add( Role.SELLER.name());
    }
}

/**
 * Administrator role
 *
 * @author zh
 * @version v7.0
 * @date 18/6/27 Forenoon 10:09 am
 * @since v7.0
 */

public class Admin extends User {

    /**
     * Super administrator or not
     */
    private Integer founder;


    /**
     * role
     */
    private List<String> roles;

    //getter setter Ignore...
    
}

 

 

The above is the basic architecture and ideas of permission system in Java shop as well as related source code. Because of the space, the specific permission verification process and code will be shared in the next article.

 

Topics: Java Session