使用SpringBoot2.0搭建企业级应用开发框架(七)集成Shiro

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mxxrgxg/article/details/81358536
  • 准备

首先创建用户权限表

//用户表
CREATE TABLE `sys_user` (
  `id` varchar(32) NOT NULL COMMENT 'id',
  `username` varchar(64) DEFAULT NULL COMMENT '用户名',
  `password` varchar(64) DEFAULT NULL COMMENT '密码',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户表';
INSERT INTO `demo`.`sys_user` (`id`, `username`, `password`) VALUES ('1', 'admin', '123456');

//角色表
CREATE TABLE `sys_role` (
  `id` varchar(32) NOT NULL COMMENT 'id',
  `role_name` varchar(32) DEFAULT NULL COMMENT '角色名称',
  `role_desc` varchar(32) DEFAULT NULL COMMENT '描述',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='角色表';
INSERT INTO `demo`.`sys_role` (`id`, `role_name`, `role_desc`) VALUES ('1', 'ROLE_ADMIN', '管理员');

//用户-角色表
CREATE TABLE `sys_user_role` (
  `id` varchar(32) NOT NULL COMMENT 'id',
  `user_id` varchar(32) DEFAULT NULL COMMENT '用户id',
  `role_id` varchar(32) DEFAULT NULL COMMENT '角色id',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户角色表';
INSERT INTO `demo`.`sys_user_role` (`id`, `user_id`, `role_id`) VALUES ('1', '1', '1');

 然后用之前说的generator生成实体

  • 集成

首先添加Shiro的依赖

<!--shiro-->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring-boot-web-starter</artifactId>
    <version>1.4.0</version>
</dependency>

然后创建自定义Realm

public class MyRealm extends AuthorizingRealm {

    @Autowired
    private SysUserMapper sysUserMapper;

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
            throws AuthenticationException {
        //获得当前用户的用户名
        String username = (String) authenticationToken.getPrincipal();

        //从数据库中根据用户名查找用户
        SysUser user = sysUserMapper.findByUserName(username);
        if (user == null) {
            log.info("没有用户名为{}的用户",username);
            throw new UnknownAccountException("没有在本系统中找到对应的用户信息");
        }

        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(),getName());
        return info;
    }

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //从凭证中获得用户名
        String username = (String) SecurityUtils.getSubject().getPrincipal();
        //根据用户名查询用户对象
        SysUser user = sysUserMapper.findByUserName(username);
        //查询用户拥有的角色
        List<SysRole> roleList = user.getRoles();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        log.debug("用户{}拥有以下角色:");
        for (SysRole role : roleList) {
            //赋予用户角色
            info.addStringPermission(role.getRoleName());
        }
        return info;
    }
}

创建config类

@Configuration
public class ShiroConfiguration {

    @Bean
    public MyRealm realm(){
        return new MyRealm();
    }

    //使用shiro-spring-boot-starter 1.4时,返回类型是SecurityManager会报错,直接引用shiro-spring则不报错
    @Bean
    public DefaultWebSecurityManager securityManager(MyRealm realm){
        DefaultWebSecurityManager securityManager =  new DefaultWebSecurityManager();
        securityManager.setRealm(realm);
        return securityManager;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean  = new ShiroFilterFactoryBean();
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面
        shiroFilterFactoryBean.setLoginUrl("/login");
        // 登录成功后要跳转的链接
        shiroFilterFactoryBean.setSuccessUrl("/index");
        //未授权界面;
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

        //拦截器.
        Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
        //配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了
        filterChainDefinitionMap.put("/logout", "logout");
        // 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 :这是一个坑呢,一不小心代码就不好使了;
        // authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/login.html", "anon");
        filterChainDefinitionMap.put("/**", "authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }
}

创建登录测试

@Controller
public class ShiroController {

    @GetMapping("/login")
    public String login(){
        return "redirect:login.html";
    }

    @PostMapping("/login")
    public String login(String username, String password){
        Subject user = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        String returnUrl = "redirect:index.html";
        String a = "1";
        try {
            //shiro帮我们匹配密码什么的,我们只需要把东西传给它,它会根据我们在UserRealm里认证方法设置的来验证
            user.login(token);
        } catch (UnknownAccountException e) {
            //账号不存在
            returnUrl = "redirect:login.html?error=0";
            //账号不存在和下面密码错误一般都合并为一个账号或密码错误,这样可以增加暴力破解难度
        } catch (DisabledAccountException e) {
            //账号未启用
            returnUrl = "redirect:login.html?error=1";
        } catch (IncorrectCredentialsException e) {
            //密码错误
            returnUrl = "redirect:login.html?error=2";
        } catch (Throwable e) {
            //未知错误
            returnUrl = "redirect:login.html?error=3";
        } finally {
            return returnUrl;
        }
    }
}

login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title1</title>
</head>
<body>
    <form method="post" action="/login">
        用户名:<input name="username" /><br />
        密码:<input name="password" /><br />
        <input type="submit" value="登录" />
    </form>
</body>
</html>

集成中的坑

1、config类中的securityManager()返回类型

如果jar包用spring-shiro,则返回SecurityManager即可,如果用shiro-spring-boot-starter 1.4,则需要返回DefaultWebSecurityManager,否则会报错

2、多环境配置

多环境配置中需要手动定义resuources目录下加载的文件,所以不要忘记将html加入进去

3、页面跳转问题

如果使用return "xx.html"方式的话,在登陆时,由于提交表单是post,而访问xx.html是get方法,所以会报错,需要使用redirect或者forward

猜你喜欢

转载自blog.csdn.net/mxxrgxg/article/details/81358536