SpringBoot对于Shiro的使用

写在前面:引用博客地址

在springBoot中探究shhiro的认证授权过程 

  •  第一步:

 自定义Reaml,作用在于对于用户的认证和授权。此处需要链接数据库获取项目用户的信息进行校验,编写自己的验证逻辑。

package com.howie.shiro.shiro;

import com.howie.shiro.mapper.UserMapper;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
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 org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.Set;

@Component
public class CustomRealm extends AuthorizingRealm {
    private final UserMapper userMapper;

    @Autowired
    public CustomRealm(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    /**
     * 获取身份验证信息
     * Shiro中,最终是通过 Realm 来获取应用程序中的用户、角色及权限信息的。
     *
     * @param authenticationToken 用户身份信息 token
     * @return 返回封装了用户信息的 AuthenticationInfo 实例
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("————身份认证方法————");
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        // 从数据库获取对应用户名密码的用户
//      String password = userMapper.getPassword(token.getUsername());
//      伪装从数据库去已经取出数据,进行登录操作!
        String password = "123456";
        if (null == password) {
            throw new AccountException("用户名不正确");
        } else if (!password.equals(new String((char[]) token.getCredentials()))) {
            throw new AccountException("密码不正确");
        }
        return new SimpleAuthenticationInfo(token.getPrincipal(), password, getName());
    }

    /**
     * 获取授权信息
     *
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("————权限认证————");
        String username = (String) SecurityUtils.getSubject().getPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //获得该用户角色
//        String role = userMapper.getRole(username);
        //伪装数据库的查询结果
        String role = "admin";
        Set<String> set = new HashSet<>();
        //需要将 role 封装到 Set 作为 info.setRoles() 的参数
        set.add(role);
        //设置该用户拥有的角色
        info.setRoles(set);
        return info;
    }
}
  • 第二步

 自定义一个ShiroConfig的配置类,把securityManager在携带自定义的Realm的前提下注入到spring容器中

   /**
     * 注入 securityManager
     */
    @Bean
    public SecurityManager securityManager(CustomRealm customRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realm.
        securityManager.setRealm(customRealm);
        return securityManager;
    }

把securityManager交给ShiroFilterFactoryBean管理,作为参数传入。此处实际是初始化 ShiroFilterFactoryBean,在此Bean中实际的作用就是配置自己的请求拦截,然后返回给Spring容器就行了,此后的请求都会经过拦截器!

  • 第三步 
    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // setLoginUrl 如果不设置值,默认会自动寻找Web工程根目录下的"/login.jsp"页面 或                       "/login" 映射
        shiroFilterFactoryBean.setLoginUrl("/notLogin");
        // 设置无权限时跳转的 url;
        shiroFilterFactoryBean.setUnauthorizedUrl("/notRole");

        // 设置拦截器
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        //游客,开发权限
        filterChainDefinitionMap.put("/guest/**", "anon");
        //用户,需要角色权限 “user”
        filterChainDefinitionMap.put("/user/**", "roles[user]");
        //管理员,需要角色权限 “admin”
        filterChainDefinitionMap.put("/admin/**", "roles[admin]");
        //开放登陆接口
        filterChainDefinitionMap.put("/login", "anon");
        //其余接口一律拦截
        //主要这行代码必须放在所有权限设置的最后,不然会导致所有 url 都被拦截
        filterChainDefinitionMap.put("/**", "authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        System.out.println("Shiro拦截器工厂类注入成功");
        return shiroFilterFactoryBean;
    }
  • 第四步: 

 到此结束了一个简单的shirio配置所有了,后面的使用就是正常的编写redtFul接口了。

查看项目启动加载过程

  •  首先是绑定自定义Realm的SecurityManager的注入
  • 然后是在Shiro工厂注入ShrioManager,完成拦截器的初始化功能

 项目接口测试

  •  测试未登入状态可以访问的资源
         //游客,开发权限
        filterChainDefinitionMap.put("/guest/**", "anon");
  •  
// setLoginUrl 如果不设置值,默认会自动寻找Web工程根目录下的"/login.jsp"页面 或 "/login" 映射
        shiroFilterFactoryBean.setLoginUrl("/notLogin");
  • 测试发现请求所有/guest/*的接口都是没有拦截的(无需认证和授权,也不会触发任何配置类信息) 
  • 把游客权限改为"authc",再次请求游客信息发现跳转到了"/notLogin"接口
  • 理解一个概念

 "anon"是不需要任何认证和授权就可以的,但是"authc"是需要登录的。

"user"和"authc"也是不同的:当应用开启rememberMe时,用户下次的请求可以是个user,但是绝对不会是个authc(也就是说需要重新进行认证的),当"user"请求任何资源的时候不会再进行认证的校验,直接进行授权的校验。

 // 设置无权限时跳转的 url;
        shiroFilterFactoryBean.setUnauthorizedUrl("/notRole");
  • 当已经认证的请求进入程序的时候,出现访问资源校验没有权限的时候,会挑战到"/notRole"接口下 

 需要登录的情况下使用Shiro

  • 在登录的接口中需要进行subject的注入生成一个token

 

@RequestMapping(value = "/login", method = RequestMethod.POST)
    public ResultMap login(String username, String password) {
        // 从SecurityUtils里边创建一个 subject
        Subject subject = SecurityUtils.getSubject();
        // 在认证提交前准备 token(令牌)
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        // 执行认证登陆
        subject.login(token);
        //根据权限,指定返回数据
//        String role = userMapper.getRole(username);
        String role ="admin";
        if ("user".equals(role)) {
            return resultMap.success().message("欢迎登陆");
        }
        if ("admin".equals(role)) {
            return resultMap.success().message("欢迎来到管理员页面");
        }
        return resultMap.fail().message("权限错误!");
    }
  • 在完成subject.login(token)后会执行ShiroConfig配置类中的doGetAuthenticationInfo(args)重写的方法中(用于身份的认证)
  • 完成后跳回subject.login(toekn)继续执行完成所有业务代码
  • 在往后的请求中都会直接先走授权(每次请求会携带一个cookie认证通过后的返回)
  • 在没有权限时候会被拦截器拦截直接跳回到ShiroConfig配置中的"/notRole"
  • 结束

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值