前后端分离整合shiro做权限控制

添加 shiro依赖

      <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.5.3</version>
        </dependency>

首先写 自定义Realm

public class UserRealm extends AuthorizingRealm {

    @Autowired(required = false)
    private SysUserService sysUserService;

    @Autowired(required = false)
    SysUserRoleMapper sysUserRoleMapper;

    // AuthorizationInfo代表了角色的权限信息集合 授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        System.out.println("执行了=>授权doGetAuthorizationInfo");
        // 授权
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        Subject subject = SecurityUtils.getSubject();
        // 获取当前user
        SysUser user = (SysUser) subject.getPrincipal();

        //
        Map<String,Object> map = new HashMap<>();
        map.put("userId",user.getId());
        List<SysRole> userRoleList = sysUserRoleMapper.selRoleByuserId(map);
        Set<String> permissionCode = new HashSet<>();
        Set<String> roleName = new HashSet<>();

        for (SysRole userRole : userRoleList) {
            roleName.add(userRole.getRoleName());
        }

        // 将 角色名称级权限的名称放进 info中 以供 shiroConfig 拦截
        info.setRoles(roleName);
        return info;
    }


    /**
     * 用户信息的认证
     *
     * 该方法主要执行以下操作:
     *      1、检查提交的进行认证的令牌信息
     *      2、根据令牌信息从数据源(通常为数据库)中获取用户信息
     *      3、对用户信息进行匹配验证。
     *      4、验证通过将返回一个封装了用户信息的AuthenticationInfo实例。
     *      5、验证失败则抛出AuthenticationException异常信息。
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了=>认证 doGetAuthorizationInfo");
        UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
        String username = userToken.getUsername();
        SysUser user = sysUserService.getUserByName(username);
        if (user == null){
            return null;
        }
        String paw1 = String.valueOf(userToken.getPassword());
        String paw2 = RSAUtil.privateKeyEncryption(paw1);
        String paw3 = DigestUtil.md5Hex(paw2);
        userToken.setPassword(paw3.toCharArray());
        // 密码认证
        return new SimpleAuthenticationInfo(user, user.getPassword(),this.getName());
    }
}

解读代码

继承 AuthorizingRealm 需要重写 两个方法,一个是 用户认证的方法,一个是 给用户 授权的方法
1、用户认证

    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("执行了=>认证 doGetAuthorizationInfo");
        UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
        String username = userToken.getUsername();
        SysUser user = sysUserService.getUserByName(username);
        if (user == null){
            return null;
        }
        // 用户输入的密码
        String paw1 = String.valueOf(userToken.getPassword());
        
        // 因为数据库存的是 MD5,多以对密码进行加密
        String paw3 = DigestUtil.md5Hex(paw2);
        userToken.setPassword(paw3.toCharArray());
        // 密码认证
        return new SimpleAuthenticationInfo(user, user.getPassword(),this.getName());
    }

通过 userToken 中的用户名 查询用户信息 检验用户密码等 判断用户信息是否正确。

2、将用户的权限角色信息 写进info

    // AuthorizationInfo代表了角色的权限信息集合 授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        System.out.println("执行了=>授权doGetAuthorizationInfo");
        // 授权
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        Subject subject = SecurityUtils.getSubject();
        // 获取当前user
        SysUser user = (SysUser) subject.getPrincipal();

        //
        Map<String,Object> map = new HashMap<>();
        map.put("userId",user.getId());
        List<SysRole> userRoleList = sysUserRoleMapper.selRoleByuserId(map);
        // 这个放 用户权限的CODE
        Set<String> permissionCode = new HashSet<>();
        // 这个放用户角色的名字
        Set<String> roleName = new HashSet<>();

        for (SysRole userRole : userRoleList) {
            roleName.add(userRole.getRoleName());
        }

        // 将 角色名称级权限的名称放进 info中 以供 shiroConfig 拦截
        info.setRoles(roleName);
        return info;
    }

3、在登陆的接口 需要加上这个,返回信息

  @GetMapping("/login")
    public String login(String username,String password,Model model){
        // 获取 一个用户
        Subject subject = SecurityUtils.getSubject();
        // 封装用户的登录数据
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);

        // 执行登录的方法 无异常就ok了
        try{
            subject.login(token);

        }catch (UnknownAccountException e){
            model.addAttribute("msg","用户名错误");
            return "login";
        }catch (IncorrectCredentialsException e) {//密码不存在
            model.addAttribute("msg","密码错误");
            return "login";
        }catch (LockedAccountException e){
            model.addAttribute("msg","账户被锁定");
            System.out.print("账户被锁定:"+e.getMessage());
            return "login";
        }
        // 当前用户信息被保存进Session
        return "index";
        // 登录成功 将当前用户保存在session中
    }

shiro 配置


@Configuration
public class ShiroConfig {
    // 1、创建realm对象 需要自定义类
    @Bean
    public UserRealm userRealm(){
        return new UserRealm();
    }

    /**
     * @Qualifier 我们可以消除需要注入哪个 bean 的问题
     * @param userRealm
     * @return
     */
    // 2、DefaultWebSecurityManager
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        // 关联userRealm
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    /**
     认证过滤器:
     anon:无需认证即可访问,游客身份。
     authc:必须认证(登录)才能访问。
     authcBasic:需要通过 httpBasic 认证。
     user:不一定已通过认证,只要是曾经被 Shiro 记住过登录状态的用户就可以正常发起请求,比如 rememberMe。

     授权过滤器:
     perms:必须拥有对某个资源的访问权限(授权)才能访问。
     role:必须拥有某个角色权限才能访问。
     port:请求的端口必须为指定值才可以访问。
     rest:请求必须是 RESTful,method 为 post、get、delete、put。
     ssl:必须是安全的 URL 请求,协议为 HTTPS。

     Filter Chain 定义说明:

     1、一个URL可以配置多个 Filter,使用逗号分隔
     2、当设置多个过滤器时,全部验证通过,才视为通过
     3、部分过滤器可指定参数,如 perms,roles
     *
     * bean.setLoginUrl: 请求被拦截 跳转拦截成功页面
     * setSuccessUrl:授权成功 跳转 通过的页面
     * setUnauthorizedUrl:授权失败 跳转 失败的页面
     *
     * @param defaultWebSecurityManager
     * @return
     */
    // 3、shiroFilterFactoryBean 拦截
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        // 设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);
        // 拦截器
        Map<String,String> filterMap = new HashMap<>();
        filterMap.put("/api/project/deleteProject","roles[administrator]");

        bean.setFilterChainDefinitionMap(filterMap);
        return bean;
    }

}

解读代码
1、创建realm 对象

  @Bean
    public UserRealm userRealm(){
        return new UserRealm();
    }

2、

    // 2、DefaultWebSecurityManager
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();

        // 关联userRealm
        securityManager.setRealm(userRealm);
        return securityManager;
    }

 /**
     认证过滤器:
     anon:无需认证即可访问,游客身份。
     authc:必须认证(登录)才能访问。
     authcBasic:需要通过 httpBasic 认证。
     user:不一定已通过认证,只要是曾经被 Shiro 记住过登录状态的用户就可以正常发起请求,比如 rememberMe。

     授权过滤器:
     perms:必须拥有对某个资源的访问权限(授权)才能访问。
     role:必须拥有某个角色权限才能访问。
     port:请求的端口必须为指定值才可以访问。
     rest:请求必须是 RESTful,method 为 post、get、delete、put。
     ssl:必须是安全的 URL 请求,协议为 HTTPS。

     Filter Chain 定义说明:

     1、一个URL可以配置多个 Filter,使用逗号分隔
     2、当设置多个过滤器时,全部验证通过,才视为通过
     3、部分过滤器可指定参数,如 perms,roles
     *
     * bean.setLoginUrl: 请求被拦截 跳转拦截成功页面
     * setSuccessUrl:授权成功 跳转 通过的页面
     * setUnauthorizedUrl:授权失败 跳转 失败的页面
     *
     * @param defaultWebSecurityManager
     * @return
     */
    // 3、shiroFilterFactoryBean 拦截
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        // 设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);
        // 拦截器
        Map<String,String> filterMap = new HashMap<>();
        filterMap.put("/api/project/deleteProject","roles[administrator]");

        bean.setFilterChainDefinitionMap(filterMap);
        return bean;
    }

此处配置的 拦截器 在 删除项目的接口 用户的角色需要是 administrator,否则会报401 无权限异常。用户角色在 Realm中 放进了 info 当然这个也可以 根据权限 来拦截请求

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值