zoukankan      html  css  js  c++  java
  • 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中权限体系中基础的架构和思路以及相关源码,因为篇幅关系,具体的权限校验流程及代码将在下一篇文章中分享。

     

  • 相关阅读:
    Linux设置复制粘帖的快捷方式
    UC伯克利发布一个低成本家居机器人,会叠衣服、会泡咖啡
    称职QA经理必备的13项技能
    李开复:AI正在从黑科技变成主流,传统公司都需要“CAIO”
    为什么纸牌游戏Hanabi是人工智能的下一个挑战
    专家质疑亚马逊面部识别技术:机器眼里女士皮肤黑就等于是男人
    日媒联手高科技公司利用人工智能预测新闻对企业的影响
    Python 封王,Java和C宣布永久退出竞争舞台
    李开复:AI进入商用时代 偏重科研的“黑科技”非创业主旋律
    AI医疗与人类疾病的竞跑:5G落地,就像“三甲”到家
  • 原文地址:https://www.cnblogs.com/javashop-docs/p/12600831.html
Copyright © 2011-2022 走看看