SpringBoot安全管理 ——模块4:Spring Boot 整合 Shiro

Spring Boot 整合 Shiro

Shiro简介

Apache Shiro 是一个开源的轻量级的 Java 安全框架,它提供身份验证,授权,密码管理以及会话管理等功能,相对于 Spring Security ,Shiro 框架更加直观,易用,同时也能提供健壮的安全性。
1.创建项目,添加如下依赖:

		<dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-web-starter</artifactId>
            <version>1.4.0</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

2.Shiro 基本配置,在application.properties中进行配置如下代码

#开启Shrio配置
shiro.enabled=true
#开启Shiro Web配置
shiro.web.enabled=true
#默认的登陆地址
shiro.loginUrl=/login
#登陆成功后的地址
shiro.successUrl=/index
#未授权默认跳转地址
shiro.unauthorizedUrl=/unauthorized
#是否允许通过URL参数实现会话跟踪,如果网站支持Cookie,可以关闭此选项
shiro.sessionManager.sessionIdUrlRewritingEnabled=true
#是否允许通过Cookie实现会话跟踪
shiro.sessionManager.sessionIdCookieEnabled=true

3.配置 Shiro

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.text.TextConfigurationRealm;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ShiroConfig {
    @Bean
    public Realm realm() {
        TextConfigurationRealm realm = new TextConfigurationRealm();
        realm.setUserDefinitions("sang=123,user\n admin=123,admin"); //这里配置了两个用户
        realm.setRoleDefinitions("admin=read,write\n user=read");   //admin具有读写权限,user具有读权限
        return realm;
    }

    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
        chainDefinition.addPathDefinition("/login","anon");     //匿名访问
        chainDefinition.addPathDefinition("/doLogin","anon");   //匿名访问
        chainDefinition.addPathDefinition("/logout","logout");  //注销登陆
        chainDefinition.addPathDefinition("/**","authc");       //其他请求需要认证
        return chainDefinition;
    }

    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();  //支持在 Themyleaf 中使用 Shiro 标签
    }
}

4.配置登陆接口以及页面访问接口

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class UserController {
    @PostMapping("/doLogin")
    public String doLogin(String username, String password, Model model) {
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        Subject subject = SecurityUtils.getSubject();
        try {
            subject.login(token);
        } catch (AuthenticationException e) {
            model.addAttribute("error","用户名密码输入错误!");
            return "login";
        }
        return "redirect:/index";
    }

    @RequiresRoles("admin")
    @GetMapping("/admin")
    public String admin() {
        return "admin";
    }

    @RequiresRoles(value = {"admin","user"},logical = Logical.OR)
    @GetMapping("/user")
    public String user() {
        return "user";
    }
}

在doLogin方法中,首先创建一个 UsernamePasswordToken实例,然后获取一个Subject对象并调用该对象中的login方法执行登陆操作,在登陆操作执行过程中,当有异常出现时,说明登陆失败,并将错误信息返回给前端页面

对于其他不需要角色就能访问的接口,直接在WebMvc中配置就行,代码如下:
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/login").setViewName("login");
        registry.addViewController("/index").setViewName("index");
        registry.addViewController("/unauthorized").setViewName("unauthorized");
    }
}

5.创建全局异常处理器进行全局异常处理

import org.apache.shiro.authz.AuthorizationException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

@ControllerAdvice
public class ExceptionController {
    @ExceptionHandler(AuthorizationException.class)
    public ModelAndView error(AuthorizationException e) {
        ModelAndView mv = new ModelAndView("unauthorized");
        mv.addObject("error",e.getMessage());
        return mv;
    }
}
当用户访问未授权的资源时,自动跳转到 unauthorized 这个视图中,并把错误信息显示出来
配置完成后,最后在 resources/template 目录下创建HTML页面进行测试

(1)index.html 首页

<!DOCTYPE html>
<html lang="en" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h3>Hello, <shiro:principal/></h3>
    <h3><a href="/logout">注销登录</a></h3>
    <h3><a shiro:hasRole="admin" href="/admin">管理员页面</a></h3>
    <h3><a shiro:hasAnyRoles="admin,user" href="/user">普通用户页面</a></h3>
</body>
</html>

(2) login.html 登陆页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<div>
    <form action="/doLogin" method="post">
        <input type="text" name="username"> <br>
        <input type="password" name="password"> <br>
        <div th:text="${error}"></div>
        <input type="submit" value="登陆">
    </form>
</div>
</body>
</html>

(3) user.html 普通用户页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>普通用户页面</title>
</head>
<body>
<h1>普通用户页面</h1>
</body>
</html>

(4) admin.html 管理员页面

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>管理员页面</title>
</head>
<body>
<h1>管理员页面</h1>
</body>
</html>

(5) unauthorized.html 未授权页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h3>未获授权,非法访问</h3>
<h3 th:text="${error}"></h3>
</body>
</html>

6.进行测试

启动项目,访问登陆页面,分别使用 sang/123 和 admin/123 进行访问,结果如下图所示

sang 用户登陆后所展示的内容

在这里插入图片描述
————————————————————————————

admin 用户登陆后所展示的内容

在这里插入图片描述
————————————————————————————

登陆成功后,无论 sang 还是 admin 用户,单击 注销登录 都会注销成功,然后回到登陆页面, sang 用户因为不具备管理员权限,因此没有管理员页面的超链接,无法进入管理员页面,如果sang用户手动在地址栏中输入管理员的地址 http:localhost:8080/admin ,则会跳转到未授权页面,如下所示:

注意,必须先用 sang 用户登陆成功后在访问管理员网址才会产生这种结果
在这里插入图片描述
这些就是 shiro 的简单使用!

发布了24 篇原创文章 · 获赞 47 · 访问量 4084

猜你喜欢

转载自blog.csdn.net/qq_43647359/article/details/104539287