shiro环境的简单搭建

spring boot简单搭建一个Shiro项目demo



前言

搭建一个shiro的项目demo,体验shiro的权限控制功能以及数据库表的简单设计。


使用步骤

1.数据库表的设计

主要分为三张主要表和两张关联表,分别是:
1)三张主表:用户表(user)、角色表(user)和权限表(permission)
2)两张关联表:用户角色表(user_role)和角色权限表(permission_role)

/**
* ①用户表包括:id、用户名和密码
* ②角色表包括:id和角色名
* ③权限表包括:id、权限名和路径
* ④用户角色关联表包括:用户id和角色id
* ⑤权限角色关联表包括:角色id和权限id
*/

/**
*对应实体类的设计
*/
@Data
public class User {
    private Integer uid;
    private String username;
    private String password;
    private Set<Role> roles = new HashSet<>();
}
@Data
public class Role {
    private Integer rid;
    private String rname;
    private Set<User> users = new HashSet<>();
    private Set<Permission> permissions = new HashSet<>();
}
@Data
public class Permission {
    private Integer pid;
    private String pname;
    private String url;
}

2.导入所需的依赖以及对应的配置

maven依赖文件如下:

    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.7.1</version>
    </dependency>

yml配置文件如下:

spring:
    #database-mysql
    datasource:
        url: jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8
        username: root
        password: root
        driver-class-name: com.mysql.cj.jdbc.Driver
        type: com.alibaba.druid.pool.DruidDataSource

#mybatis
mybatis:
	#实体类所放置的包位置
    type-aliases-package: com.shiro.model
    #映射文件所放置的文件位置
    mapper-locations: mappers/*.xml

3.创建配置类

(1)创建身份认证类AuthRealm.class

/**
 * Created by Jzs on 2021/6/27
 * 身份认证与权限分配
 */
public class AuthRealm extends AuthorizingRealm {
    @Autowired
    UserService userService;

    //认证登录
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        String username = usernamePasswordToken.getUsername();
        User user = userService.findByUsername(username);
        return new SimpleAuthenticationInfo(user,user.getPassword(),this.getClass().getName());
    }

    //用户授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //登录成功之后会把登录成功的用户对象放入session中
        User user = (User) principals.fromRealm(this.getClass().getName()).iterator().next();
        List<String> permissionList = new ArrayList<>();
        List<String> roleNameList = new ArrayList<>();
        //获取用户所有的角色
        Set<Role> roles = user.getRoles();
        if(CollectionUtils.isNotEmpty(roles)){
            //角色不为空就进行遍历获取角色的名字和权限
            roles.stream().forEach(r->{
                //设置角色名称
                roleNameList.add(r.getName());
                //设置权限
                Set<Permission> permissions = r.getPermissions();
                if (CollectionUtils.isNotEmpty(permissions)){
                    List<String> collect = permissions.stream().map(p -> p.getName()).collect(Collectors.toList());
                    permissionList.addAll(collect);
                }
            });
        }
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //将权限和角色名称分别放入SimpleAuthorizationInfo,shiro中进行过滤的时候才能根据角色和权限进行分配
        info.addStringPermissions(permissionList);
        info.addRoles(roleNameList);
        return info;
    }
}

此处用一个userService,其中的根据用户名获取用户信息的代码也粘贴一下,对实体类的嵌套查询还是

(2)创建密码校验类CredentialMatcher.class

/**
 * Created by Jzs on 2021/6/27
 * 自定义的密码校验规则,此处只是单纯的进行字符串对比
 * 可以使用自定义的密码加密和校验规则,如MD5等
 */
public class CredentialMatcher extends SimpleCredentialsMatcher {
    /**
     * @Description:
     * @Author: Jzs
     * @Date: 2021/6/27 22:19
     * @param token: 传入的用户信息
     * @param info: 数据库中查询出的用户信息
     * @return: boolean
     **/
    @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        //传入的信息获取到的密码,返回的是char型数组,需要转换成String类型
        String password = new String(usernamePasswordToken.getPassword());
        //从数据库查询到的数据的密码
        String dbPassword = (String) info.getCredentials();
        return this.equals(password,dbPassword);
    }
}

(3)创建shiro配置类ShiroConfiguration.class

/**
 * Created by Jzs on 2021/6/27
 * Shiro配置类
 */
@Configuration
public class ShiroConfiguration {

    //DefaultFilter
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") SecurityManager securityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(securityManager);

        //配置登录、登录成功、失败等跳转接口
        bean.setLoginUrl("/login");
        bean.setSuccessUrl("/index");
        bean.setUnauthorizedUrl("/unauthorized");

        //配置权限规则
        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        //index的路径使用authc的权限认证(DefaultFilter,每一个都是一个拦截类)
        filterChainDefinitionMap.put("/index","authc");//需要身份认证
        filterChainDefinitionMap.put("/","authc");//需要身份认证
        filterChainDefinitionMap.put("/login","anon");//忽略
        filterChainDefinitionMap.put("/loginUser","anon");//忽略
        //RolesAuthorizationFilter,具有这个角色的用户才可以访问
        filterChainDefinitionMap.put("/search","roles[user]");
        //PermissionsAuthorizationFilter,具有这个权限的用户才可以访问
        filterChainDefinitionMap.put("/edit","perms[edit]");
        //filterChainDefinitionMap.put("/druid/**","anon");//将druid的请求全部放开
        filterChainDefinitionMap.put("/**","user");//当前是否登录用户
        bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return bean;
    }

    @Bean("securityManager")
    public SecurityManager securityManager(@Qualifier("authRealm") AuthRealm authRealm){
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(authRealm);
        return manager;
    }

    //将自定义的密码校验器设置到authRealm中
    @Bean("authRealm")
    public AuthRealm authRealm(@Qualifier("credentialMatcher") CredentialMatcher credentialMatcher){
        AuthRealm authRealm = new AuthRealm();
        authRealm.setCredentialsMatcher(credentialMatcher);
        return authRealm;
    }
    
    //注入自定义的密码校验器
    @Bean("credentialMatcher")
    public CredentialMatcher credentialMatcher(){
        return new CredentialMatcher();
    }

    //shiro跟spring关联的配置
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("securityManager") SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(@Qualifier("securityManager") SecurityManager securityManager){
        //使用代理,默认是false=》true
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

4.测试controller

@Controller
public class TestController {

    //跳转到登录界面
    @GetMapping("/login")
    public String login(){
        return "login";
    }
    //跳转到首页
    @GetMapping(value = {"/index","/"})
    public String index(){
        System.out.println("======");
        return "index";
    }
    //用户登录请求
    @PostMapping("/loginUser")
    public String loginUser(@RequestParam("username") String username,
                            @RequestParam("password") String password,
                            HttpSession session){
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
            User user = (User) subject.getPrincipal();
            session.setAttribute("user",user);
            return "index";
        }catch (Exception e){
            return "login";
        }
    }
    //没有权限跳转接口
    @GetMapping("/unauthorized")
    public String unauthorized(){
        System.out.println("unauthorized====");
        return "unauthorized";
    }
    //用户注销,跳转到登录界面
    @GetMapping("/logout")
    public String logout(){
        System.out.println("logout====");
        Subject subject = SecurityUtils.getSubject();
        if(!Objects.isNull(subject)){
            //如果存在认证信息,进行注销
            subject.logout();
        }
        return "logout";
    }
    //搜索接口
    @GetMapping("/search")
    @ResponseBody
    public String search(){
        System.out.println("search====");
        return "search====";
    }
    //编辑接口
    @GetMapping("/edit")
    @ResponseBody
    public String edit(){
        System.out.println("edit====");
        return "edit====";
    }
}

总结

总的来说,简单的使用下来,shiro相对使用上会简单点,只需要维护shiroConfiguration类,在其中进行规则的编码即可进行权限的控制与分配。 而Spring Security相对来说使用上会比较麻烦一些。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Jz_Stu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值