b2b2c system jwt permission source code sharing part1

demand analysis


Before sharing the source code, first organize and clarify the requirements of the permission module in the b2b2c system to facilitate the understanding of the source code.

Business needs

  • There are three main roles in the b2b2c e-commerce system: buyers, sellers, and platform administrators.

  • Among them, there is a clerk in the seller role, and you can set different permissions for the clerk to manage (for example, the permissions of products and orders are assigned to different clerks). Similarly, the platform administrator also needs to manage the above-mentioned fine permissions, and the buyer permissions are relatively simple.

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

Technical requirements

  • decentralization

The javashop e-commerce system adopts a decentralized and containerized deployment scheme. Considering performance and scalability, the authentication needs to use the token method, and the centralized session scheme cannot be used.

  • Common Capability Abstraction

There are three terminals (buyer, seller, management terminal) in the b2b2c e-commerce system. For performance and stability reasons, these three terminals are separated in deployment, which is reflected in buyer API, seller API, management terminal API, and permissions. In essence, it intercepts the api requests from these three terminals and performs authentication. The authentication of these three roles has both general logic and personalized logic:

  • General: token generation and parsing
  • Personalization: different permissions 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 side.

This requires the reuse of the reuse and the separation of the separation in architecture and code implementation.

Architecture ideas


Token parsing architecture idea:

  • The two interfaces correspond to token parsing and token generation 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 are implemented for specific business

JWT-based authority authentication source code

TokenManager


The business class interface of Token has two core methods: creating and parsing the token. Considering scalability, the interface level does not reflect the dependency of jwt:

/**
 * token业务管理接口
 * @author kingapex
 * @version 1.0
 * @since 7.1.0
 * 2019/12/25
 */
public interface TokenManager {

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

    /**
     * 解析token
     * @param token
     * @return 用户对象
     */
    <T>  T parse(Class<T> clz, String token) throws TokenParseException;
}

TokenManagerImpl


The implementation of the token business class based on jwt:

/**
 * token管理基于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创建接口
 * @author kingapex
 * @version 1.0
 * @since 7.1.0
 * 2019-06-21
 */
public interface TokenCreater {


    /**
     * 创建token
     * @param user 用户
     * @return token
     */
    Token create(AuthUser user);

}

Token parser


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

    /**
     * 解析token
     * @param token
     * @return 用户对象
     */
    <T>  T parse(Class<T> clz, String token) throws TokenParseException;

}

JwtTokenCreater


Create implementation based on jwt token:

/**
 * Jwt token 创建实现
 *
 * @author kingapex
 * @version 1.0
 * @since 7.1.0
 * 2019-06-21
 */

public class JwtTokenCreater implements TokenCreater {

/**
 * jwt秘钥,需要在构造器中初始化
 */
private String secret;

/**
 * 访问token的有效期,在构造器中初始化,可以通过setter改变
 */
private int accessTokenExp;

/**
 * 刷新token的有效期,在构造器中初始化,可以通过setter改变
 */
private int refreshTokenExp;

/**
 * 在构造器中初始化参数、默认值
 * @param secret
 */
public JwtTokenCreater(String secret) {

    this.secret = secret;

    accessTokenExp=60*60;

    //默认session失效时间为1小时:60秒 x 60 (=1分钟) * 60 (=1小时)
    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


jwt-based token parser

 /**

 * jwt token解析器
 * @author kingapex
 * @version 1.0
 * @since 7.1.0
 * 2019-06-24
 */

public class JwtTokenParser implements TokenParser {

/**
 * jwt秘钥,需要在构造器中初始化
 */
     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

/**
 * 认证用户接口
 * @author kingapex
 * @version 1.0
 * @since 7.1.0
 * 2019-06-21
 */
public interface AuthUser {

    List<String> getRoles();

    void setRoles(List<String> roles);
}

Three roles are implemented based on the above interface: Buyer, Seller, Admin

User:

base class

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

    /**
     * 会员id
     */
    private Integer uid;

    /**
     * 唯一标识
     */
    private String uuid;

    /**
     * 用户名
     */
    private String username;
    /**
     * 角色
     */
    private List<String> roles;

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

    /**
     * 为用户定义角色
     *
     * @param roles 角色集合
     */
    public void add(String... roles) {
        for (String role : roles) {
            this.roles.add(role);
        }
    }

//getter setter 忽略。。。
}

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

    /**
     * 定义买家的角色
     */
    public Buyer() {
        this.add(Role.BUYER.name());
    }


}

public class Seller extends  Buyer {

    /**
     * 卖家id
     */
    private  Integer sellerId;

    /**
     * 卖家店铺名称
     */
    private String sellerName;
    
    /**
     * 是否是自营  0 不是  1是
     */
    private Integer selfOperated;


    public Seller() {
         //seller有 买家的角色和卖宾角色
         add( Role.SELLER.name());
    }
}

/**
 * 管理员角色
 *
 * @author zh
 * @version v7.0
 * @date 18/6/27 上午10:09
 * @since v7.0
 */

public class Admin extends User {

    /**
     * 是否是超级管理员
     */
    private Integer founder;


    /**
     * 角色
     */
    private List<String> roles;

    //getter setter 忽略。。。
    
}

The above is the basic structure, ideas and related source code of the permission system in javashop. Because of the space, the specific permission verification process and code will be shared in the next article.

Original article by javashop

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324109855&siteId=291194637