当前位置: 移动技术网 > IT编程>开发语言>Java > Spring Boot整合Shiro

Spring Boot整合Shiro

2020年07月27日  | 移动技术网IT编程  | 我要评论

1.Shiro

什么是Shiro
是一款主流的Java安全框架,不依赖任何容器,可以运行在Java SE和Java EE项目中,它的主要作用是对访问系
统的用户进行身份认证、授权、会话管理、加密等操作。
Shiro就是用来解决安全管理的系统化框架。

2 Shiro核心组件

用户、角色、权限
会给角色赋予权限,给用户赋予角色
1、UsernamePasswordToken, Shiro 用来封装用户登录信息,使用用户的登录信息来创建令牌Token。
2、SecurityManager, Shiro 的核心部分,负责安全认证和授权。
3、Suject, Shiro 的一个抽象概念,包含了用户信息。
4、Realm,开发者自定义的模块,根据项目的需求,验证和授权的逻辑全部写在Realm中。
5、AuthenticationInfo, 用户的角色信息集合,认证时使用。
6、AuthorzationInfo, 角色的权限信息集合,授权时使用。
7、DefaultWebSecurityDManager, 安全管理器,开发者自定义的Realm需要注入到
DefaultWebSecurityDManager进行管理才能生效。
8、ShiroFilterFactoryBean, 过滤器工厂,Shiro 的基本运行机制是开发者定制规则,Shiro 去执行,具体的执行操
作就是由ShiroFilterFactoryBean创建的一个个Filter对象来完成。
Shiro的运行机制如下图所示。
在这里插入图片描述

Shiro的核心概念Subject、SecurityManager、Realm

Subject:主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如爬虫、机器人等;即一个抽象概念;所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者。
SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是shiro的核心, SecurityManager相当于spring mvc中的dispatcherServlet前端控制器。
Realm:域,shiro从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。

3.Spring Boot整合Shiro

项目开始:

一、数据库设计
在这里插入图片描述

二、创建项目导入依赖(springboot项目为例)
1、用idea新建Spring Initializr项目,项目结构如下:
在这里插入图片描述
在这里插入图片描述

2、添加依赖

 <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <!-- shiro -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.5.2</version>
        </dependency>
         <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <!-- mybatis-plus-boot-starter -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.0.5</version>
        </dependency>
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>

2.配置application.yml

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root
    url: jdbc:mysql://localhost:3306/shiro?useSSL=false&serverTimezone=UTC&characterEncoding=utf8&allowPublicKeyRetrieval=true
mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Account {

    private Integer id;
    private String username;
    private String password;
    private String perms;
    private String role;
}
类介绍:
在Realm类中去写认证逻辑和授权逻辑;
public class AccountRealm extends AuthorizingRealm {

    @Autowired
    private AccountService accountService;

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //获取当前登录的用户信息
        Subject subject = SecurityUtils.getSubject();
        Account account = (Account) subject.getPrincipal();

        //设置角色
        Set<String> roles = new HashSet<>();
        roles.add(account.getRole());
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);

        //设置权限
        info.addStringPermission(account.getPerms());
        return info;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        Account account = accountService.findByUsername(token.getUsername());
        if (account != null){
            return new SimpleAuthenticationInfo(account,account.getPassword(),getName());
        }
        return null;
    }
}

写完之后,配置一个config类,配置类里面需要注入ShiroFilterFactoryBean,securityManager,Realm,配置完这3个接下来就可以写你的逻辑了;

ShiroFilterFactoryBean:是个拦截器,在请求进入控制层前将其拦截,需要将安全管理器SecurityManager注入其中。

SecurityManager:安全管理器,需要将自定义realm注入其中,以后还可以将缓存、remeberme等注入其中

@Configuration
public class ShiroConfig {

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager);
        //权限设置
        Map<String,String> map = new Hashtable<>();
        map.put("/main","authc");
        map.put("/manage","perms[manage]");
        map.put("/administrator","roles[administrator]");
        factoryBean.setFilterChainDefinitionMap(map);
        //设置登录页面
        factoryBean.setLoginUrl("/login");
        //设置未授权页面
        factoryBean.setUnauthorizedUrl("/unauth");
        return factoryBean;
    }

    @Bean
    public DefaultWebSecurityManager securityManager(@Qualifier("accountRealm") AccountRealm accountRealm){
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        manager.setRealm(accountRealm);
        return manager;
    }

    @Bean
    public AccountRealm accountRealm(){
        return new AccountRealm();
    }

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

Controller类说明

登录过程其实只是处理异常的相关信息,具体的登录验证交给shiro来处理

@Controller
@Slf4j
public class AccountController {
// 请打开麦克风交流
    @GetMapping("/{url}")
    public String redirect(@PathVariable("url") String url){
        return url;
    }

    @PostMapping("/login")
    public String login(String username , String password, Model model){

        log.warn("username is ======>"+username);

        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        try {
            subject.login(token);
            Account account = (Account) subject.getPrincipal();
            subject.getSession().setAttribute("account",account);
            return "index";
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            model.addAttribute("msg","用户名错误!");
            return "login";
        }catch (IncorrectCredentialsException e){
            model.addAttribute("msg","密码错误!");
            e.printStackTrace();
            return "login";
        }
    }

    @GetMapping("/unauth")
    @ResponseBody
    public String unauth(){
        return "未授权,无法访问:";
    }

    @GetMapping("/logout")
    public String logout(){
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "login";
    }
}

页面说明

登录页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="shortcut icon" href="#"/>
</head>
<body>
    <form action="/login" method="post">
        <table>
            <span th:text="${msg}" style="color: red"></span>
            <tr>
                <td>用户名:</td>
                <td>
                    <input type="text" name="username"/>
                </td>
            </tr>
            <tr>
                <td>密码:</td>
                <td>
                    <input type="password" name="password"/>
                </td>
            </tr>
            <tr>
                <td>
                    <input type="submit" value="登录"/>
                </td>
            </tr>
        </table>
    </form>
</body>
</html>

index页面

<!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</title>
    <link rel="shortcut icon" href="#"/>
</head>
<body>
    <h1>index</h1>
    <div th:if="${session.account != null}">
        <span th:text="${session.account.username}+'欢迎回来!'"></span><a href="/logout">退出</a>
    </div>

    <a href="/main">main</a> | <a href="manage">manage</a> | <a href="/administrator">administrator</a>
    <!--<a href="/main">main</a> <br/>-->
    <!--<div shiro:hasPermission="manage">-->
        <!--<a href="manage">manage</a> <br/>-->
    <!--</div>-->
    <!--<div shiro:hasRole="administrator">-->
        <!--<a href="/administrator">administrator</a>-->
    <!--</div>-->
</body>
</html>

administator.html页面

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

main.html页面

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

manage.html页面

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

编写认证和授权规则:

认证过滤器

auths:必须认证
authcBasic:需耍通过HTTPBasic认证
user:不-定通过认证,只要曾经被Shiro记录即可,比如:记住我

授权过滤器

perms:必须拥有某个权限才能访问
role:必须拥有某个角色才能访问
port:请求的端口必须是指定值才可以
rest:请求必须基于RESTful, POST. PUT. GET. DELETE
ssl:必须是安全的URL请求,协议HTTPS

创建3个页面,main.html. manage.html. administrator.html
访问权限如下:
1、必须登录才能访问main.html
2、当前用户必须拥有manage授权才能访问manage.html
3、当前用户必须拥有administrator角色才能访问administrator.html

Shiro整合Thymeleaf

1.pom.xml 引入依赖

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

2.配置类添加 ShiroDialect

@Bean
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }
Service类
@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    private AccountMapper accountMapper;

    @Override
    public Account findByUsername(String username) {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("username",username);
        return accountMapper.selectOne(wrapper);
    }
}

public interface AccountService {
    public Account findByUsername(String username);
}
mapper类
public interface AccountMapper extends BaseMapper<Account> {
}

测试类

@SpringBootTest
class AccountMapperTest {

    @Autowired
    private AccountMapper mapper;

    @Test
    void test(){
        mapper.selectList(null).forEach(System.out::println);
    }
}
@SpringBootTest
class SpringbootShiroApplicationTests {

    @Test
    void contextLoads() {
    }

}
@SpringBootApplication
@MapperScan("com.fang.mapper")
public class SpringbootShiroApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringbootShiroApplication.class, args);
    }

}

测试
http://www.lhsxpumps.com/_localhost:8080/login 页面
在这里插入图片描述

登录成功跳转 index 页面
在这里插入图片描述

在这里插入图片描述

本文地址:https://blog.csdn.net/liyanfang0310/article/details/107163379

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网