第6章 Shiro高级及SaaS-HRM的认证授权

1 Shiro在SpringBoot工程的应用 Apache Shiro是一个功能强大、灵活的,开源的安全框架。它可以干净利落地处理身份验证、授权、企业会话管理 和加密。越来越多的企业使用Shiro作为项目的安全框架,保证项目的平稳运行。 在之前的讲解中只是单独的使用shiro,方便学员对shiro有一个直观且清晰的认知,我们今天就来看一下shiro在 springBoot工程中如何使用以及其他特性

1.1 案例说明 使用springBoot构建应用程序,整合shiro框架完成用户认证与授权。

1.1.1 数据库表

微服务认证中心Spring Cloud 微服务shiro认证_java

2.2 应用场景分析 在分布式系统或者微服务架构下,都是通过统一的认证中心进行用户认证。如果使用默认会话管理,用户信息只会 保存到一台服务器上。那么其他服务就需要进行会话的同步。

微服务认证中心Spring Cloud 微服务shiro认证_sass_02

导入Shir项目工程进行测试

@RequestMapping(value="/login")
    public String login(String username,String password) {
	    //构造登录令牌
        try {

            /**
             * 密码加密:
             *     shiro提供的md5加密
             *     Md5Hash:
             *      参数一:加密的内容
             *              111111   --- abcd
             *      参数二:盐(加密的混淆字符串)(用户登录的用户名)
             *              111111+混淆字符串
             *      参数三:加密次数
             *
             */
            password = new Md5Hash(password,username,3).toString();

            UsernamePasswordToken upToken = new UsernamePasswordToken(username,password);
            //1.获取subject
            Subject subject = SecurityUtils.getSubject();

            //获取session
            String sid = (String) subject.getSession().getId();

            //2.调用subject进行登录
            subject.login(upToken);
            return "登录成功";
        }catch (Exception e) {
            return "用户名或密码错误";
        }
    }

授权的方法:

/**
     * 授权方法
     *      操作的时候,判断用户是否具有响应的权限
     *          先认证 -- 安全数据
     *          再授权 -- 根据安全数据获取用户具有的所有操作权限
     *
     *
     */
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //1.获取已认证的用户数据
        User user = (User) principalCollection.getPrimaryPrincipal();//得到唯一的安全数据
        //2.根据用户数据获取用户的权限信息(所有角色,所有权限)
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        Set<String> roles = new HashSet<>();//所有角色
        Set<String> perms = new HashSet<>();//所有权限
        for (Role role : user.getRoles()) {
            roles.add(role.getName());
            for (Permission perm : role.getPermissions()) {
                perms.add(perm.getCode());
            }
        }
        info.setStringPermissions(perms);
        info.setRoles(roles);
        return info;
    }

认证的方法

/**
     * 认证方法
     *  参数:传递的用户名密码
     */
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //1.获取登录的用户名密码(token)
        UsernamePasswordToken upToken = (UsernamePasswordToken) authenticationToken;
        String username = upToken.getUsername();
        String password = new String( upToken.getPassword());
        //2.根据用户名查询数据库
        User user = userService.findByName(username);
        //3.判断用户是否存在或者密码是否一致
        if(user != null && user.getPassword().equals(password)) {
            //4.如果一致返回安全数据
            //构造方法:安全数据,密码,realm域名
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),this.getName());
            return info;
        }
        //5.不一致,返回null(抛出异常)
        return null;
    }

进行项目整合测试:

微服务认证中心Spring Cloud 微服务shiro认证_微服务认证中心Spring Cloud_03

微服务认证中心Spring Cloud 微服务shiro认证_sass_04

加盐处理登录成功

微服务认证中心Spring Cloud 微服务shiro认证_微服务认证中心Spring Cloud_05

通过过滤器可以判断是否具有角色和角色所对应的权限,讲Shiro信息存储到Redis当中

微服务认证中心Spring Cloud 微服务shiro认证_redis_06

Shiro认证和JWT认证得区别

微服务认证中心Spring Cloud 微服务shiro认证_redis_07

改造后端得登录逻辑

/**
     * 用户登录
     *  1.通过service根据mobile查询用户
     *  2.比较password
     *  3.生成jwt信息
     *
     */
    @RequestMapping(value="/login",method = RequestMethod.POST)
    public Result login(@RequestBody Map<String,String> loginMap) {
        String mobile = loginMap.get("mobile");
        String password = loginMap.get("password");
        try {
            //1.构造登录令牌 UsernamePasswordToken
            //加密密码
            password = new Md5Hash(password,mobile,3).toString();  //1.密码,盐,加密次数
            UsernamePasswordToken upToken = new UsernamePasswordToken(mobile,password);
            //2.获取subject
            Subject subject = SecurityUtils.getSubject();
            //3.调用login方法,进入realm完成认证
            subject.login(upToken);
            //4.获取sessionId
            String sessionId = (String)subject.getSession().getId();
            //5.构造返回结果
            return new Result(ResultCode.SUCCESS,sessionId);
        }catch (Exception e) {
            return new Result(ResultCode.MOBILEORPASSWORDERROR);
        }

系统认证得方法代码接口部分

//认证方法
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //1.获取用户的手机号和密码
        UsernamePasswordToken upToken = (UsernamePasswordToken) authenticationToken;
        String mobile = upToken.getUsername();
        String password = new String( upToken.getPassword());
        //2.根据手机号查询用户
        User user = userService.findByMobile(mobile);
        //3.判断用户是否存在,用户密码是否和输入密码一致
        if(user != null && user.getPassword().equals(password)) {
            //4.构造安全数据并返回(安全数据:用户基本数据,权限信息 profileResult)
            ProfileResult result = null;
            if("user".equals(user.getLevel())) {
                result = new ProfileResult(user);
            }else {
                Map map = new HashMap();
                if("coAdmin".equals(user.getLevel())) {
                    map.put("enVisible","1");
                }
                List<Permission> list = permissionService.findAll(map);
                result = new ProfileResult(user,list);
            }
            //构造方法:安全数据,密码,realm域名
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(result,user.getPassword(),this.getName());
            return info;
        }
        //返回null,会抛出异常,标识用户名和密码不匹配
        return null;
    }

授权接口认证:

//授权方法
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //1.获取安全数据
        ProfileResult result = (ProfileResult)principalCollection.getPrimaryPrincipal();
        //2.获取权限信息
        Set<String> apisPerms = (Set<String>)result.getRoles().get("apis");
        //3.构造权限数据,返回值
        SimpleAuthorizationInfo info = new  SimpleAuthorizationInfo();
        info.setStringPermissions(apisPerms);
        return info;
    }

    //认证方法
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        return null;
    }

覆写Shiro得配置信息:

/**
     * 1.redis的控制器,操作redis
     */
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host);
        redisManager.setPort(port);
        return redisManager;
    }

    /**
     * 2.sessionDao
     */
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO sessionDAO = new RedisSessionDAO();
        sessionDAO.setRedisManager(redisManager());
        return sessionDAO;
    }

    /**
     * 3.会话管理器
     */
    public DefaultWebSessionManager sessionManager() {
        CustomSessionManager sessionManager = new CustomSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());
        //禁用cookie
        sessionManager.setSessionIdCookieEnabled(false);
        //禁用url重写   url;jsessionid=id
        sessionManager.setSessionIdUrlRewritingEnabled(false);
        return sessionManager;
    }

测试认证:

微服务认证中心Spring Cloud 微服务shiro认证_微服务认证中心Spring Cloud_08

微服务认证中心Spring Cloud 微服务shiro认证_sass_09

测试授权:

微服务认证中心Spring Cloud 微服务shiro认证_sass_10

登录成功

微服务认证中心Spring Cloud 微服务shiro认证_java_11

查询全部企业信息

微服务认证中心Spring Cloud 微服务shiro认证_微服务认证中心Spring Cloud_12