基于Spring Boot整合shiro的基本使用

1.引入依赖

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

2.了解shiro的三大对象(转载至:https://blog.csdn.net/qq_41430393/article/details/87730198):

1.Subject(主体)

应用代码的直接交互对象就是Subject,也就是说Shiro对外的核心API就是Subject,Subject代表了当前“用户”,这个用户不是指具体的某一个人,可以说与当前应用交互的任何东西都是Subject,与Subject的所有交互都会委托给SecurityManager来执行,可以理解为Subject只是一个充当门面的,真正的幕后老大是SecurityManager,SecurityManager才是实际的执行者。

2.SecurityManager(安全管理器)

所有与安全有关的操作都会与SecurityManager进行交互,并且SecurityManager管理者所有的Subject,可以看出它才是Shiro的核心,它负责与Shiro的其他组件进行交互,它相当于SpringMvc中的dispatcherServlet(前端控制器)的角色。

3.Realm

Shiro从Realm获取安全数据(用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法,也需要从Realm获取用户的角色权限来判断用户是否能进行一系列操作。可以把Realm看作DataSource数据源.

3.配置shiroConfig类以及shiroReaml类

shiroConfig类(将三大对象联系起来,配置需要拦截的页面):

@Configuration //交由spring管理
public class shiroConfig {
    //自底向上创建,并绑定

    //ShiroFilterFactoryBean,第三步
    @Bean
    public ShiroFilterFactoryBean getFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //关联安全管理器
        bean.setSecurityManager(securityManager);

        //添加shiro的内置过滤器
        /*
            anon:无需认证就可以访问
            authc:必须认证才能访问 验证密码和用户
            user:必须拥有 记住我 功能才能用
            perms:拥有对某个资源的权限才能访问
            role:拥有某个角色权限才能访问
         */
        //使用map添加相应页面的过滤
        Map<String, String> filterMap=new LinkedHashMap<>();

        //因为是链式过滤,所以得先过滤范围小的
        //不仅需要登陆还得拥有权限才可访问
        //表示数据库中user表中的字段perm为user:update才表示有这个权限访问改路径
        filterMap.put("/user/update","perms[user:update]");
        filterMap.put("/user/add","perms[user:add]");

        //需要登陆即可访问的页面
        filterMap.put("/user/*","authc");

        //设置未登录时,进入需要权限的页面时,跳转的登陆页面
        bean.setLoginUrl("/toLogin");

        //设置权限不足时跳转的页面
        bean.setUnauthorizedUrl("/noAuth");
        
        bean.setFilterChainDefinitionMap(filterMap);

        return bean;
    }

    //DefaultWebSecurityManager,第二步
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("getRealm") shiroRealm shiroRealm){
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
        //关联realm
        securityManager.setRealm(shiroRealm);
        return securityManager;
    }


    //创建realm对象,第一步@Bean交由spring管理
    @Bean
    public shiroRealm getRealm(){
        return new shiroRealm();
    }

}

shiroReaml类(用于实现用户认证和授权的操作)

//授权和认证都会经过此类
public class shiroRealm extends AuthorizingRealm {
    @Autowired
    userService service;

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        Subject subject = SecurityUtils.getSubject();//获取当前用户
        user currentUser = (user) subject.getPrincipal();//从当前用户中取出Principal(认证时已存储了user)
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();//是AuthorizationInfo的实现类
        info.addStringPermission(currentUser.getPerm());//根据数据库中的perm字段添加相应的权限
        return info;
    }


    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        user user = service.findByUsername(token.getUsername());
        //用户名校验,查看是否存在用户名
        if(user==null){
            return null;//返回null表示账号不存在,会抛出异常UnknownAccountException
        }
        //密码校验,shiro自带检验
        //若是密码错误会抛出异常IncorrectCredentialsException
        return new SimpleAuthenticationInfo(user,user.getPassword(),"");
        //第一个参数是principal作用是传递信息的,如认证完后可以将数据库中查询的user放进去,
        //供授权时,给相应的用户添加相应数据库中的权限
    }
}

4.配置Controller的实现

@Controller
public class myController {

    @RequestMapping({"/","/index"})
    public String index(){
        return "index";
    }

    @RequestMapping("/user/add")
    public String add(){
        return "user/add";
    }

    @RequestMapping("/user/update")
    public String update(){
        return "user/update";
    }

    @RequestMapping("/toLogin")
    public String toLogin(){
        return "login";
    }

    @RequestMapping("/login")
    public String login(String username, String password, Model model){
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        try {
            subject.login(token);// 该操作会将token转至手写的realm类中的doGetAuthenticationInfo方法中认证登陆
            return "index";
        }catch (UnknownAccountException e){//用户名不存在
            model.addAttribute("msg","用户名不存在");
            return "login";
        }catch (IncorrectCredentialsException e){//密码不存在
            model.addAttribute("msg","密码错误");
            return "login";
        }

    }

    @RequestMapping("/noAuth")
    @ResponseBody
    public String noAuth(){
        return "权限不足!";
    }

    @RequestMapping("/logout")
    @ResponseBody
    public String logout(){
        SecurityUtils.getSubject().logout();//注销
        return "注销成功!";
    }
}

5.shiro整合thymeleaf

a.引入整合的依赖:

        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

b.在shiroConfig类中添加ShiroDialect类

    @Bean
    public ShiroDialect getDialect(){
        return new ShiroDialect();
    }

c.在前端页面引入thymeleaf整合shiro的命名空间

<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">

d.将登陆成功的用户保存至shiro的session(与HttpSession不同)

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        user user = service.findByUsername(token.getUsername());
        //用户名校验,查看是否存在用户名
        if(user==null){
            return null;//返回null表示账号不存在,会抛出异常UnknownAccountException
        }
        //登陆成功将用户放进session
        Subject currentSubject = SecurityUtils.getSubject();
        currentSubject.getSession().setAttribute("loginUser",user);
        //密码校验,shiro自带检验
        //若是密码错误会抛出异常IncorrectCredentialsException
        return new SimpleAuthenticationInfo(user,user.getPassword(),"");
        //第一个参数是principal作用是传递信息的,如认证完后可以将数据库中查询的user放进去,
        //供授权时,给相应的用户添加相应数据库中的权限
    }

e.前端页面的逻辑实现

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
<h1>首页</h1>
<hr>
<div th:if="${session.loginUser==null}">
<a th:href="@{/toLogin}">登陆</a>
</div>

<div th:if="${session.loginUser!=null}">
<a th:href="@{/logout}">点我注销</a>
    <div th:text="当前用户为+':'+${session.loginUser.Username}"></div>
</div>

<div shiro:hasPermission="user:add">
<a th:href="@{/user/add}">add</a>
</div>

<div shiro:hasPermission="user:update">
<a th:href="@{/user/update}">update</a>
</div>

</body>
</html>
原文地址:https://www.cnblogs.com/shouyaya/p/13454687.html