springboot整合shiro实现登录认证授权以及退出

springboot整合shiro实现登录认证授权以及退出

shrio简介

shiro是一个权限管理框架,用于实现登录认证以及授权。

环境准备

创建一个springboot的项目

这里我创建的是最简单的web项目(只勾选了web下的spring web选项),没有导入,mybatis等等这些依赖。这些依赖,后面再慢慢导入,

导入相关的依赖

springboot整合shiro的依赖
<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<version>1.5.3</version>
		</dependency>
thymleaf的依赖
<!--thymeleaf模板-->
		<dependency>
			<groupId>org.thymeleaf</groupId>
			<artifactId>thymeleaf-spring5</artifactId>
		</dependency>
		<dependency>
			<groupId>org.thymeleaf.extras</groupId>
			<artifactId>thymeleaf-extras-java8time</artifactId>
		</dependency>

创建首页

在templates目录下创建一个首页index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>首页</h1>
</body>
</html>

创建controller

package com.dlj.shriospringboot.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @author lijiedong
 * @version 1.0
 * @date 2020/12/3 15:11
 */
@Controller
public class IndexController {
    @RequestMapping("/")
    public String index(){
        System.out.println("kk");
        return "index";
    }

}

先把项目运行起来,下面就正式开始集成。
在这里插入图片描述

shiro重要概念

shiro中有一些重要概念:

  • subject 指当前用户
  • securityManager 安全管理器,类似于springmvc中的前端控制器
  • Realm 数据源用于获取数据进行验证

拦截器拦截请求

创建配置类

shiro校验请求是通过拦截器来实现的。在web项目里,首先创建一个shiro的配置类。
创建config的包,在下面创建一个类UserRealm,它继承AuthorizingRealm类
在这里插入图片描述
它要实现两个方法

public class UserRealm extends AuthorizingRealm {

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    // 授权的时候执行
        return null;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    // 认证的时候执行
        return null;
    }
}

然后创建ShiroConfig类,这个是shiro具体的配置类。
通过过ShiroFiletrFactoryBean创建拦截器。它需要先创建UserRealm,然后再创建securityManager

@Configuration
public class ShiroConfig {
    //ShiroFiletrFactoryBean
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        // 设置安全管理器
        bean.setSecurityManager(defaultWebSecurityManager);
        // 添加shiro的内置过滤器
        /**
         * anon:无需认证就可以访问
         * authc:必须认证了才能访问
         * user:必须拥有记住我功能才能用
         * perms:拥有对某个资源的权限才能访问
         * role:拥有某个角色的权限才能访问
         */
        Map<String, String> filterMap=new LinkedHashMap<>();

        filterMap.put("/user/add","authc");
        filterMap.put("/user/update","authc");
        bean.setFilterChainDefinitionMap(filterMap);
        //设置登录的请求
        bean.setLoginUrl("/toLogin");
        return bean;
    }

    // DefalutWebSecurityManager
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("getUserRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);
        // 关联UserRealm
        return securityManager;
    }
    // 创建Realm对象,需要自定义
    @Bean("getUserRealm")
    public UserRealm getUserRealm() {
        return new UserRealm();
    }
}
filterMap.put("/user/add","authc");
        filterMap.put("/user/update","authc");

这两行代码就是添加了具体要拦截的请求的url。并设置它要使用的拦截器。

修改首页

添加两个按钮,分别是添加和修改,然后让它指向上面写的两个路径。
首先在indexController里面加两个方法,接收请求

  @RequestMapping("/add")
    public String toAdd(){
        return "add";
    }
    @RequestMapping("/update")
    public String toUpdate(){
        return "update";
    }

然后在index.htmli添加两个超链接。同时在页面头部添加thymleaf的命名空间。

<!DOCTYPE html>
<html lang="en" xmlns:th=“http://www.thymeleaf.org”>
<head>
    <meta charset="UTF-8" >
    <title>Title</title>
</head>
<body>
<h1>首页</h1>

<a th:href="@{user/add}" aria-label="Previous">
    add
</a>
<a th:href="@{user/update}">update</a>
</body>
</body>
</html>

运行项目:
在这里插入图片描述如果把下面这两行给注掉的话,是可以点进去的。

filterMap.put("/user/add","authc");
        filterMap.put("/user/update","authc");

点击add可以进入下面的链接。
在这里插入图片描述

登录页面

下面创建一个登录登录页面,

<!DOCTYPE html>
<html lang="en" xmlns:th=“http://www.thymeleaf.org”>
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>登录</h1>
<hr>
<p th:text="${msg}" style="color:red"></p>
<form >
    <p>用户名: <input type="text" name="username"></p>
    <p>密码: <input type="text" name="password"></p>
    <p><input type="submit"></p>
</form>
</body>
</html>

在indexController创建接收请求的方法。

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

把刚刚那两行注掉的代码给放开,运行项目,点击add,他就会跳转到登录页面。至于它是怎么知道具体的登录页面的,是通过下面这行代码设置的。

bean.setLoginUrl("/toLogin");

登录认证

上面已经实现了拦截请求,下面就是登录。
首先在indexController里面,创建一个接收登录请求的方法。
先获取当前用户,然后构建token,进行登录。当执行subject.login(token);方法的时候,就会进行登录认证,然后就走到UserRealm里的doGetAuthenticationInfo方法,修改那个方法

@RequestMapping("/login")
    public String login(@RequestParam("username") String userName, @RequestParam("password")  String password, Model model){
        // 获取当前用户
        Subject subject = SecurityUtils.getSubject();
        // 创建token
        UsernamePasswordToken token = new UsernamePasswordToken(userName, password);
        // 执行登录方法,如果没有异常就说明登录了
        try {
            System.out.println("登录");
            subject.login(token);
            return "index";
        } catch (UnknownAccountException e) {
            model.addAttribute("msg","用户名不存在");
            return "login";
        }catch (IncorrectCredentialsException e){
            model.addAttribute("msg","密码错误");
            return "login";
        }
    }

执行认证的时候,先进行用户名的判断,不相等的话就会抛出UnknownAccountException,校验密码是shiro帮我们做的。

@Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 用户名,密码,数据库中去取,这里直接使用硬编码
        String name="root";
        String password="123456";
        UsernamePasswordToken userToken= (UsernamePasswordToken) authenticationToken;
        if (!userToken.getUsername().equals(name)){
            return null; // 抛出UnknownAccountException
        }
        // 密码认证 shiro做
        return new SimpleAuthenticationInfo("",password,"");
    }

修改login.html页面。给form添加action属性值。

<form th:action="@{/login}">

然后输入用户名 root,密码:123456点击登录就会直接跳转到首页。再点击add标签,就可以跳转到add页面。
至此登录认证功能就算是完成了。
下面是授权

授权

shiro授权有好几种方式,参考链接
修改ShiroConfig配置类,添加授权校验

filterMap.put("/user/add","authc");
        filterMap.put("/user/update","authc");
        // 下面两行授权,正常情况下,没有授权会跳转到未授权页面
        filterMap.put("/user/add","perms[user:add]");
        filterMap.put("/user/update","perms[user:update]");

对于/user/add资源,只有拥有了user:add权限才可以操作。
修改indexController,设置未授权的登陆页面

@RequestMapping("/noauth")
    @ResponseBody
    public String unauthorized(){

        return "未经授权,无法访问此页面";
    }

然后修改ShiroConfig类,添加未授权的登录页面

 // 未授权页面
        bean.setUnauthorizedUrl("/noauth");

这个时候登录以后,点击add标签,会提示没有权限操作。
如下图。
在这里插入图片描述
这是因为我们没有授权,这个需要修改UserRealm中的doGetAuthorizationInfo方法

  // 给与授权,这个实际上可以从数据库中查询。
          SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();

      authorizationInfo.addStringPermission("user:add,update");
        return authorizationInfo;
        

再重复上面的操作就可以了,这里我给用户添加了user:add权限和user:update权限,所以add和update标签都可以进行跳转。
至此授权已经完成。

退出

当我们点击退出按钮的时候,直接退出,具体代码如下:
修改add.html,我这里直接使用的超链接,点击它就会发送退出请求。

<a th:href="@{/logout}">退出</a>

修改index.controller代码,添加接收注销的请求。

@RequestMapping("/logout")
    public String logout(){
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "redirect:/";
    }

这样当我们退出以后,会再次跳转到首页,我们再点击add标签的时候,会提示你重新登录,但是如果我logout函数里的redirect 给去掉,改成return "index;我就发现,它还可以直接进入到add页面,似乎注销并没有起作用,关于redirect我还不是特别清楚,暂时先这样写吧。
上面的代码在我的gitee上有:代码仓库
参考的视频是B站上的一个视频:视频链接

克隆代码idea无法打开

昨天写的时候忘记了一个问题,就是由于我提交的gitee上没有把iml文件给提交上去,就会导致克隆下来,用idea打开,看不到源码,
file => project structure => Modules => ‘+’ => import modules => 选中项目 => import modules => next…
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
然后一路next就可以了。

另一种退出方式

shiro自带了一个过滤器logoutFilter,我们可以不用自己写退出的方法,
直接在ShiroConfig类加一个过滤器就可以了。

//logout是shiro提供的过滤器
        filterMap.put("/logout", "logout");

然后就可以实现和上面一样的功能

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Master_Yoda

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

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

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

打赏作者

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

抵扣说明:

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

余额充值