Spring Boot整合shiro

1、shiro是什么

用官方的话说Apache Shiro是一个功能强大且易于使用的Java安全框架,它为开发人员提供了一种直观而全面的解决方案,用于身份验证,授权,加密和会话管理。
首先我们先看官方给出的Shiro外部结构图,看shiro是如何完成工作的:


官方结构图.png

shiro主要有三大功能模块:

Subject:

应用代码直接交互的对象Subject,也就是说Shiro的对外API核心就是Subject,代表了当前的用户,也不一定是一个具体的人,也当前应用交互的任何东西都是Subject,与Subject的所有交互都会委托给SecurityManager,Subject其实就是一个门面,SecurityManager才是实际的执行者

SecurityManager:

安全管理器,即所有与安全有关的操作都会与SecurityManager交互,并且它管理着所有的Sbject,它才是Shiro的核心,负责与Shiro的其他组件进行交互

Realms:

Shiro从Realm获取安全数据(用户,角色,权限),就是说SecurityManager要验证用户身份,它就需要从Realm获取相应的用户进行比较,来确定用户的身份是否合法,也需要用Realm得到用户相应的角色、权限,进行验证用户的操作是否能够进行

2、集成Shiro

1、导入jar包

在pom文件中添加shiro依赖

 
        
            org.apache.shiro
            shiro-spring
            1.6.0
        
2、编写配置类

创建ShiroConfig类

@Configuration
public class ShiroConfig {
    //ShiroFilterFactoryBean
    //DefaultWebSecurityManager
    //创建realm对象
}

这三个就对应我们刚刚说的三个模块,然后就开始配置这三个对象,我们先从realm开始配置,realm对象需要我们自己先定义,我们先新建一个ShiroRealm类然后继承 AuthorizingRealm,然后重写他的方法,一个授权,一个认证

//自定义realm 需要继承 AuthorizingRealm
public class ShiroRealm extends AuthorizingRealm {
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        return null;
    }
}

然后返回ShiroConfig去创建realm对象

@Configuration
public class ShiroConfig {
    //ShiroFilterFactoryBean
    //DefaultWebSecurityManager

    //创建realm对象
    @Bean
    public ShiroRealm shiroRealm(){
        return new ShiroRealm();
    }
}

这样我们写的对象就被spring托管了,接下来我们写DefaultWebSecurityManager,因为DefaultWebSecurityManager需要Realm

@Configuration
public class ShiroConfig {
    //ShiroFilterFactoryBean
    
    //DefaultWebSecurityManager
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("shiroRealm") ShiroRealm shiroRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联realm
        securityManager.setRealm(shiroRealm);
        return securityManager;
    }

    //创建realm对象
    @Bean
    public ShiroRealm shiroRealm(){
        return new ShiroRealm();
    }
}

接下来写ShiroFilterFactoryBean

@Configuration
public class ShiroConfig {
    //ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager manager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(manager);
        return bean;
    }
    //DefaultWebSecurityManager
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("shiroRealm") ShiroRealm shiroRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联realm
        securityManager.setRealm(shiroRealm);
        return securityManager;
    }

    //创建realm对象
    @Bean
    public ShiroRealm shiroRealm(){
        return new ShiroRealm();
    }
}

3、设置过滤器

前面我们已经把shiro初步集成了,接下来就需要配置过滤器

//ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager manager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(manager);
        /*
            添加shiro的内置过滤器
            anon:  无需认证就可访问
            authc: 必须认证才能访问
            user:  必须拥有 记住我功能才可访问
            perms: 拥有对某个资源的权限才能访问
            role:  拥有某个角色权限才能访问
         */
        MapfilterMap = new HashMap<>();
        filterMap.put("/version/*","authc");
        filterMap.put("/api/*","anon");
        bean.setFilterChainDefinitionMap(filterMap);
        //设置登录请求
        bean.setLoginUrl("/home/toLogin");
        return bean;
    }

这样配置的意思是路径/version/是需要认证才可访问,/api/无需认证就可访问,然后没认证的返回登录页面去认证,接下来试试,在网页中输入网址


image.png

因为没认证过直接跳转到了登录页面,这样就算成功了


image.png

4、实现登录功能

现在我们已经成功拦截了我们设置的路径,然后就要实现登录通过认证,首先写一个用户实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Admin {
    private Integer id;
    //用户名称
    private String name;
    //登录帐号
    private String username;
    //登录密码
    private String password;
    //创建时间
    private Date createTime;
}

然后写登录方法

    @PostMapping("login")
    public String login(String adminName, String password, Model model) {
        Admin admin = adminMapper.searchByAccount(adminName);
        if (admin == null){
            model.addAttribute("error","帐号密码错误");
            return "home/login";
        }
        if (!admin.getPassword().equals(password)){
            model.addAttribute("error","帐号密码错误");
            return "home/login";
        }
        //获取当前用户
        Subject subject = SecurityUtils.getSubject();
        //封装用户的登录数据
        UsernamePasswordToken token = new UsernamePasswordToken(admin.getUsername(),admin.getPassword());
        try {
            subject.login(token);  //执行登录方法
            return "redirect:/version/list";
        } catch (Exception e){ 
            e.printStackTrace();
        }
        return "home/login";
    }

这样我们在请求登录请求后他会去执行doGetAuthenticationInfo方法做认证操作,那我们就去里面写认证操作

 //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String adminName = token.getUsername();
        if (adminName != null && !adminName.equals("")){
            Admin admin = adminMapper.searchByAccount(adminName);
            if (admin != null){
                return new SimpleAuthenticationInfo(admin.getUsername(),admin.getPassword(),getName());
            }
        }
        return null;
    }

如果查询数据库没有该用户return null后会抛出一个UnknownAccountException异常,成功返回AuthenticationInfo的实现类
这样我们就实现了登录认证功能

你可能感兴趣的:(Spring Boot整合shiro)