技术交流


springboot集成Security使用token实现认证授权(一) 准备篇

Apr 15, 2020 10:11:45 PM
103
9

springsecurity是企业中经常用到的安全控制框架,为我们提供认证授权的功能,由于securitysping无缝对接,让程序员的开发简单灵活。本文将简单地演示一下springsecurityspringboot项目中如何实现基于token的认证授权。

本文主要参考博客: https://www.cnblogs.com/ifme/p/12184587.html

RBAC

RBAC是基于角色的访问控制(Role-Based Access Control )。在 RBAC 中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。相当于权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便。

本文主要讲解通过角色来控制用户访问方法的权限。

建表语句

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
 
-- ----------------------------
-- Table structure for sys_permission
-- ----------------------------
DROP TABLE IF EXISTS `sys_permission`;
CREATE TABLE `sys_permission`  (
  `permission_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `permission_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '权限名称',
  `permission_desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '权限描述',
  PRIMARY KEY (`permission_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '权限表' ROW_FORMAT = Dynamic;
 
-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role`  (
  `role_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `role_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色名称',
  `role_desc` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色说明',
  INDEX `role_id`(`role_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色表' ROW_FORMAT = Dynamic;
 
-- ----------------------------
-- Table structure for sys_role_permission_auth
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_permission_auth`;
CREATE TABLE `sys_role_permission_auth`  (
  `role_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色id',
  `permission_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '权限id',
  UNIQUE INDEX `role_id`(`role_id`, `permission_id`) USING BTREE,
  INDEX `permission_id`(`permission_id`) USING BTREE,
  CONSTRAINT `sys_role_permission_auth_ibfk_1` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`role_id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
  CONSTRAINT `sys_role_permission_auth_ibfk_2` FOREIGN KEY (`permission_id`) REFERENCES `sys_permission` (`permission_id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '角色权限关联表' ROW_FORMAT = Dynamic;
 
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`  (
  `user_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
  `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户名',
  `password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '密码',
  `state` int(2) NOT NULL COMMENT '状态。1正常,2删除',
  PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
 
-- ----------------------------
-- Table structure for sys_user_role_auth
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role_auth`;
CREATE TABLE `sys_user_role_auth`  (
  `user_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '用户',
  `role_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '角色',
  UNIQUE INDEX `user_id`(`user_id`, `role_id`) USING BTREE,
  INDEX `role_id`(`role_id`) USING BTREE,
  CONSTRAINT `sys_user_role_auth_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `sys_user` (`user_id`) ON DELETE RESTRICT ON UPDATE RESTRICT,
  CONSTRAINT `sys_user_role_auth_ibfk_2` FOREIGN KEY (`role_id`) REFERENCES `sys_role` (`role_id`) ON DELETE RESTRICT ON UPDATE RESTRICT
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户角色关系表' ROW_FORMAT = Dynamic;
 
SET FOREIGN_KEY_CHECKS = 1;

 

代码实现

搭建maven工程

pom依赖

<!-- 安全框架 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>

<!-- 由于后面要用springcloud继续优化,所以选择了cloud-stater -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-security</artifactId>
</dependency>

<!-- jwt  -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-api</artifactId>
    <version>0.10.7</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-impl</artifactId>
    <version>0.10.7</version>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt-jackson</artifactId>
    <version>0.10.7</version>
    <scope>runtime</scope>
</dependency>

<!-- 获取配置信息 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
<!-- lombok插件 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

<!-- 时间工具包 -->
<dependency>
    <groupId>com.bluecatcode.time</groupId>
    <artifactId>joda-time-2.1-extended</artifactId>
    <version>1.1.0</version>
</dependency>

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- mybatis -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.1.1</version>
</dependency>
<!-- mysql连接工具 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <scope>runtime</scope>
</dependency>

 

启动类

@SpringBootApplication

//扫描dao接口
@MapperScan(basePackages = {"work.chenchuan.providertestone.**.dao"})
//开启事务管理
@EnableTransactionManagement
public class ProviderTestOneApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProviderTestOneApplication.class, args);
    }
}

 

导入工具类

json工具类:

public class JsonUtil {
    public static final ObjectMapper mapper = new ObjectMapper();

    private static final Logger logger = LoggerFactory.getLogger(JsonUtil.class);

    public static String toString(Object obj) {
        if (obj == null) {
            return null;
        }
        if (obj.getClass() == String.class) {
            return (String) obj;
        }
        try {
            return mapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            logger.error("json序列化出错:" + obj, e);
            return null;
        }
    }

    public static <T> T toBean(String json, Class<T> tClass) {
        try {
            return mapper.readValue(json, tClass);
        } catch (IOException e) {
            logger.error("json解析出错:" + json, e);
            return null;
        }
    }

    public static <E> List<E> toList(String json, Class<E> eClass) {
        try {
            return mapper.readValue(json, mapper.getTypeFactory().constructCollectionType(List.class, eClass));
        } catch (IOException e) {
            logger.error("json解析出错:" + json, e);
            return null;
        }
    }

    public static <K, V> Map<K, V> toMap(String json, Class<K> kClass, Class<V> vClass) {
        try {
            return mapper.readValue(json, mapper.getTypeFactory().constructMapType(Map.class, kClass, vClass));
        } catch (IOException e) {
            logger.error("json解析出错:" + json, e);
            return null;
        }
    }

    public static <T> T nativeRead(String json, TypeReference<T> type) {
        try {
            return mapper.readValue(json, type);
        } catch (IOException e) {
            logger.error("json解析出错:" + json, e);
            return null;
        }
    }
}

 

jwt工具类:

public class JwtUtil {
    private static final String JWT_PAYLOAD_USER_KEY = "user";

    /**
     * 私钥加密token
     *
     * @param userInfo   载荷中的数据
     * @param privateKey 私钥
     * @param expire     过期时间,单位分钟
     * @return JWT
     */
    public static String generateTokenExpireInMinutes(Object userInfo, PrivateKey privateKey, int expire) {
        return Jwts.builder()
                .claim(JWT_PAYLOAD_USER_KEY, JsonUtil.toString(userInfo))
                .setId(createJTI())
                .setExpiration(DateTime.now().plusMinutes(expire).toDate())
                .signWith(privateKey, SignatureAlgorithm.RS256)
                .compact();
    }

    /**
     * 私钥加密token
     *
     * @param userInfo   载荷中的数据
     * @param privateKey 私钥
     * @param expire     过期时间,单位秒
     * @return JWT
     */
    public static String generateTokenExpireInSeconds(Object userInfo, PrivateKey privateKey, int expire) {
        return Jwts.builder()
                .claim(JWT_PAYLOAD_USER_KEY, JsonUtil.toString(userInfo))
                .setId(createJTI())
                .setExpiration(DateTime.now().plusSeconds(expire).toDate())
                .signWith(privateKey, SignatureAlgorithm.RS256)
                .compact();
    }

    /**
     * 公钥解析token
     *
     * @param token     用户请求中的token
     * @param publicKey 公钥
     * @return Jws<Claims>
     */
    private static Jws<Claims> parserToken(String token, PublicKey publicKey) {
        return Jwts.parser().setSigningKey(publicKey).parseClaimsJws(token);
    }

    private static String createJTI() {
        return new String(Base64.getEncoder().encode(UUID.randomUUID().toString().getBytes()));
    }

    /**
     * 获取token中的用户信息
     *
     * @param token     用户请求中的令牌
     * @param publicKey 公钥
     * @return 用户信息
     */
    public static <T> Payload<T> getInfoFromToken(String token, PublicKey publicKey, Class<T> userType) {
        Jws<Claims> claimsJws = parserToken(token, publicKey);
        Claims body = claimsJws.getBody();
        Payload<T> claims = new Payload<>();
        claims.setId(body.getId());
        claims.setUserInfo(JsonUtil.toBean(body.get(JWT_PAYLOAD_USER_KEY).toString(), userType));
        claims.setExpiration(body.getExpiration());
        return claims;
    }

    /**
     * 获取token中的载荷信息
     *
     * @param token     用户请求中的令牌
     * @param publicKey 公钥
     * @return 用户信息
     */
    public static <T> Payload<T> getInfoFromToken(String token, PublicKey publicKey) {
        Jws<Claims> claimsJws = parserToken(token, publicKey);
        Claims body = claimsJws.getBody();
        Payload<T> claims = new Payload<>();
        claims.setId(body.getId());
        claims.setExpiration(body.getExpiration());
        return claims;
    }
}

 

rsa工具类:

public class RsaUtil {

    private static final int DEFAULT_KEY_SIZE = 2048;


    /**
     * 从文件中读取公钥
     *
     * @param filename 公钥保存路径,相对于classpath
     * @return 公钥对象
     * @throws Exception
     */
    public static PublicKey getPublicKey(String filename) throws Exception {
        byte[] bytes = readFile(filename);
        return getPublicKey(bytes);
    }

    /**
     * 从文件中读取密钥
     *
     * @param filename 私钥保存路径,相对于classpath
     * @return 私钥对象
     * @throws Exception
     */
    public static PrivateKey getPrivateKey(String filename) throws Exception {
        byte[] bytes = readFile(filename);
        return getPrivateKey(bytes);
    }

    /**
     * 获取公钥
     *
     * @param bytes 公钥的字节形式
     * @return
     * @throws Exception
     */
    private static PublicKey getPublicKey(byte[] bytes) throws Exception {
        bytes = Base64.getDecoder().decode(bytes);
        X509EncodedKeySpec spec = new X509EncodedKeySpec(bytes);
        KeyFactory factory = KeyFactory.getInstance("RSA");
        return factory.generatePublic(spec);
    }

    /**
     * 获取密钥
     *
     * @param bytes 私钥的字节形式
     * @return
     * @throws Exception
     */
    private static PrivateKey getPrivateKey(byte[] bytes) throws NoSuchAlgorithmException, InvalidKeySpecException {
        bytes = Base64.getDecoder().decode(bytes);
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(bytes);
        KeyFactory factory = KeyFactory.getInstance("RSA");
        return factory.generatePrivate(spec);
    }

    /**
     * 根据密文,生存rsa公钥和私钥,并写入指定文件
     *
     * @param publicKeyFilename  公钥文件路径
     * @param privateKeyFilename 私钥文件路径
     * @param secret             生成密钥的密文
     */
    public static void generateKey(String publicKeyFilename, String privateKeyFilename, String secret, int keySize) throws Exception {
        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
        SecureRandom secureRandom = new SecureRandom(secret.getBytes());
        keyPairGenerator.initialize(Math.max(keySize, DEFAULT_KEY_SIZE), secureRandom);
        KeyPair keyPair = keyPairGenerator.genKeyPair();
        // 获取公钥并写出
        byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
        publicKeyBytes = Base64.getEncoder().encode(publicKeyBytes);
        writeFile(publicKeyFilename, publicKeyBytes);
        // 获取私钥并写出
        byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
        privateKeyBytes = Base64.getEncoder().encode(privateKeyBytes);
        writeFile(privateKeyFilename, privateKeyBytes);
    }

    private static byte[] readFile(String fileName) throws Exception {
        return Files.readAllBytes(new File(fileName).toPath());
    }

    private static void writeFile(String destPath, byte[] bytes) throws IOException {
        File dest = new File(destPath);
        if (!dest.exists()) {
            dest.createNewFile();
        }
        Files.write(dest.toPath(), bytes);
    }
}

 

响应状态码枚举,定于程序响应状态的状态码和状态说明:

public enum ResponseCodeAndMsgEnum {
    SUCCESS("200", "请求成功"),
    FAILE("-1", "请求失败"),
    SYS_ERROR("500", "服务器内部错误"),
    UNAUTHORIZED("401", "没有权限访问该资源"),
    //FORBIDDEN("403", "没有权限访问该资源"),
    NOT_FOUND("404", "访问的资源不存在"),
    SERVICE_UNAVAILABLE("503","相关服务器异常,触发熔断");


    /**
     * 状态码
     */
    private String code;

    /**
     * 消息提示
     */
    private String msg;


    ResponseCodeAndMsgEnum(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

 

controller格式统一返回的属性:

public class JsonResult<T> {
    /**
     * 访问状态
     */
    private Boolean state;

    /**
     * 响应状态码
     */
    private String code;

    /**
     * 响应提示信息
     */
    private String msg;

    /**
     * 返回数据
     */
    private T data;

    /**
     * 请求路径
     */
    private String uri;

    /**
     * 当前时间
     */
    private Long timestamp;


    public Boolean getState() {
        return state;
    }

    public void setState(Boolean state) {
        this.state = state;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getUri() {
        return uri;
    }

    public void setUri(String uri) {
        this.uri = uri;
    }

    public Long getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(Long timestamp) {
        this.timestamp = timestamp;
    }
}

 

controller统一格式返回工具类:

public class JsonResponseUtil {

    /**
     * 请求成功默认
     */
    private static final ResponseCodeAndMsgEnum SUCCESS = ResponseCodeAndMsgEnum.SUCCESS;

    /**
     * 请求失败默认
     */
    private static final ResponseCodeAndMsgEnum FAILE = ResponseCodeAndMsgEnum.FAILE;

    /**
     * 系统服务错误映射
     */
    private static final ResponseCodeAndMsgEnum SYS_ERROR = ResponseCodeAndMsgEnum.SYS_ERROR;

    /**
     * 未授权映射
     */
    private static final ResponseCodeAndMsgEnum UNAUTHORIZED = ResponseCodeAndMsgEnum.UNAUTHORIZED;

    /**
     * 未找到资源映射
     */
    private static final ResponseCodeAndMsgEnum NOT_FOUND = ResponseCodeAndMsgEnum.NOT_FOUND;

    /**
     * 服务器由于维护或者负载过重未能应答或相关服务器异常,触发熔断
     */
    private static final ResponseCodeAndMsgEnum SERVICE_UNAVAILABLE = ResponseCodeAndMsgEnum.SERVICE_UNAVAILABLE;


    /**
     * 成功无数据——默认
     *
     * @return json对象
     */
    public static JsonResult success() {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setState(true);
        jsonResult.setCode(SUCCESS.getCode());
        jsonResult.setMsg(SUCCESS.getMsg());
        jsonResult.setData(null);
        jsonResult.setTimestamp(new Date().getTime());
        return jsonResult;
    }

    /**
     * 成功无数据——自定义codemsg
     *
     * @param code
     * @param msg
     * @return
     */
    public static JsonResult success(String code, String msg) {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setState(true);
        jsonResult.setCode(code);
        jsonResult.setMsg(msg);
        jsonResult.setData(null);
        jsonResult.setTimestamp(new Date().getTime());
        return jsonResult;
    }

    /**
     * 成功有数据——默认
     *
     * @param o
     * @return
     */
    public static JsonResult success(Object o) {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setState(true);
        jsonResult.setCode(SUCCESS.getCode());
        jsonResult.setMsg(SUCCESS.getMsg());
        jsonResult.setData(o);
        jsonResult.setTimestamp(new Date().getTime());
        return jsonResult;
    }

    /**
     * 成功有数据——自定义codemsg
     *
     * @param code
     * @param msg
     * @param o
     * @return
     */
    public static JsonResult success(String code, String msg, Object o) {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setState(true);
        jsonResult.setCode(code);
        jsonResult.setMsg(msg);
        jsonResult.setData(o);
        jsonResult.setTimestamp(new Date().getTime());
        return jsonResult;
    }

    /**
     * 失败无数据——默认
     *
     * @return
     */
    public static JsonResult fail() {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setState(false);
        jsonResult.setCode(FAILE.getCode());
        jsonResult.setMsg(FAILE.getMsg());
        jsonResult.setData(null);
        jsonResult.setTimestamp(new Date().getTime());
        return jsonResult;
    }

    /**
     * 失败无数据——自定义codemsg
     *
     * @param code
     * @param msg
     * @return
     */
    public static JsonResult fail(String code, String msg) {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setState(false);
        jsonResult.setCode(code);
        jsonResult.setMsg(msg);
        jsonResult.setData(null);
        jsonResult.setTimestamp(new Date().getTime());
        return jsonResult;
    }

    /**
     * 失败有数据——默认
     *
     * @return
     */
    public static JsonResult fail(Object o) {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setState(false);
        jsonResult.setCode(FAILE.getCode());
        jsonResult.setMsg(FAILE.getMsg());
        jsonResult.setData(o);
        jsonResult.setTimestamp(new Date().getTime());
        return jsonResult;
    }

    /**
     * 失败有数据——自定义codemsg
     *
     * @param code
     * @param msg
     * @param o
     * @return
     */
    public static JsonResult fail(String code, String msg, Object o) {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setState(false);
        jsonResult.setCode(code);
        jsonResult.setMsg(msg);
        jsonResult.setData(o);
        jsonResult.setTimestamp(new Date().getTime());
        return jsonResult;
    }

    /**
     * 内部服务器错误
     *
     * @return
     */
    public static JsonResult sysError() {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setState(false);
        jsonResult.setCode(SYS_ERROR.getCode());
        jsonResult.setMsg(SYS_ERROR.getMsg());
        jsonResult.setData(null);
        jsonResult.setTimestamp(new Date().getTime());
        return jsonResult;
    }

    /**
     * 没有权限访问资源
     *
     * @return
     */
    public static JsonResult unauthorized() {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setState(false);
        jsonResult.setCode(UNAUTHORIZED.getCode());
        jsonResult.setMsg(UNAUTHORIZED.getMsg());
        jsonResult.setData(null);
        jsonResult.setTimestamp(new Date().getTime());
        return jsonResult;
    }

    /**
     * 资源不存在
     *
     * @return
     */
    public static JsonResult notFound() {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setState(false);
        jsonResult.setCode(NOT_FOUND.getCode());
        jsonResult.setMsg(NOT_FOUND.getMsg());
        jsonResult.setData(null);
        jsonResult.setTimestamp(new Date().getTime());
        return jsonResult;
    }

    /**
     * 服务器由于维护或者负载过重未能应答或相关服务器异常,触发熔断
     * ————默认
     *
     * @return
     */
    public static JsonResult unavailable() {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setState(false);
        jsonResult.setCode(SERVICE_UNAVAILABLE.getCode());
        jsonResult.setMsg(SERVICE_UNAVAILABLE.getMsg());
        jsonResult.setData(null);
        jsonResult.setTimestamp(new Date().getTime());
        return jsonResult;
    }

    /**
     * 服务器由于维护或者负载过重未能应答或相关服务器异常,触发熔断
     * ————msg自定义
     *
     * @param msg
     * @return
     */
    public static JsonResult unavailable(String msg) {
        JsonResult jsonResult = new JsonResult();
        jsonResult.setState(false);
        jsonResult.setCode(SERVICE_UNAVAILABLE.getCode());
        jsonResult.setMsg(msg);
        jsonResult.setData(null);
        jsonResult.setTimestamp(new Date().getTime());
        return jsonResult;
    }

}

 

自定义基础异常类:

public class BaseException extends RuntimeException {

    /**
     * 状态码
     */
    private String code;


    /**
     * 默认异常信息
     *
     * @param jsonResult codemsg枚举
     */
    public BaseException(JsonResult jsonResult) {
        super(jsonResult.getMsg());
        this.code = jsonResult.getCode();
    }

    /**
     * 自定义msg
     *
     * @param message
     */
    public BaseException(String message) {
        super(message);
        this.code = ResponseCodeAndMsgEnum.FAILE.getCode();
    }

    /**
     * 自定义codemsg
     *
     * @param code 状态码
     * @param msg  消息提示
     */
    public BaseException(String code, String msg) {
        super(msg);
        this.code = code;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }
}

 

全局异常捕获:

@RestControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 自定义异常处理程序
     *
     * @param request
     * @param e
     * @return
     */
    @ExceptionHandler(value = RuntimeException.class)
    public JsonResult gloabalExceptionHandler(HttpServletRequest request, RuntimeException e) {
        e.printStackTrace();
        //异常状态码和消息提示,初始化未定义的异常信息为500
        ResponseCodeAndMsgEnum responseCodeAndMsgEnum = ResponseCodeAndMsgEnum.SYS_ERROR;
        String code = responseCodeAndMsgEnum.getCode();
        String msg = responseCodeAndMsgEnum.getMsg();
        //请求路径
        String uri = request.getRequestURI();
        //自定义异常codemsg
        if (e instanceof BaseException) {
            code = ((BaseException) e).getCode();
            msg = e.getMessage();
        }
        JsonResult jsonResult = JsonResponseUtil.fail(code, msg);
        jsonResult.setUri(uri);
        return jsonResult;
    }
}

 

数据写入响应的工具类:

public class DataToHttpServletResponseUtil {

    /**
     * 返回的统一json格式数据写入响应
     *
     * @return
     */
    public static void msgToResponseWhenSuccess(HttpServletResponse response, JsonResult jsonResult) {
        try {
            response.setContentType("application/json;charset=utf-8");
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            PrintWriter out = response.getWriter();
            out.write(new ObjectMapper().writeValueAsString(jsonResult));
            out.flush();
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

配置

yml配置

server:
  port: 9005
spring:
  application:
    # 服务别名
    name: provider-test-one
  # 数据源
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncodeing=utf-8&serverTimezone=GMT%2b8
    username: root
    password: 123

mybatis:
  ## mybatis扫描xml路径
  mapper-locations: classpath:providertestone/mybatis/mapper/**/*.xml

# jwtrsa加密
rsa:
  key:
    private-key-file: D:\P\ideaProjects\mine\springcloud-frame-v1\jwtRsaKey\private.key
    public-key-file: D:\P\ideaProjects\mine\springcloud-frame-v1\jwtRsaKey\public.pub

 

分对称性加密配置

@ConfigurationProperties(prefix = "rsa.key")
@Component
@Data
public class RsaProperties {
    /**
     * 私秘钥文件
     */
    private String privateKeyFile;

    /**
     * 公钥文件
     */
    private String publicKeyFile;

    /**
     * 公钥
     */
    private PublicKey publicKey;

    /**
     * 私钥
     */
    private PrivateKey privateKey;

    @PostConstruct
    public void createRsaKey() throws Exception {
        publicKey = RsaUtil.getPublicKey(publicKeyFile);
        privateKey = RsaUtil.getPrivateKey(privateKeyFile);
    }
}

 

实体类

用户:

@Data
public class UserPo extends BasePo implements UserDetails {
    private String userId;
    private String username;
    private String password;

    /**
     * 状态
     */
    private Integer state;

    /**
     * 角色集合
     */
    private List<RolePo> roleList = new ArrayList<>();

    @JsonIgnore
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return roleList;
    }

    /**
     * 账户是否过期
     * @return
     */
    @Override
    @JsonIgnore
    public boolean isAccountNonExpired() {
        return true;
    }

    /**
     * 账户是否锁定
     * @return
     */
    @Override
    @JsonIgnore
    public boolean isAccountNonLocked() {
        return true;
    }

    /**
     * 凭证是否可用
     * @return
     */
    @Override
    @JsonIgnore
    public boolean isCredentialsNonExpired() {
        return true;
    }

    /**
     * 账户是否启用
     * @return
     */
    @Override
    @JsonIgnore
    public boolean isEnabled() {
        return true;
    }
}

 

角色:

@Data
public class RolePo extends BasePo implements GrantedAuthority {
    private String roleId;
    private String roleName;
    private String roleDesc;


    /**
     * 权限列表本次暂时没有使用权限列表
     */
    private List<PermissionPo> permissionList = new ArrayList<>();

    //标记此属性不做json处理
    @JsonIgnore
    @Override
    public String getAuthority() {
        return roleName;
    }
}

 

权限:

@Data
public class PermissionPo extends BasePo {
    private String permissionId;
    private String permissionName;
    private String permissionDesc;
}

 

用户角色查询

usermapper文件,查询用户的角色:

mapper对应的接口忽略。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.2//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="work.chenchuan.providertestone.sys.dao.UserDao">

    <sql id="userObjResult">
       u.user_id    AS userId,
       u.username   AS username,
       u.password   AS password,
       u.state      AS state
    </sql>

    <!-- 用户权限集合 -->
    <resultMap id="userAndPermissionAuth" type="work.chenchuan.providertestone.sys.po.UserPo">
        <id column="userId" property="userId"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="state" property="state"/>
        <collection property="roleList" ofType="work.chenchuan.providertestone.sys.po.RolePo">
            <id column="roleId" property="roleId"/>
            <result column="roleName" property="roleName"/>
            <result column="roleDesc" property="roleDesc"/>
            <collection property="permissionList" ofType="work.chenchuan.providertestone.sys.po.PermissionPo">
                <id column="permissionId" property="permissionId"/>
                <result column="permissionName" property="permissionName"/>
                <result column="permissionDesc" property="permissionDesc"/>
            </collection>
        </collection>
    </resultMap>

    <!-- 根据登录信息获取用户详情 -->
    <select id="getUserByLoginInfo" parameterType="work.chenchuan.providertestone.sys.po.UserPo"
            resultMap="userAndPermissionAuth">
        SELECT
        <include refid="userObjResult"/>,
        <include refid="work.chenchuan.providertestone.sys.dao.RoleDao.roleObjResult"/>,
        <include refid="work.chenchuan.providertestone.sys.dao.PermissionDao.permissionObjResult"/>
        FROM `sys_user` u
        LEFT JOIN sys_user_role_auth ura
        ON u.user_id = ura.user_id
        LEFT JOIN sys_role r
        ON ura.role_id = r.role_id
        LEFT JOIN sys_role_permission_auth rpa
        ON r.role_id = rpa.role_id
        LEFT JOIN sys_permission p
        ON rpa.permission_id = p.permission_id
        <where>
            AND u.username = #{username}
        </where>
    </select>

</mapper>

 

UserService实现类:

service接口忽略

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserDao userDao;


    /**
     * 用户认证
     *
     * @param s
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        UserPo userPo = new UserPo();
        userPo.setUsername(s);
        userPo = userDao.getUserByLoginInfo(userPo);
        if (userPo == null) {
            return null;
        }
        return userPo;
    }
}


接下文“springboot集成Security使用token实现认证授权(二)  认证授权”......



如果你喜欢我的内容,就请打赏一下吧
微信
支付宝
温馨提示: 你的打赏金额会直接转入对方账户,不可退回。

评论专区


审核通过的评论(0)
暂无评论信息
个人名片

  欢迎来到“浩瀚星尘”的个人博客!
  首先,该博客用于分享本人的生活事迹与兴趣爱好; 此外,该博客的主要作用便是与广大的小伙伴一起分享探讨开发技术, 希望大家多多关照。

网名: 浩瀚星尘
城市: 重庆
工作: java