b2b2c系统jwt权限源码分享part1

2020-03-30 16:04:13来源:博客园 阅读 ()

新老客户大回馈,云服务器低至5折

b2b2c系统jwt权限源码分享part1

需求分析

在分享源码之前,先将b2b2c系统中权限模块的需求整理、明确,方便源码的理解。

业务需求

  • b2b2c电子商务系统中权限主要有三个角色:买家、卖家、平台管理员。

  • 其中卖家角色中又有店员,可以设置店员管理不同的权限(如商品和订单的权限分派给不同的店员),同理平台管理员也需要进行上述精细权限的管理,买家权限相对比较单一。

  • 如果禁用了某个店员或管理员,则这个用户需要立刻被登出,保证数据安全性

技术需求

  • 去中心化

javashop电商系统采用去中心化、容器化的部署方案,考虑性能及扩展性,鉴权需要采用token的方式,不能采用有中心的session方案

  • 公用能力抽象

b2b2c电商体系中存在三端(买家、卖家、管理端),出于性能、稳定性考虑,这三端在部署上是分离的,体现为买家API、卖家API、管理端API,权限本质上就是拦截这三端的api请求,进行鉴权,这三种角色的鉴权既有通用的逻辑又有个性化的逻辑:

  • 通用:token的生成和解析

  • 个性化:权限数据源不同(SecurityMetadataSource)

具体体现就是角色和权限绑定关系的来源不同:卖家端来自卖家的权限设置,平台的来自管理端的权限设置。

这就要求在架构和代码实现上做的该重用的重用,该分离的分离。

架构思路

Token解析架构思路:

  • 两个接口分别对应token的解析和token的生成

  • 默认实现了一个jwt的实现类

安全认证领域模型架构

  • AuthUser是最上层的可被认证用户接口

  • User为基础实现

  • Buyer,Seller,Admin为具体业务实现

基于JWT的权限认证源码

TokenManager

Token的业务类接口,有两个核心的方法:创建和解析token,扩展性的考虑,接口层面并未体现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

token业务类基于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创建接口

/**
 * 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 解析器

/**
 * 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

基于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的token解析器

 /**

 * 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

认证用户接口

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

    List<String> getRoles();

    void setRoles(List<String> roles);
}

 

基于上述接口实现三种角色 :Buyer,Seller,Admin

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 {

    /**
     * 会员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 忽略。。。
    
}

 

 

以上是javashop中权限体系中基础的架构和思路以及相关源码,因为篇幅关系,具体的权限校验流程及代码将在下一篇文章中分享。

 


原文链接:https://www.cnblogs.com/javashop-docs/p/12600831.html
如有疑问请与原作者联系

标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇:Shiro 入门demo

下一篇:【Java】 NullPointerException、ArrayIndexOutOfBoundsExceptio