一、Spring Security

一、Spring Security介绍

1、框架介绍

Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分。

(1)用户认证指的是:验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。

(2)用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。

Spring Security其实就是用filter,多请求的路径进行过滤。

(1)如果是基于Session,那么Spring-security会对cookie里的sessionid进行解析,找到服务器存储的sesion信息,然后判断当前用户是否符合请求的要求。

(2)如果是token,则是解析出token,然后将当前请求加入到Spring-security管理的权限信息中去

2、认证与授权实现思路

如果系统的模块众多,每个模块都需要就行授权与认证,所以我们选择基于token的形式进行授权与认证,用户根据用户名密码认证成功,然后获取当前用户角色的一系列权限值,并以用户名为key,权限列表为value的形式存入redis缓存中,根据用户名相关信息生成token返回,浏览器将token记录到cookie中,每次调用api接口都默认将token携带到header请求头中,Spring-security解析header头获取token信息,解析token获取当前用户名,根据用户名就可以从redis中获取权限列表,这样Spring-security就能够判断当前请求是否有权限访问。

二、整合Spring Security

1、在common下创建spring_security模块

2、在spring_security引入相关依赖

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>common</artifactId>
        <groupId>com.javaclimb</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>spring_security</artifactId>

    <dependencies>
        <dependency>
            <groupId>com.javaclimb</groupId>
            <artifactId>common_util</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.javaclimb</groupId>
            <artifactId>service_base</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
        <!-- Spring Security依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
        </dependency>
    </dependencies>

</project>

 

3、在service_acl引入spring_security依赖

<dependency>
    <groupId>com.javaclimb</groupId>
    <artifactId>spring_security</artifactId>
    <version>0.0.1-SNAPSHOT</version>
</dependency>

 

4、代码结构说明

核心配置类:TokenWebSecurityConfig

用户实体类:User 安全认证用户详情信息实体类:SecurityUser

登录过滤器:TokenLoginFilter

访问过滤器:TokenAuthenticationFilter

密码处理类:DefaultPasswordEncoder

登出业务逻辑类:TokenLogoutHandler

token操作工具类:TokenManager

未授权的统一处理方式:UnauthorizedEntryPoint

5、辅助类

(1) UserService.java

package com.stu.service.acl.service;

import com.stu.service.acl.entity.User;
import com.baomidou.mybatisplus.extension.service.IService;

/**
 * <p>
 * 用户表 服务类
 * </p>
 *
 * @author stu
 * @since 2022-08-16
 */
public interface UserService extends IService<User> {

    /***********************************
     * 用途说明:获取用户详情
     * @param username
     * 返回值说明:
     * @return com.stu.service.acl.entity.User
     ***********************************/
    User selectByUserName(String username);
}

 

(2) UserServiceImpl.java

package com.stu.service.acl.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.stu.service.acl.entity.User;
import com.stu.service.acl.mapper.UserMapper;
import com.stu.service.acl.service.UserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

/**
 * <p>
 * 用户表 服务实现类
 * </p>
 *
 * @author stu
 * @since 2022-08-16
 */
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    /***********************************
     * 用途说明:获取用户详情
     * @param username
     * 返回值说明:
     * @return com.stu.service.acl.entity.User
     ***********************************/
    @Override
    public User selectByUserName(String username) {
        return baseMapper.selectOne(new QueryWrapper<User>().eq("username", username));
    }
}

(3) PermissionMapper.java接口

package com.stu.service.acl.mapper;

import com.stu.service.acl.entity.Permission;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;

import java.util.List;

/**
 * <p>
 * 权限 Mapper 接口
 * </p>
 *
 * @author stu
 * @since 2022-08-16
 */
public interface PermissionMapper extends BaseMapper<Permission> {

    /***********************************
     * 用途说明:获取全部菜单的权限
     * 返回值说明:
     * @return java.util.List<java.lang.String>
     ***********************************/
    List<String> selectAllPermissionValue();

    /***********************************
     * 用途说明:根据用户id查询所有权限
     * @param id
     * 返回值说明:
     * @return java.util.List<java.lang.String>
     ***********************************/
    List<String> selectPermissionValueByUserId(String id);

    /***********************************
     * 用途说明:根据用户id查询所有菜单
     * @param userId
     * 返回值说明:
     * @return java.util.List<com.stu.service.acl.entity.Permission>
     ***********************************/
    List<Permission> selectPermissionByUserId(String userId);
}

(4) PermissionMapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.stu.service.acl.mapper.PermissionMapper">

    <resultMap id="permissionMap" type="com.stu.service.acl.entity.Permission">
        <result property="id" column="id"/>
        <result property="pid" column="pid"/>
        <result property="name" column="name"/>
        <result property="type" column="type"/>
        <result property="permissionValue" column="permission_value"/>
        <result property="path" column="path"/>
        <result property="component" column="component"/>
        <result property="icon" column="icon"/>
        <result property="status" column="status"/>
        <result property="isDeleted" column="is_deleted"/>
        <result property="gmtCreate" column="gmt_create"/>
        <result property="gmtModified" column="gmt_modified"/>
    </resultMap>

    <!-- 用于select查询公用抽取的列 -->
    <sql id="columns">
        p.id,p.pid,p.name,p.type,p.permission_value,path,p.component,p.icon,p.status,p.is_deleted,p.gmt_create,p.gmt_modified
    </sql>

    <select id="selectPermissionByUserId" resultMap="permissionMap">
        select
        <include refid="columns" />
        from acl_user_role ur
        inner join acl_role_permission rp on rp.role_id = ur.role_id
        inner join acl_permission p on p.id = rp.permission_id
        where ur.user_id = #{userId}
        and ur.is_deleted = 0
        and rp.is_deleted = 0
        and p.is_deleted = 0
    </select>

    <select id="selectPermissionValueByUserId" resultType="String">
        select
            p.permission_value
        from acl_user_role ur
                 inner join acl_role_permission rp on rp.role_id = ur.role_id
                 inner join acl_permission p on p.id = rp.permission_id
        where ur.user_id = #{userId}
          and ur.is_deleted = 0
          and rp.is_deleted = 0
          and p.is_deleted = 0
    </select>

    <select id="selectAllPermissionValue" resultType="String">
        select
            permission_value
        from acl_permission
          where is_deleted = 0
    </select>
</mapper>

(5)PermissionService.java接口

package com.stu.service.acl.service;

import com.alibaba.fastjson.JSONObject;
import com.stu.service.acl.entity.Permission;
import com.baomidou.mybatisplus.extension.service.IService;

import java.util.List;

/**
 * <p>
 * 权限 服务类
 * </p>
 *
 * @author stu
 * @since 2022-08-16
 */
public interface PermissionService extends IService<Permission> {

    /***********************************
     * 用途说明:查询所有权限菜单
     * 返回值说明:
     * @return java.util.List<com.stu.service.acl.entity.Permission>
     ***********************************/
    List<Permission> ListAllPermissions();

    /***********************************
     * 用途说明:递归删除菜单
     * @param id
     * 返回值说明:
     * @return boolean
     ***********************************/
    boolean removeChildById(String id);

    /***********************************
     * 用途说明:根據角色獲取菜單
     * @param id
     * 返回值说明:
     * @return java.util.List<com.stu.service.acl.entity.Permission>
     ***********************************/
    List<Permission> listAllMenu(String id);

    /***********************************
     * 用途说明:给角色分配菜单权限
     * @param roleId
     * @param permissionId
     * 返回值说明:
     * @return boolean
     ***********************************/
    boolean saveRolePermissionrelationShip(String roleId, String[] permissionId);

    /***********************************
     * 用途说明:根据用户id查询有权限的菜单
     * @param id
     * 返回值说明:
     * @return java.util.List<java.lang.String>
     ***********************************/
    List<String> selectPermissionValueListByUserId(String id);

    /***********************************
     * 用途说明:根据用户id查询所有权限的菜单详细列表
     * @param userId
     * 返回值说明:
     * @return java.util.List<org.json.JSONObject>
     ***********************************/
    List<JSONObject> selectPermissionByUserId(String userId);

}

(6) PermissionServiceImpl.java实现类

package com.stu.service.acl.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.stu.service.acl.entity.Permission;
import com.stu.service.acl.entity.RolePermission;
import com.stu.service.acl.entity.User;
import com.stu.service.acl.mapper.PermissionMapper;
import com.stu.service.acl.service.PermissionService;
import com.stu.service.acl.service.RolePermissionService;
import com.stu.service.acl.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 权限 服务实现类
 * </p>
 *
 * @author stu
 * @since 2022-08-16
 */
@Service
public class PermissionServiceImpl extends ServiceImpl<PermissionMapper, Permission> implements PermissionService {

    @Autowired
    private RolePermissionService rolePermissionService;

    @Autowired
    private UserService userService;

    /***********************************
     * 用途说明:查询所有权限菜单
     * 返回值说明:
     * @return java.util.List<com.stu.service.acl.entity.Permission>
     ***********************************/
    @Override
    public List<Permission> ListAllPermissions() {
        QueryWrapper<Permission> queryWrapper = new QueryWrapper<>();
        queryWrapper.orderByDesc("id");
        return bulidPermission(baseMapper.selectList(queryWrapper));
    }

    /***********************************
     * 用途说明:把返回所有菜单list集合进行封装的方法
     * @param list
     * 返回值说明:
     * @return java.util.List<com.stu.service.acl.entity.Permission>
     ***********************************/
    private List<Permission> bulidPermission(List<Permission> list) {
        //创建list集合,用于数据最终封装
        List<Permission> finalNode = new ArrayList<>();

        //把所有菜单list集合遍历,得到顶层菜单 pid=0菜单,设置level是1
        for (Permission permission : list) {
            //得到顶层菜单 pid=0菜单
            if ("0".equals(permission.getPid())) {
                permission.setLevel(1);
                //根据顶层菜单,向里面进行查询子菜单,封装到finalNode里面
                finalNode.add(selectChildren(permission, list));
            }
        }

        return finalNode;
    }

    /***********************************
     * 用途说明:递归查询下级菜单
     * @param permission
     * @param list
     * 返回值说明:
     * @return com.stu.service.acl.entity.Permission
     ***********************************/
    private Permission selectChildren(Permission permission, List<Permission> list) {
        //1 因为向一层菜单里面放二层菜单,二层里面还要放三层,把对象初始化
        permission.setChildren(new ArrayList<Permission>());
        //2 遍历所有菜单list集合,进行判断比较,比较id和pid值是否相同
        for (Permission child : list) {
            if (permission.getId().equals(child.getPid())) {
                child.setLevel(permission.getLevel() + 1);
                if (child.getChildren() == null) {
                    child.setChildren(new ArrayList<>());
                }
//                permission.getChildren().add(child);
//                selectChildren(child,list);
                permission.getChildren().add(selectChildren(child, list));
            }
        }
        return permission;

    }

    /***********************************
     * 用途说明:递归删除菜单
     * @param id
     * 返回值说明:
     * @return boolean
     ***********************************/
    @Override
    public boolean removeChildById(String id) {
        List<String> idList = new ArrayList<>();
        selectChildListById(id, idList);
        idList.add(id);
        return baseMapper.deleteBatchIds(idList) > 0;
    }

    /***********************************
     * 用途说明:根據角色獲取菜單
     * @param id
     * 返回值说明:
     * @return java.util.List<com.stu.service.acl.entity.Permission>
     ***********************************/
    @Override
    public List<Permission> listAllMenu(String id) {
        //获取所有菜单
        List<Permission> allPermissionList = baseMapper.selectList(new QueryWrapper<>());
        //根据角色id呼气角色权限列表
        List<RolePermission> rolePermissionsList = rolePermissionService
                .list(new QueryWrapper<RolePermission>().eq("role_id", id));
        //遍历所有菜单,获取每一项,看是否在权限列表,如果在,就标记
        List<String> permissionIdList = rolePermissionsList.stream().map(e -> e.getPermissionId()).collect(Collectors.toList());
        allPermissionList.forEach(permission -> {
            if (permissionIdList.contains(permission.getId())) {
                permission.setHasSelect(true);
            } else {
                permission.setHasSelect(false);
            }
        });
        /*for (int i = 0; i < allPermissionList.size(); i++) {
            Permission permission = allPermissionList.get(i);
            for (int m = 0; m < rolePermissionList.size(); m++) {
                RolePermission rolePermission = rolePermissionList.get(m);
                if(rolePermission.getPermissionId().equals(permission.getId())) {
                    permission.setSelect(true);
                }
            }
        }*/
        return bulidPermission(allPermissionList);
    }

    /***********************************
     * 用途说明:给角色分配菜单权限
     * @param roleId
     * @param permissionId
     * 返回值说明:
     * @return boolean
     ***********************************/
    @Override
    public boolean saveRolePermissionrelationShip(String roleId, String[] permissionId) {

        //删除旧的权限
        rolePermissionService.remove(new QueryWrapper<RolePermission>().eq("role_id", roleId));
        List<RolePermission> list = new ArrayList<>();
        for (String id : permissionId) {
            RolePermission rolePermission = new RolePermission();
            rolePermission.setRoleId(roleId);
            rolePermission.setPermissionId(id);
            list.add(rolePermission);
        }

        return rolePermissionService.saveBatch(list);
    }

    /***********************************
     * 用途说明:根据用户id查询有权限的菜单
     * @param id
     * 返回值说明:
     * @return java.util.List<java.lang.String>
     ***********************************/
    @Override
    public List<String> selectPermissionValueListByUserId(String id) {
        List<String> list;
        if (checkAdmin(id)) {
            //如果是超级管理员获取所有权限
            list = baseMapper.selectAllPermissionValue();
        } else {
            //根据用户id查询所有权限
            list = baseMapper.selectPermissionValueByUserId(id);
        }
        return list;
    }

    /***********************************
     * 用途说明:根据用户id查询所有权限的菜单详细列表
     * @param userId
     * 返回值说明:
     * @return java.util.List<org.json.JSONObject>
     ***********************************/
    @Override
    public List<JSONObject> selectPermissionByUserId(String userId) {
        List<Permission> selectPermissionList = null;
        if (checkAdmin(userId)) {
            //如果是超级管理员获取所有权限
            selectPermissionList = baseMapper.selectList(null);
        } else {
            //根据用户id查询所有权限
            selectPermissionList = baseMapper.selectPermissionByUserId(userId);
        }
        //先转换成树状
        List<Permission> permissionList = bulidPermission(selectPermissionList);
        //然后转化成前端需要的格式
        List<JSONObject> result = bulidJson(permissionList);

        return result;
    }

    /***********************************
     * 用途说明:转化成前端需要的格式
     * @param permissionList
     * 返回值说明:
     * @return java.util.List<org.json.JSONObject>
     ***********************************/
    private List<JSONObject> bulidJson(List<Permission> permissionList) {
        List<JSONObject> menus = new ArrayList<>();
        if (permissionList.size() == 1) {
            Permission topNode = permissionList.get(0);
            //组建左侧一级菜单
            List<Permission> oneMenuList = topNode.getChildren();
            for (Permission one : oneMenuList) {
                JSONObject oneMenu = new JSONObject();
                oneMenu.put("path", one.getPath());
                oneMenu.put("component", one.getComponent());
                oneMenu.put("redirect", "noredirect");//第一级不需要重定向
                oneMenu.put("name", "name_" + one.getId());
                oneMenu.put("hidden", false);//一级不需要因此,3级需要
                JSONObject oneMeta = new JSONObject();
                oneMeta.put("title", one.getName());
                oneMeta.put("icon", one.getIcon());
                oneMenu.put("meta", oneMeta);

                List<JSONObject> children = new ArrayList<>();
                List<Permission> twoMenuList = one.getChildren();//二级菜单
                for (Permission two : twoMenuList) {
                    JSONObject twoMenu = new JSONObject();
                    twoMenu.put("path", two.getPath());
                    twoMenu.put("component", two.getComponent());
//                    twoMenu.put("redirect", "noredirect");//第一级不需要重定向
                    twoMenu.put("name", "name_" + two.getId());
                    twoMenu.put("hidden", false);//一级不需要因此,3级需要
                    JSONObject twoMeta = new JSONObject();
                    twoMeta.put("title", two.getName());
                    twoMeta.put("icon", two.getIcon());
                    twoMenu.put("meta", twoMeta);
                    children.add(twoMenu);

                    //功能按钮
                    List<Permission> threeMenuList = two.getChildren();
                    for (Permission three : threeMenuList) {
                        if (StringUtils.isEmpty(three.getPath())) {
                            continue;
                        }
                        JSONObject threeMenu = new JSONObject();
                        threeMenu.put("path", three.getPath());
                        threeMenu.put("component", three.getComponent());
//                        threeMenu.put("redirect", "noredirect");//第一级不需要重定向
                        threeMenu.put("name", "name_" + three.getId());
                        threeMenu.put("hidden", true);//一级不需要因此,3级需要
                        JSONObject threeMeta = new JSONObject();
                        threeMeta.put("title", three.getName());
                        threeMeta.put("icon", three.getIcon());
                        threeMenu.put("meta", threeMeta);

                        children.add(threeMenu);
                    }

                }
                oneMenu.put("children", children);
                menus.add(oneMenu);

            }
        }
        return menus;
    }

    /***********************************
     * 用途说明:判断是否管理员
     * @param id
     * 返回值说明:
     * @return boolean
     ***********************************/
    private boolean checkAdmin(String id) {
        User user = userService.getById(id);
        if (user != null && "admin".equals(user.getUsername())) {
            return true;
        }
        return false;
    }

    /***********************************
     * 用途说明:根据当前菜单id查询他的子子孙孙id,封装到list集合
     * @param id
     * @param idList
     * 返回值说明:
     ***********************************/
    private void selectChildListById(String id, List<String> idList) {
        //查询当前菜单的下级
        QueryWrapper<Permission> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("pid", id);
        queryWrapper.select("id");
        List<Permission> childList = baseMapper.selectList(queryWrapper);
        //把childIdList里面菜单id值获取出来,封装idList里面,做递归查询
        childList.forEach(item -> {
            idList.add(item.getId());
            selectChildListById(item.getId(), idList);
        });

    }

}

(7)UserDetailsServiceImpl.java

package com.stu.service.acl.service.impl;

import com.stu.security.entity.SecurityUser;
import com.stu.service.acl.entity.User;
import com.stu.service.acl.service.PermissionService;
import com.stu.service.acl.service.UserService;
import com.stu.service.base.exception.CustomException;
import com.stu.service.base.result.ResultCodeEnum;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.List;

/******************************
 * 用途说明:自定义UserDetailsService实现类,认证用户详情
 * 作者姓名: Administrator
 * 创建时间: 2022-09-01 10:05
 ******************************/
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private UserService userService;

    @Autowired
    private PermissionService permissionService;

    /**
     *根据用户名查询用户信息
     * @param username the username identifying the user whose data is required.
     * @return a fully populated user record (never <code>null</code>)
     * @throws UsernameNotFoundException if the user could not be found or the user has no
     *                                   GrantedAuthority
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userService.selectByUserName(username);
        if(user == null){
           throw new CustomException(ResultCodeEnum.LOGIN_MOBILE_ERROR);
        }
        // 返回UserDetails实现类
        com.stu.security.entity.User curUser = new com.stu.security.entity.User();
        BeanUtils.copyProperties(user,curUser);
        //根据用户id查询有权限的菜单
        List<String> authorities = permissionService.selectPermissionValueListByUserId(user.getId());
        SecurityUser securityUser = new SecurityUser(curUser);
        securityUser.setPermissionValueList(authorities);
        return securityUser;
    }
}

 

(8)ResponseUtil.java

package com.stu.service.base.utils;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.stu.service.base.result.R;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/******************************
 * 用途说明:
 * 作者姓名: Administrator
 * 创建时间: 2022-09-01 20:44
 ******************************/
public class ResponseUtil {

    public static void out(HttpServletResponse response, R r) {
        ObjectMapper mapper = new ObjectMapper();
        response.setStatus(HttpStatus.OK.value());
        response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
        try {
            mapper.writeValue(response.getWriter(), r);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

 

(9)RoleService.java接口增加

 

package com.stu.service.acl.service;

import com.stu.service.acl.entity.Permission;
import com.stu.service.acl.entity.Role;
import com.baomidou.mybatisplus.extension.service.IService;

import java.util.List;
import java.util.Map;

/**
 * <p>
 *  服务类
 * </p>
 *
 * @author stu
 * @since 2022-08-16
 */
public interface RoleService extends IService<Role> {


    /***********************************
     * 用途说明:根据用户获取角色
     * @param userId
     * 返回值说明:
     * @return java.util.List<com.stu.service.acl.entity.Permission>
     ***********************************/
    Map<String, Object> findRoleByUserId(String userId);

    /***********************************
     * 用途说明:给用户分配角色权限
     * @param userId
     * @param permissionIds
     * 返回值说明:
     * @return boolean
     ***********************************/
    boolean saveUserRelationShip(String userId, String[] permissionIds);

    /***********************************
     * 用途说明:根据userid获取用户信息
     * @param id
     * 返回值说明:
     * @return java.util.List<com.stu.service.acl.entity.Role>
     ***********************************/
    List<Role> selectRoleByUserId(String id);
}

 

(10)模块RoleServiceImpl.java实现类

package com.stu.service.acl.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.stu.service.acl.entity.Permission;
import com.stu.service.acl.entity.Role;
import com.stu.service.acl.entity.RolePermission;
import com.stu.service.acl.entity.UserRole;
import com.stu.service.acl.mapper.RoleMapper;
import com.stu.service.acl.service.RoleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.stu.service.acl.service.UserRoleService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author stu
 * @since 2022-08-16
 */
@Service
public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {

    @Autowired
    private UserRoleService userRoleService;

    /***********************************
     * 用途说明:根据用户获取角色
     * @param userId
     * 返回值说明:
     * @return java.util.List<com.stu.service.acl.entity.Permission>
     ***********************************/
    @Override
    public Map<String, Object> findRoleByUserId(String userId) {
        //获取所有角色
        List<Role> allRoleList = baseMapper.selectList(new QueryWrapper<>());
        //根据用户id获取角色列表
        List<UserRole> existUserRoleList = userRoleService
                .list(new QueryWrapper<UserRole>().eq("user_id", userId).select("role_id"));
        //遍历所有菜单,获取每一项,看是否在权限列表,如果在,就标记
        List<String> existRoleLists = existUserRoleList.stream().map(e -> e.getRoleId()).collect(Collectors.toList());

        List<Role> assignRoles = new ArrayList<>();
        allRoleList.forEach(role -> {
            if (existRoleLists.contains(role.getId())) {
                assignRoles.add(role);
            }
        });

        Map<String, Object> roleMap = new HashMap<>();
        roleMap.put("assignRoles", assignRoles);
        roleMap.put("allRoleList", allRoleList);
        return roleMap;
    }

    /***********************************
     * 用途说明:给用户分配角色权限
     * @param userId
     * @param roleIds
     * 返回值说明:
     * @return boolean
     ***********************************/
    @Override
    public boolean saveUserRelationShip(String userId, String[] roleIds) {
        //删除旧的所有角色权限
        userRoleService.remove(new QueryWrapper<UserRole>().eq("user_id", userId));
        List<UserRole> list = new ArrayList<>();
        for (String id : roleIds) {
            UserRole rolePermission = new UserRole();
            rolePermission.setRoleId(id);
            rolePermission.setUserId(userId);
            list.add(rolePermission);
        }

        return userRoleService.saveBatch(list);
    }

    /***********************************
     * 用途说明:根据userid获取用户信息
     * @param userId
     * 返回值说明:
     * @return java.util.List<com.stu.service.acl.entity.Role>
     ***********************************/
    @Override
    public List<Role> selectRoleByUserId(String userId) {
        //根据用户id获取角色列表
        List<UserRole> userRoleList = userRoleService
                .list(new QueryWrapper<UserRole>().eq("user_id", userId).select("role_id"));
        //遍历所有菜单,获取每一项,看是否在权限列表,如果在,就标记
        List<String> roleIdLists = userRoleList.stream().map(e -> e.getRoleId()).collect(Collectors.toList());
        List<Role> roleList = new ArrayList<>();
        if (roleIdLists.size() > 0) {
            roleList = baseMapper.selectBatchIds(roleIdLists);
        }

        return roleList;
    }
}

 

(11)模块新增IndexService.java接口

package com.stu.service.acl.service;

import com.alibaba.fastjson.JSONObject;

import java.util.List;
import java.util.Map;

public interface IndexService {

    /***********************************
     * 用途说明:根据用户明获取用户登录信息
     * @param userName
     * 返回值说明:
     * @return java.util.Map<java.lang.String, java.lang.Object>
     ***********************************/
    Map<String, Object> getUserInfo(String userName);

    /***********************************
     * 用途说明:根据用户动态获取菜单
     * @param userName
     * 返回值说明:
     * @return java.util.List<org.json.JSONObject>
     ***********************************/
    List<JSONObject> getMenu(String userName);
}

(12)模块新增IndexServiceImpl.java实现类

package com.stu.service.acl.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.stu.service.acl.entity.Role;
import com.stu.service.acl.entity.User;
import com.stu.service.acl.service.IndexService;
import com.stu.service.acl.service.PermissionService;
import com.stu.service.acl.service.RoleService;
import com.stu.service.acl.service.UserService;
import com.stu.service.base.exception.CustomException;
import com.stu.service.base.result.ResultCodeEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/******************************
 * 用途说明:
 * 作者姓名: Administrator
 * 创建时间: 2022-09-01 22:34
 ******************************/
@Service
public class IndexServiceImpl implements IndexService {

    @Autowired
    private UserService userService;

    @Autowired
    private RoleService roleService;

    @Autowired
    private PermissionService permissionService;

    @Autowired
    private RedisTemplate redisTemplate;

    /***********************************
     * 用途说明:根据用户明获取用户登录信息
     * @param userName
     * 返回值说明:
     * @return java.util.Map<java.lang.String, java.lang.Object>
     ***********************************/
    @Override
    public Map<String, Object> getUserInfo(String userName) {
        Map<String, Object> result = new HashMap<>();
        User user = userService.selectByUserName(userName);
        if (user == null) {
            throw new CustomException(ResultCodeEnum.FETCH_USERINFO_ERROR);
        }
        //根据用户id获取角色
        List<Role> roleList = roleService.selectRoleByUserId(user.getId());
        //转换成角色名称列表
        List<String> roleNameList = roleList.stream()
                .map(item -> item.getRoleName()).collect(Collectors.toList());

        //前端框架必须返回一个角色,否则报错,如果没有角色,返回一个空角色
        if (roleNameList.size() == 0) {
            roleNameList.add("");
        }

        List<String> permissionValueList = permissionService.selectPermissionValueListByUserId(user.getId());
        redisTemplate.opsForValue().set(userName, permissionValueList);

        result.put("name", user.getUsername());
        result.put("roles", roleNameList);
        result.put("permissionValueList", permissionValueList);
        return result;
    }

    /***********************************
     * 用途说明:根据用户动态获取菜单
     * @param userName
     * 返回值说明:
     * @return java.util.List<org.json.JSONObject>
     ***********************************/
    @Override
    public List<JSONObject> getMenu(String userName) {
        User user = userService.selectByUserName(userName);
        if (user == null) {
            throw new CustomException(ResultCodeEnum.FETCH_USERINFO_ERROR);
        }
        //根据用户动态获取菜单
        return permissionService.selectPermissionByUserId(user.getId());
    }
}

(13) 模块新增IndexController.java

package com.stu.service.acl.controller.admin;

import com.alibaba.fastjson.JSONObject;
import com.stu.service.acl.service.IndexService;
import com.stu.service.base.result.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;

/******************************
 * 用途说明:
 * 作者姓名: Administrator
 * 创建时间: 2022-09-01 21:42
 ******************************/
@RestController
@RequestMapping("/admin/acl/index")
public class IndexController {

    @Autowired
    private IndexService indexService;

    /***********************************
     * 用途说明:退出
     * 返回值说明:
     * @return com.stu.service.base.result.R
     ***********************************/
    @PostMapping("logout")
    public R logout() {
        return R.ok();
    }

    /***********************************
     * 用途说明:
     * 返回值说明:
     * @return com.stu.service.base.result.R
     ***********************************/
    @GetMapping("getUserInfo")
    public R getUserInfo() {
        String userName = SecurityContextHolder.getContext().getAuthentication().getName();
        Map<String, Object> userInfo = indexService.getUserInfo(userName);

        return R.ok().data(userInfo);
    }

    /***********************************
     * 用途说明:根据用户明获取动态菜单
     * 返回值说明:
     * @return com.stu.service.base.result.R
     ***********************************/
    @GetMapping("menu")
    public R menu() {
        String userName = SecurityContextHolder.getContext().getAuthentication().getName();
        List<JSONObject> permissionList = indexService.getMenu(userName);
        return R.ok().data("permissionList", permissionList);
    }
}

6、Spring Security配置

(1)核心配置类:TokenWebSecurityConfig

Spring Security的核心配置就是继承WebSecurityConfigurerAdapter并注解@EnableWebSecurity的配置。

这个配置指明了用户名密码的处理方式、请求路径的开合、登录登出控制等和安全相关的配置。

package com.stu.security.config;

import com.stu.security.filter.TokenAuthenticationFilter;
import com.stu.security.filter.TokenLoginFilter;
import com.stu.security.security.DefaultPasswordEncoder;
import com.stu.security.security.TokenLogoutHandler;
import com.stu.security.security.TokenManager;
import com.stu.security.security.UnauthorizedEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;

/******************************
 * 用途说明:
 * 作者姓名: Administrator
 * 创建时间: 2022-09-01 9:30
 ******************************/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class TokenWebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private DefaultPasswordEncoder defaultPasswordEncoder;
    @Autowired
    private TokenManager tokenManager;
    @Autowired
    private RedisTemplate redisTemplate;


    /***********************************
     * 用途说明:密码处理
     * @param auth
     * 返回值说明:
     ***********************************/
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(defaultPasswordEncoder);
    }

    /***********************************
     * 用途说明:配置设置
     * @param http
     * 返回值说明:
     ***********************************/
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling().authenticationEntryPoint(new UnauthorizedEntryPoint())  //未授权异常处理
                .and().csrf().disable().authorizeRequests().anyRequest().authenticated() //取消跨域所有请求
                .and().logout().logoutUrl("/admin/acl/index/logout")
                .addLogoutHandler(new TokenLogoutHandler(tokenManager, redisTemplate))
                .and().addFilter(new TokenLoginFilter(authenticationManager(), tokenManager, redisTemplate))
                .addFilter(new TokenAuthenticationFilter(authenticationManager(), tokenManager, redisTemplate))
                .httpBasic();

    }

    /***********************************
     * 用途说明:配置哪些请求不拦截
     * @param web
     * 返回值说明:
     ***********************************/
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(
                "/api/**",
                "/swagger-resources/**",
                "/webjars/**",
                "/v2/**",
                "/swagger-ui.html/**"
        );
    }
}

(2)用户实体类:User

package com.stu.security.entity;

import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;

import java.io.Serializable;
import java.util.Date;

/******************************
 * 用途说明:
 * 作者姓名: Administrator
 * 创建时间: 2022-09-01 9:38
 ******************************/
@Data
@ApiModel(value = "User对象", description = "用户表")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "会员id")
    private String id;

    @ApiModelProperty(value = "用户名称")
    private String username;

    @ApiModelProperty(value = "密码")
    private String password;

    @ApiModelProperty(value = "昵称")
    private String nickName;

    @ApiModelProperty(value = "用户头像")
    private String salt;

    @ApiModelProperty(value = "用户签名")
    private String token;


}

(3)安全认证用户详情信息实体类:SecurityUser

package com.stu.security.entity;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/******************************
 * 用途说明:
 * 作者姓名: Administrator
 * 创建时间: 2022-09-01 9:38
 ******************************/
@Data
@Slf4j
public class SecurityUser implements UserDetails {

    //当前登录用户
    private transient User currentUserInfo;

    //当前登录用户权限
    private List<String> permissionValueList;

    public SecurityUser() {
    }

    public SecurityUser(User user) {
        if (user != null) {
            this.currentUserInfo = user;
        }
    }

    /***********************************
     * 用途说明:获取当前用户的所有权限
     * 返回值说明:
     * @return java.util.Collection<? extends org.springframework.security.core.GrantedAuthority>
     ***********************************/
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        for(String permissionValue:permissionValueList){
            if(StringUtils.isEmpty(permissionValue)){
                continue;
            }
            SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permissionValue);
            authorities.add(authority);
        }
        return authorities;
    }

    @Override
    public String getPassword() {
        return currentUserInfo.getPassword();
    }

    @Override
    public String getUsername() {
        return currentUserInfo.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

(4)登录过滤器:TokenLoginFilter

package com.stu.security.filter;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.stu.security.entity.SecurityUser;
import com.stu.security.entity.User;
import com.stu.security.security.TokenManager;
import com.stu.service.base.exception.CustomException;
import com.stu.service.base.result.R;
import com.stu.service.base.result.ResultCodeEnum;
import com.stu.service.base.utils.ResponseUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;

/******************************
 * 用途说明:登录过滤器,对用户名称和密码进行校验
 * 作者姓名: Administrator
 * 创建时间: 2022-09-01 9:39
 ******************************/
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {

    private AuthenticationManager authenticationManager;
    private TokenManager tokenManager;
    private RedisTemplate redisTemplate;

    public TokenLoginFilter(AuthenticationManager authenticationManager,
                            TokenManager tokenManager,
                            RedisTemplate redisTemplate) {
        this.authenticationManager = authenticationManager;
        this.tokenManager = tokenManager;
        this.redisTemplate = redisTemplate;
        //设置访问方式,可以post以为的访问
        this.setPostOnly(false);
        this.setRequiresAuthenticationRequestMatcher(
                new AntPathRequestMatcher("/admin/acl/login", "POST"));
    }

    /***********************************
     * 用途说明:验证账号密码是否正确
     * @param request
     * @param response
     * 返回值说明:
     * @return org.springframework.security.core.Authentication
     ***********************************/
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
        try {
            User user = new ObjectMapper().readValue(request.getInputStream(), User.class);
            return authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword(), new ArrayList<>()));
        } catch (Exception e) {
            e.printStackTrace();
            throw new CustomException(ResultCodeEnum.LOGIN_MOBILE_ERROR);
        }
    }

    /***********************************
     * 用途说明:登录成功
     * @param request
     * @param response
     * @param chain
     * @param authResult
     * 返回值说明:
     ***********************************/
    @Override
    protected void successfulAuthentication(HttpServletRequest request,
                                            HttpServletResponse response,
                                            FilterChain chain,
                                            Authentication authResult) throws IOException, ServletException {
        SecurityUser user = (SecurityUser) authResult.getPrincipal();
        String token = tokenManager.createToken(user.getCurrentUserInfo().getUsername());
        redisTemplate.opsForValue().set(user.getCurrentUserInfo().getUsername(), user.getPermissionValueList());
        ResponseUtil.out(response, R.ok().data("token", token));
    }

    /***********************************
     * 用途说明:登录失败
     * @param request
     * @param response
     * @param e
     * 返回值说明:
     ***********************************/
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
                                              AuthenticationException e) throws IOException, ServletException {
        ResponseUtil.out(response, R.error());
    }
}

(5)访问过滤器:TokenAuthenticationFilter.java

package com.stu.security.filter;

import com.stu.security.security.TokenManager;
import com.stu.service.base.result.R;
import com.stu.service.base.utils.ResponseUtil;
import io.netty.util.internal.StringUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.util.StringUtils;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/******************************
 * 用途说明:
 * 作者姓名: Administrator
 * 创建时间: 2022-09-01 9:39
 ******************************/
public class TokenAuthenticationFilter extends BasicAuthenticationFilter {

    private AuthenticationManager authenticationManager;
    private TokenManager tokenManager;
    private RedisTemplate redisTemplate;

    public TokenAuthenticationFilter(AuthenticationManager authenticationManager,
                                     TokenManager tokenManager,
                                     RedisTemplate redisTemplate) {
        super(authenticationManager);
        this.tokenManager = tokenManager;
        this.redisTemplate = redisTemplate;

    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain) throws IOException, ServletException {
        if (request.getRequestURI().indexOf("admin") == -1) {
            chain.doFilter(request, response);
            return;
        }
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = null;
        try {
            usernamePasswordAuthenticationToken = getAuthentication(request);
        } catch (Exception e) {
            ResponseUtil.out(response, R.error());
        }
        if (usernamePasswordAuthenticationToken != null) {
            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        } else {
            ResponseUtil.out(response, R.error());
        }
        chain.doFilter(request, response);
    }

    /***********************************
     * 用途说明:从request获取token,根据token获取权限列表
     * 返回值说明:
     * @return org.springframework.security.authentication.UsernamePasswordAuthenticationToken
     ***********************************/
    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        String token = request.getHeader("token");
        if (token != null && !"".equals(token.trim())) {
            String userName = tokenManager.getUserFromToken(token);
            List<String> permissionValueList = (List<String>) redisTemplate.opsForValue().get(userName);
            Collection<GrantedAuthority> authorities = new ArrayList<>();
            for (String permissionValue : permissionValueList) {
                if (StringUtils.isEmpty(permissionValue)) {
                    continue;
                }
                SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(permissionValue);
                authorities.add(simpleGrantedAuthority);
            }

            return new UsernamePasswordAuthenticationToken(userName, token, authorities);
        }
        return null;
    }
}

(6)密码处理类:DefaultPasswordEncoder

package com.stu.security.security;


import com.stu.service.base.utils.MD5;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

/******************************
 * 用途说明:
 * 作者姓名: Administrator
 * 创建时间: 2022-09-01 9:39
 ******************************/
@Component
public class DefaultPasswordEncoder implements PasswordEncoder {

    /**
     * 加密密码
     *
     * @param rawPassword
     */
    @Override
    public String encode(CharSequence rawPassword) {
        return MD5.encrypt(rawPassword.toString());
    }

    /**
     * 判断密码是否正确
     *
     * @param rawPassword     the raw password to encode and match
     * @param encodedPassword the encoded password from storage to compare with
     * @return true if the raw password, after encoding, matches the encoded password from
     * storage
     */
    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        return encodedPassword.equals(MD5.encrypt(rawPassword.toString()));
    }
}

(7)登出业务逻辑类:TokenLogoutHandler

package com.stu.security.security;

import com.stu.service.base.result.R;
import com.stu.service.base.utils.ResponseUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutHandler;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/******************************
 * 用途说明:
 * 作者姓名: Administrator
 * 创建时间: 2022-09-01 9:39
 ******************************/
public class TokenLogoutHandler implements LogoutHandler {

    private AuthenticationManager authenticationManager;
    private TokenManager tokenManager;
    private RedisTemplate redisTemplate;

    public TokenLogoutHandler(TokenManager tokenManager, RedisTemplate redisTemplate) {
        this.tokenManager = tokenManager;
        this.redisTemplate = redisTemplate;

    }

    @Override
    public void logout(HttpServletRequest request,
                       HttpServletResponse response,
                       Authentication authentication) {
        String token = request.getHeader("token");
        if (token != null) {
            tokenManager.removeToken(token);
            String userName = tokenManager.getUserFromToken(token);
            redisTemplate.delete(userName);
            ResponseUtil.out(response, R.ok());
        }

    }
}

(8)token操作工具类:TokenManager

package com.stu.security.security;

import io.jsonwebtoken.CompressionCodecs;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.stereotype.Component;

import java.util.Date;

/******************************
 * 用途说明:
 * 作者姓名: Administrator
 * 创建时间: 2022-09-01 9:40
 ******************************/
@Component
public class TokenManager {

    private long tokenExpiration = 24*60*60*1000;
    private String tokenSignKey = "123456";

    public String createToken(String username) {
        String token = Jwts.builder().setSubject(username)
                .setExpiration(new Date(System.currentTimeMillis() + tokenExpiration))
                .signWith(SignatureAlgorithm.HS512, tokenSignKey).compressWith(CompressionCodecs.GZIP).compact();
        return token;
    }

    public String getUserFromToken(String token) {
        String user = Jwts.parser().setSigningKey(tokenSignKey).parseClaimsJws(token).getBody().getSubject();
        return user;
    }

    public void removeToken(String token) {
        //jwttoken无需删除,客户端扔掉即可。
    }
}

(9)未授权的统一处理方式:UnauthorizedEntryPoint

package com.stu.security.security;

import com.stu.service.base.result.R;
import com.stu.service.base.utils.ResponseUtil;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/******************************
 * 用途说明:
 * 作者姓名: Administrator
 * 创建时间: 2022-09-01 9:40
 ******************************/
public class UnauthorizedEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest httpServletRequest,
                         HttpServletResponse httpServletResponse,
                         AuthenticationException e) throws IOException, ServletException {
        ResponseUtil.out(httpServletResponse, R.error());

    }
}

 

目录截图

 

作者:
出处:https://www.cnblogs.com/konglxblog//
版权:本文版权归作者和博客园共有
转载:欢迎转载,文章中请给出原文连接,此文章仅为个人知识学习分享,否则必究法律责任

 

posted @ 2022-10-17 22:33  程序员小明1024  阅读(45)  评论(0编辑  收藏  举报