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.