SpringBoot整合Shiro+Redis框架权限管理

这里用到的Redis参考我写的另一篇博客Redis+SpringBoot整合注解版

本文是我从项目中截取出来的,可能直接跑是跑不起来


一、导入依赖

        <!--		shiro的依赖-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.0</version>
        </dependency>
        <!-- shiro+redis缓存插件 -->
        <dependency>
            <groupId>org.crazycake</groupId>
            <artifactId>shiro-redis</artifactId>
            <version>3.1.0</version>
        </dependency>

二、Config类

2.1、自定义realm

import com.example.arcsoft_Administration.lcy_module.service.UserService;
import com.example.arcsoft_Administration.public_module.entity.Permission;
import com.example.arcsoft_Administration.public_module.entity.Role;
import com.example.arcsoft_Administration.public_module.entity.User;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

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

/**
 * 自定义realm
 */
public class CustomRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    /**
     * 用户登录的时候会调用
     *
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        System.out.println("认证 doGetAuthenticationInfo");

        //从token获取用户信息,token代表用户输入
        String username = (String) token.getPrincipal();

        User user = userService.findAllUserInfoByUsername(username);
        user.toString();

        //取密码
        String pwd = user.getPassword();
        if (pwd == null || "".equals(pwd)) {
            return null;
        }

        return new SimpleAuthenticationInfo(user, user.getPassword(), this.getClass().getName());
    }

    /**
     * 进行权限校验的时候回调用
     *
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("授权 doGetAuthorizationInfo");
        User newUser = (User) principals.getPrimaryPrincipal();
//        newUser.toString();
        User user = userService.findAllUserInfoByUsername(newUser.getUsername());

//        user.toString();

        //角色集合
        List<String> stringRoleList = new ArrayList<>();
        //权限集合
        List<String> stringPermissionList = new ArrayList<>();


        List<Role> roleList = user.getRoleList();

        for (Role role : roleList) {
            stringRoleList.add(role.getName());

            List<Permission> permissionList = role.getPermissionList();

            for (Permission p : permissionList) {
                if (p != null) {
                    stringPermissionList.add(p.getName());
                }
            }

        }

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addRoles(stringRoleList);
        simpleAuthorizationInfo.addStringPermissions(stringPermissionList);

        return simpleAuthorizationInfo;
    }
}

2.2、自定义AuthorizationFilter

import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
 * 自定义权限拦截,原来是两个缺一不可现在是满足其中一个即可
 * @author lichangyuan
 * @create 2021-02-08 12:28
 */
public class CustomRolesOrAuthorizationFilter extends AuthorizationFilter {

    @Override
    protected boolean isAccessAllowed(ServletRequest req, ServletResponse resp, Object mappedValue) throws Exception {

        Subject subject = getSubject(req, resp);

        //获取当前访问路径所需要的角色集合
        String[] rolesArray = (String[]) mappedValue;

        //没有角色限制,有权限访问
        if (rolesArray == null || rolesArray.length == 0) {
            return true;
        }

        //当前subject是rolesArray(门槛条件)中的任何一个,则有权限访问
        for (int i = 0; i < rolesArray.length; i++) {
            if (subject.hasRole(rolesArray[i])) {
                return true;
            }
        }

        return false;
    }
}

2.3、自定义SessionIdGenerator

自定义SessionId

import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.eis.SessionIdGenerator;

import java.io.Serializable;
import java.util.UUID;

/**
 * 自定义sesionid生成
 */
public class CustomSessionIdGenerator implements SessionIdGenerator {

    @Override
    public Serializable generateId(Session session) {
        return "ACE_"+UUID.randomUUID().toString().replace("-","");
    }
}

2.4、自定义DefaultWebSessionManager

import org.apache.shiro.web.servlet.ShiroHttpServletRequest;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.Serializable;

public class CustomSessionManager extends DefaultWebSessionManager {

    private static final String AUTHORIZATION = "token";


    public CustomSessionManager(){
        super();
    }

    @Override
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {

        String sessionId = WebUtils.toHttp(request).getHeader(AUTHORIZATION);

        if(sessionId != null){
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
                    ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionId);

            //automatically mark it valid here.  If it is invalid, the
            //onUnknownSession method below will be invoked and we'll remove the attribute at that time.
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
            return sessionId;

        }else {
            return super.getSessionId(request,response);
        }

    }
    
}

2.5、ShiroConfig

import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {


    @Bean
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {

        System.out.println("执行 ShiroFilterFactoryBean.shiroFilter()");

        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();

        //必须设置securityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);


        //需要登录的接口,如果访问某个接口,需要登录却没登录,则调用此接口(如果不是前后端分离,则跳转页面)
        shiroFilterFactoryBean.setLoginUrl("/pub/need_login");

        //登录成功,跳转url,如果前后端分离,则没这个调用
        shiroFilterFactoryBean.setSuccessUrl("/");

        //没有权限,未授权就会调用此方法, 先验证登录-》再验证是否有权限
        shiroFilterFactoryBean.setUnauthorizedUrl("/pub/not_permit");

        //加载设置自定义的filter
        Map<String, Filter> filterMap = new LinkedHashMap<>();
        filterMap.put("roleOrFilter", new CustomRolesOrAuthorizationFilter());

        shiroFilterFactoryBean.setFilters(filterMap);

        //拦截器路径,坑一,部分路径无法进行拦截,时有时无;因为同学使用的是hashmap, 无序的,应该改为LinkedHashMap
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();

        //退出过滤器
//        filterChainDefinitionMap.put("/logout","anon");

        //匿名可以访问,也是就游客模式
        filterChainDefinitionMap.put("/pub/**", "anon");
        filterChainDefinitionMap.put("/file/**", "anon");

        //有管理员编辑权限才可以访问
        filterChainDefinitionMap.put("/authc/admin/**", "perms[admin_update]");

        //有巡检员编辑权限才可以访问
        filterChainDefinitionMap.put("/authc/inspector/**", "perms[inspector_update]");

        //登录用户就可以访问的接口
        filterChainDefinitionMap.put("/authc/**", "authc");


//        //管理员和超管角色才可以访问的接口(比如修改)(我们自定义的AuthorizationFilter)
//        filterChainDefinitionMap.put("/admin/**", "roleOrFilter[admin,root]");

//        //巡检员和超管角色才可以访问的接口(比如修改)(我们自定义的AuthorizationFilter)
//        filterChainDefinitionMap.put("/inspector/**", "roleOrFilter[inspector,root]");

        //超管角色才可以访问的接口(比如修改和人员管理的接口)(我们自定义的AuthorizationFilter)
        filterChainDefinitionMap.put("/root/**", "roleOrFilter[root]");

//        //管理员角色才可以访问(与的关系)
//        filterChainDefinitionMap.put("/admin/**", "roles[admin]");


        //不拦截swagger
        filterChainDefinitionMap.put("/swagger-ui.html", "anon");
        filterChainDefinitionMap.put("/swagger-resources", "anon");
        filterChainDefinitionMap.put("/v2/api-docs", "anon");
        filterChainDefinitionMap.put("/webjars/springfox-swagger-ui/**", "anon");
        filterChainDefinitionMap.put("/configuration/security", "anon");
        filterChainDefinitionMap.put("/configuration/ui", "anon");
        filterChainDefinitionMap.put("/webjars/**", "anon");
        filterChainDefinitionMap.put("/configuration/**", "anon");


        //坑二: 过滤链是顺序执行,从上而下,一般讲/** 放到最下面

        //authc : url定义必须通过认证才可以访问
        //anon  : url可以匿名访问
        filterChainDefinitionMap.put("/**", "authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }


    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        //如果不是前后端分离,则不必设置下面的sessionManager
        securityManager.setSessionManager(sessionManager());

        //使用自定义的cacheManager
        securityManager.setCacheManager(CacheManager());

        //设置realm(推荐放到最后,不然某些情况会不生效)
        securityManager.setRealm(customRealm());

        return securityManager;
    }


    /**
     * 自定义realm
     *
     * @return
     */
    @Bean
    public CustomRealm customRealm() {
        CustomRealm customRealm = new CustomRealm();

        customRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return customRealm;
    }


    /**
     * 密码加解密规则
     *
     * @return
     */
    @Bean
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();

        //设置散列算法:这里使用的MD5算法
        credentialsMatcher.setHashAlgorithmName("md5");

        //散列次数,好比散列2次,相当于md5(md5(xxxx))
        credentialsMatcher.setHashIterations(2);

        return credentialsMatcher;
    }


    //自定义sessionManager
    @Bean
    public SessionManager sessionManager() {

        CustomSessionManager customSessionManager = new CustomSessionManager();

        //超时时间,默认 30分钟,会话超时;方法里面的单位是毫秒
//        customSessionManager.setGlobalSessionTimeout(1800000);
//        永不过期
        customSessionManager.setGlobalSessionTimeout(-1000L);

        //配置session持久化
        customSessionManager.setSessionDAO(redisSessionDAO());

        return customSessionManager;
    }

    /**
     * 配置RedisManager
     *
     * @return
     */
    public RedisManager getRedisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost("localhost");
        redisManager.setPort(6379);
        return redisManager;
    }

    public RedisCacheManager CacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(getRedisManager());

        //设置过期时间,单位是秒,权限校验的时才
        redisCacheManager.setExpire(120);

        return redisCacheManager;
    }

    /**
     * 自定义session持久化
     *
     * @return
     */
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        //redis缓存
        redisSessionDAO.setRedisManager(getRedisManager());

        //设置sessionid生成器
        redisSessionDAO.setSessionIdGenerator(new CustomSessionIdGenerator());
        return redisSessionDAO;
    }

    /**
     * 管理shiro一些bean的生命周期 即bean初始化 与销毁
     *
     * @return
     */
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }


    /**
     * api controller 层面
     * 加入注解的使用,不加入这个AOP注解不生效(shiro的注解 例如 @RequiresGuest)
     *
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }


    /**
     * 用来扫描上下文寻找所有的Advistor(通知器),
     * 将符合条件的Advisor应用到切入点的Bean中,需要在LifecycleBeanPostProcessor创建后才可以创建
     *
     * @return
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setUsePrefix(true);
        return defaultAdvisorAutoProxyCreator;
    }

}

三、登陆注册及其他接口

3.1、Controller层

@RestController
@RequestMapping("pub")
@CrossOrigin//跨域
@Transactional(rollbackFor = Exception.class)//事物回滚
public class PublicController {

    @Autowired
    private UserService userService;

    @Autowired
    private CommonUtils commonUtils;

    @RequestMapping("need_login")
    public JsonData needLogin() {

        return JsonData.buildError(-1, "温馨提示:请使用对应的账号登录");

    }


    @RequestMapping("not_permit")
    public JsonData notPermit() {

        return JsonData.buildError(-2, "温馨提示:拒绝访问,没权限");
    }

    /**
     * 登录接口
     *
     * @param userQuery
     * @param request
     * @param response
     * @return
     */
    @PostMapping("login")
    public JsonData login(@RequestBody UserQuery userQuery, HttpServletRequest request, HttpServletResponse response) {

        Subject subject = SecurityUtils.getSubject();
        Map<String, Object> info = new HashMap<>(16);
        try {
//            System.out.println(userQuery.getName()+userQuery.getPwd());
            UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(userQuery.getName(), userQuery.getPwd());

            subject.login(usernamePasswordToken);

            info.put("msg", "登录成功");
            info.put("token", subject.getSession().getId());

            return JsonData.buildSuccess(info);

        } catch (Exception e) {
            e.printStackTrace();
            throw new LCYException(-1, "账号或者密码错误");
        }
    }

    /**
     * 获取用户基本信息
     *
     * @return
     */
    @RequestMapping("api/getUserInfo")
    public JsonData getinfo() {
        try {
            User principal = userService.findAllUserInfoByUsername(ShiroUtils.getUser().getUsername());
			//User principal = ShiroUtils.getUser();
            if (principal != null) {
                //隐藏密码
                principal.setPassword(null);

                //返回数据存储map
                Map<String, Object> resultinfo = new HashMap<>(16);
                //储存基本信息

                resultinfo.put("user_info", principal);
                //储存信息中的角色
                List<String> stringRoleList = new ArrayList<>();
                List<Role> roleList = principal.getRoleList();
                for (Role role : roleList) {
                    stringRoleList.add(role.getName());
                }
                resultinfo.put("roles", stringRoleList);

                //查找用户的未读信息
                int userId = ShiroUtils.getUser().getId();
                Integer messageCounts = messageService.selectUserUnreadInformation(userId, 0);

                resultinfo.put("messageCounts",messageCounts);

                return JsonData.buildSuccess(resultinfo);
            } else {
                return JsonData.buildError("token无效");
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new LCYException(-1, "查询失败,可能参数原因(例如类型)");
        }
    }

    /**
     * 注册接口
     *
     * @param register_info
     * @return
     */

    @PostMapping("api/register")
    public JsonData register(@RequestBody Map<String, Object> register_info) {
        try {
            if (!commonUtils.traversingMap(new Object[]{
                    register_info.get("username"),
                    register_info.get("password"),
                    register_info.get("name"),
                    register_info.get("sex"),
                    register_info.get("phone"),
                    register_info.get("department"),
                    register_info.get("company"),
                    register_info.get("address"),
                    register_info.get("pic")})) {
                return JsonData.buildError("create");
            }
            User user = new User();
            user.setUsername(String.valueOf(register_info.get("username")));
            user.setPassword(String.valueOf(register_info.get("password")));
            user.setName(String.valueOf(register_info.get("name")));
            user.setSex(String.valueOf(register_info.get("sex")));
            user.setPhone(String.valueOf(register_info.get("phone")));
            user.setDepartment(String.valueOf(register_info.get("department")));
            user.setCompany(String.valueOf(register_info.get("company")));
            user.setAddress(String.valueOf(register_info.get("address")));
            return userService.registerAndAddRole(user, String.valueOf(register_info.get("create")));
        } catch (Exception e) {
            e.printStackTrace();
            throw new LCYException(-1, "查询失败,可能参数原因(例如类型)");
        }
    }

    /**
     * 退出接口
     *
     * @return
     */
    @RequestMapping("logout")
    public JsonData findMyPlayRecord() {

        try {
            Subject subject = SecurityUtils.getSubject();

            if (subject.getPrincipals() == null) {
                return JsonData.buildError("退出登陆失败(token错误)");
            }

            SecurityUtils.getSubject().logout();

            return JsonData.buildSuccess("退出登录成功");
        } catch (Exception e) {
            e.printStackTrace();
            throw new LCYException(-1, "查询失败,可能参数原因(例如类型)");
        }

    }
}

3.2、Service层

3.2.1、UserService

public interface UserService {


    /**
     * 获取全部用户信息,包括角色,权限
     * @param username
     * @return
     */
    User findAllUserInfoByUsername(String username);


    /**
     * 获取用户基本信息
     * @param userId
     * @return
     */
    User findSimpleUserInfoById(int userId);


    /**
     * 根据用户名查找用户信息
     * @param username
     * @return
     */
    User findSimpleUserInfoByUsername(String username);

    /**
     * 接收添加用户并赋予默认的权限
     * @param user
     * @param create
     * @return
     */
    JsonData registerAndAddRole(User user,String create);
}

3.2.2、UserServiceImpl

@Service
public class UserServiceImpl implements UserService {


    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    CommonUtils commonUtils;

    @Override
    @Cacheable(value = "user-redis-cache", key = "'UserService'+'findAllUserInfoByUsername'+#username")
    public User findAllUserInfoByUsername(String username) {
        //第一次查找只返回用户的基础信息
        User user = userMapper.findByUsername(username);

        //第二次查找返回用户的角色集合,并查找每个角色的权限集合
        List<Role> roleList = roleMapper.findRoleListByUserId(user.getId());

        //添加到user中
        user.setRoleList(roleList);

        return user;
    }


    @Override
    @Cacheable(value = "user-redis-cache", key = "'UserService'+'findSimpleUserInfoById'+#userId")
    public User findSimpleUserInfoById(int userId) {
        return userMapper.findById(userId);
    }


    @Override
    @Cacheable(value = "user-redis-cache", key = "'UserService'+'findSimpleUserInfoByUsername'+#username")
    public User findSimpleUserInfoByUsername(String username) {
        return userMapper.findByUsername(username);
    }

    @Override
    @CacheEvict(value = "user-redis-cache", allEntries = true)
    public JsonData registerAndAddRole(User user, String create) {
        if (commonUtils.strIsEmpty(user.getUsername()) || commonUtils.strIsEmpty(user.getPassword()) || commonUtils.strIsEmpty(user.getName()) || commonUtils.strIsEmpty(user.getCompany())) {
            return JsonData.buildError("账户,密码,姓名,公司不能为空");
        }
        if (userMapper.findByUsername(user.getUsername()) == null) {
            Integer roleId;
            String remarks;
//            if ("0".equals(create)) {
//                roleId = roleMapper.findRoleIdByRoleName("user");
//                remarks = user.getUsername() + "是" + "普通用户";
//            } else {
            //如果创建公司已存在
            if (userMapper.findCompany(user.getCompany()) != 0) {
                return JsonData.buildError("该公司已存在,不能创建");
            }
            userMapper.insertCompany(user.getCompany());
            roleId = roleMapper.findRoleIdByRoleName("root");
            remarks = user.getUsername() + "是" + "超级管理员";
            //}
            //给密码加密
            user.setPassword(commonUtils.MD5(user.getPassword()));
            //设置时间
            user.setCreateTime(new Date());
            //添加用户
            userMapper.addUser(user);
            //添加用户权限
            userMapper.addUserRole(user.getId(), roleId, remarks);

//                int i=1/0;

            return JsonData.buildSuccess("注册成功");
        } else {
            return JsonData.buildError("注册失败,该用户已存在");
        }

    }

}

3.3、Mapper层

RoleMapper

import com.example.arcsoft_Administration.public_module.entity.Role;
import org.apache.ibatis.annotations.*;
import org.apache.ibatis.mapping.FetchType;

import java.util.List;

public interface RoleMapper {
    /**
     * 查找角色集合通过用户id
     *
     * @param userId
     * @return
     */
    @Select("select ur.role_id as id, " +
            "r.name as name, " +
            "r.description as description " +
            " from  user_role ur left join role r on ur.role_id = r.id " +
            "where  ur.user_id = #{userId}")
    @Results(
            value = {
                    @Result(id = true, property = "id", column = "id"),
                    @Result(property = "name", column = "name"),
                    @Result(property = "description", column = "description"),
                    @Result(property = "permissionList", column = "id",
                            many = @Many(select = "com.example.arcsoft_Administration.lcy_module.mapper.PermissionMapper.findPermissionListByRoleId", fetchType = FetchType.DEFAULT)
                    )
            }
    )
    List<Role> findRoleListByUserId(@Param("userId") int userId);

    /**
     * 查找角色id通过姓名
     * @param roleName
     * @return
     */
    Integer findRoleIdByRoleName(@Param("roleName") String roleName);

    /**
     * 查找角色描述通过id
     * @param roleId
     * @return
     */
    String findRoleDescriptionById(@Param("roleId") Integer roleId);
}

userMapper

import com.example.arcsoft_Administration.public_module.entity.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;


public interface UserMapper  {

    /**
     * 查找用户通过名字
     *
     * @param username
     * @return
     */
    @Select("select * from user where username = #{username}")
    User findByUsername(@Param("username") String username);


    /**
     * 查找用户通过id
     *
     * @param id
     * @return
     */
    @Select("select * from user where id=#{userId}")
    User findById(@Param("userId") int id);


    /**
     * 查找用户通过账号和密码
     *
     * @param username
     * @param pwd
     * @return
     */
    @Select("select * from user where username = #{username} and password = #{pwd}")
    User findByUsernameAndPwd(@Param("username") String username, @Param("pwd") String pwd);

    /**
     * 添加用户返回id值
     *
     * @param user
     * @return
     */
    Integer addUser(User user);

    /**
     * 赋予用户不同的角色
     *
     * @param userId
     * @param roleId
     * @param remarks
     */
    void addUserRole(@Param("userId") Integer userId, @Param("roleId") Integer roleId, @Param("remarks") String remarks);

}

PermissionMapper

import com.example.arcsoft_Administration.public_module.entity.Equipment;
import com.example.arcsoft_Administration.public_module.entity.Permission;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface PermissionMapper  {

    /**
     * 查找权限集合通过角色id
     * @param roleId
     * @return
     */
    @Select("select p.id as id, p.name as name, p.url as url from  role_permission rp " +
            "left join permission p on rp.permission_id=p.id " +
            "where  rp.role_id= #{roleId} ")
    List<Permission> findPermissionListByRoleId(@Param("roleId") int roleId);

}

3.4、Entity实体类

3.4.1、Role

public class Role implements Serializable {

    private int id;

    private String name;

    private String description;

    //权限集合
    private List<Permission> permissionList;
}

3.4.2、User

public class User implements Serializable {
    private int id;

    private String username;

    private String password;
    
    private String name;
}

3.4.3、UserQuery

public class UserQuery implements Serializable {

    private String name;

    private String pwd;
}

3.4.4、UserRole

public class UserRole implements Serializable {

    private int id;

    private int userId;

    private int roleId;
}

3.5、数据库设计

设计图
具体设计


四、Shiro相关的自定义工具类

4.1、ShiroUtils

import com.example.arcsoft_Administration.public_module.entity.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.apache.shiro.subject.Subject;

/**
 * @author lichangyuan
 * @create 2021-03-04 10:05
 */
public class ShiroUtils {
    /**
     * @return
     */
    public static Subject getSubjct() {
        return SecurityUtils.getSubject();
    }

    /**
     * 获取用户信息
     *
     * @return
     */
    public static User getUser() {
        return (User) getSubjct().getPrincipal();
    }

    /**
     * 切换身份,登录后,动态更改subject的用户属性
     *
     * @param newUserInfo
     */
    public static void setUser(User newUserInfo) {
        Subject subject = SecurityUtils.getSubject();
        PrincipalCollection principalCollection = subject.getPrincipals();
        String realmName = principalCollection.getRealmNames().iterator().next();
        PrincipalCollection newPrincipalCollection =
                new SimplePrincipalCollection(newUserInfo, realmName);
        subject.runAs(newPrincipalCollection);
    }
}

4.2、CommonUtils

@Component
public class CommonUtils {


    /**
     * MD5加密工具类
     *
     * @param data
     * @return
     */
    public String MD5(String data) {
        String hashName = "md5";
        Object result = new SimpleHash(hashName, data, null, 2);
        return String.valueOf(result);
    }

    /**
     * 判断字符串是否为空
     *
     * @param str
     * @return
     */
    public boolean strIsEmpty(String str) {
        if (str == null || str.length() <= 0 || str == "null") {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 判断字符串是否为空
     *
     * @param str
     * @return
     */
//    public boolean strIsEmpty2(String str) {
//        if (str != null && str.length() != 0) {
//            return true;
//        } else {
//            return false;
//        }
//    }

    /**
     * 获取当前时间
     */
    public Date getNowTime() {

        return new Date();
    }
//    Date date = new Date();
//    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        format.setTimeZone(TimeZone.getTimeZone("GMT+8"));
//    String currentTime = format.format(date);
//    //将String类型转换成date类型,主要格式必须是yyyy-MM-dd HH:mm:ss相同
//        try {
//        Date newTime=format.parse(currentTime);
//        return newTime;
//    } catch (ParseException e) {
//        e.printStackTrace();
//    }
//        return null;

    /**
     * 分页查询,传入参数分别是,结果,总数量,一次数量
     */
    public Map getResultInfo(Object resultRecords, Integer totalNumber, Integer OneTimeTotal) {
        Map result = new HashMap<>(16);
        //总页数
        Integer resultPages = 0;
        if (totalNumber % OneTimeTotal > 0) {
            resultPages = totalNumber / OneTimeTotal + 1;
        } else {
            resultPages = totalNumber / OneTimeTotal;
        }

        result.put("result_records", resultRecords);
        result.put("result_pages", resultPages);
        result.put("result_counts", totalNumber);

        return result;
    }

    /**
     * 获得一个UUID
     *
     * @return String UUID
     */
    public String getUUID() {
        String uuid = UUID.randomUUID().toString();
        //去掉“-”符号
        return uuid.replaceAll("-", "");
    }

    /**
     * object转换成时间
     *
     * @param s
     * @return
     * @throws ParseException
     */
    public Date convertTimeType(Object s) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        format.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        Date date;
        try {
            date = format.parse((String) s);
        } catch (Exception e) {
            date = null;
        }
//         date=format.parse((String) s);
        return date;
    }

    /**
     * 生成指定长度的uuid
     */
    public String getCustomLengthUUID(Integer length) {
        return UUID.randomUUID().toString().replaceAll("-", "").substring(0, length);
    }

    /**
     * 自定义生成指定长度的uuid
     */
    public String getCustomPrefixAndLengthUUID(String str, Integer length) {
        return str + UUID.randomUUID().toString().replaceAll("-", "").substring(0, length);
    }

    /**
     * 如果有有空值返回false
     *
     * @param objects
     * @return
     */
    public boolean traversingMap(Object[] objects) {
        for (Object o : objects) {
            if (o == null) {
                return false;
            }
        }
        return true;
    }
}

4.3、JsonData

@ApiModel("接口实体类")
public class JsonData implements Serializable{

    /**
     * 状态码 0表示成功过,-1,-2,-3、、、为失败
     */
    @ApiModelProperty("状态码 0表示成功过,-1,-2,-3、、、为失败")
    private Integer code;

    /**
     * 业务数据
     */
    @ApiModelProperty("业务数据")
    private Object data;

    /**
     * 信息表示
     */
    @ApiModelProperty("信息表示")
    private String msg;

    public JsonData() {
    }

    public JsonData(Integer code, Object data, String msg) {
        this.code = code;
        this.data = data;
        this.msg = msg;
    }


    /**
     * 成功,不用返回数据
     *
     * @return
     */
    public static JsonData buildSuccess() {
        return new JsonData(0, null, null);
    }

    /**
     * 成功,返回数据
     *
     * @param data
     * @return
     */
    public static JsonData buildSuccess(Object data) {
        return new JsonData(0, data, null);
    }


    /**
     * 失败,固定状态码
     *
     * @param msg
     * @return
     */
    public static JsonData buildError(String msg) {
        return new JsonData(-1, null, msg);
    }


    /**
     * 失败,自定义错误码和信息
     *
     * @param code
     * @param msg
     * @return
     */
    public static JsonData buildError(Integer code, String msg) {
        return new JsonData(code, null, msg);
    }


    public Integer getCode() {
        return code;
    }

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

    public Object getData() {
        return data;
    }

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

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: Spring Boot是一种用于快速开发Java应用程序的框架,它提供了许多便捷的功能和特性,如自动配置、简化的部署等。MyBatis Plus是一个MyBatis的增强工具,可以更便捷地操作数据库。Shiro是一个强大的Java安全框架,可以提供身份认证、授权、会话管理等安全相关的功能。Redis是一个高性能的键值对存储系统,常用于缓存、分布式锁等场景。Template是Spring框架中用于渲染视图的模板引擎。 综上所述,Spring Boot与MyBatis Plus、ShiroRedis Template一起使用可以构建一个功能强大、高效、安全的应用程序。Spring Boot提供了便捷的开发环境和配置,使得整个项目的搭建和部署更加简单。MyBatis Plus提供了简洁的API,可以更方便地操作数据库,减少了开发人员的工作量。Shiro可以提供安全相关的功能,保护应用程序的数据和资源安全。Redis作为缓存可以提高应用程序的访问速度,使用分布式锁等功能可以保证数据一致性和并发控制。Template可以方便地渲染视图,使得前端页面开发更加简单。 总之,Spring Boot与MyBatis Plus、ShiroRedis Template的集成可以帮助开发人员快速构建功能完善、高效、安全的应用程序。它们各自的特性和功能相互配合,提供了一种快速开发的解决方案,为开发人员提供了更好的开发体验。 ### 回答2: Spring Boot是一个用于简化Spring应用程序开发的框架,它提供了自动配置和快速开发的特性。MyBatis Plus是基于MyBatis的增强工具,它简化了与数据库的交互,提供了很多便捷的方法和功能。Shiro是一个用于身份认证和授权的安全框架,它可以帮助我们实现用户身份认证、权限控制和会话管理的功能。Redis是一个开源的内存数据库,它提供了对数据的高速缓存和持久化存储的功能。Redis Template是Spring对Redis进行操作的一个封装工具,它提供了一系列的方法用于对Redis进行增删改查的操作。 使用Spring Boot可以简化项目的搭建和配置,通过自动配置可以省去很多繁琐的步骤。使用MyBatis Plus可以不用编写繁琐的SQL语句,只需定义实体类和Mapper接口即可完成数据库的操作。使用Shiro可以轻松实现用户的身份认证和权限控制,保障系统的安全性。使用Redis可以提高系统的性能,通过缓存机制减少数据库的访问次数。 结合起来使用,可以构建一个高效、安全和可靠的Web应用程序。Spring Boot提供了集成MyBatis Plus和Shiro的插件,可以方便地使用这两个框架Redis Template可以与Spring Boot的缓存框架一起使用,实现高速缓存。通过这些技术的使用,我们可以快速开发出功能完善的Web应用,提高开发效率和系统性能。 ### 回答3: SpringBootJava中一个开源的应用程序框架,它可以简化开发过程,提供了许多开箱即用的功能和库,使得开发者能够更快速地构建应用程序。 MyBatisPlus是一个基于MyBatis的增强工具,它提供了更方便、更强大的操作数据库的功能,大大简化了数据库操作的代码。 ShiroJava中一个功能强大且易于使用的安全框架,它提供了身份验证、授权、加密、会话管理等功能,可以帮助开发者实现应用程序的安全控制。 Redis是一个开源的内存数据库,它可以用作缓存、消息队列等,具有高性能、持久化、分布式等特点。 Template是Spring框架中的一个模板引擎,它支持HTML、XML、JSON等多种模板语言,用于将动态数据渲染到模板中,生成最终的静态页面或其他格式的文件。 综合以上技术,可以构建一个高效、安全、可靠的Web应用。使用SpringBoot可以简化项目的搭建和配置,MyBatisPlus可以方便地操作数据库,Shiro可以保护应用程序的安全,Redis可以提高系统的性能和可扩展性,Template可以方便地生成动态页面。 例如,我们可以使用SpringBoot搭建一个基于MyBatisPlus的后台管理系统,使用Shiro完成用户的身份验证和权限控制,使用Redis作为缓存存储用户的会话信息,使用Template将动态数据渲染到页面中。这样的系统具有良好的性能和安全性,提供了友好的用户界面和丰富的功能。 总之,SpringBoot、MyBatisPlus、ShiroRedis和Template等技术可以共同协作,帮助我们构建出高质量、高效率的应用程序。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李长渊哦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值