SpringSecurity与shiro详细说明与练习

本文介绍了如何在Spring Boot应用中使用Spring Security进行权限控制,包括配置安全拦截、用户认证与授权。同时,也探讨了Shiro的配置与使用,包括用户 Realm 的实现、ShiroConfig的配置以及在Controller中验证登录的方法。文章还提到了Thymeleaf与Shiro的整合,展示了如何在页面上实现权限控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

SpringSecurity(安全)

  1. 导入依赖
<!--security依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--thymeleaf整合security-->
dependency>
	<groupId>org.thymeleaf.extras</groupId>
	<artifactId>thymeleaf-extras-springsecurity4</artifactId>
	<version>3.0.4.RELEASE</version>
</dependency>
  1. SecurityConfig.java
package com.zhb.springboot02.config;

import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

//AOP:拦截器 
//链式编程
@EnableWebSecurity  //加上这个注解才生效
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //授权
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //设置权限,首页所有人都可以访问,功能页只有相应权限的人才能访问
        http.authorizeRequests()
                .antMatchers("/").permitAll()
                .antMatchers("/level1/**").hasRole("vip1")
                .antMatchers("/level2/**").hasRole("vip2")
                .antMatchers("/level3/**").hasRole("vip3");
        //没有权限跳到登录页面
        http.formLogin().loginPage("/toLogin");
        //关闭跨站请求攻击的防护,默认开启,get请求可能会报404,所以要关闭
        http.csrf().disable();
        //开启注销功能,并跳到登录页,会把session和cookie都删除
        http.logout().logoutSuccessUrl("/");
    }
    //认证
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception { 
        //这里从内存中认证作为例子,也可以从数据库中auth.jdbcAuthentication()
        //用户就三个参数:姓名,密码,角色
        //可以通过and()再添加一个用户
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
            	.withUser("zhb")
                .password("123456").roles("vip1")
                .and()
                .withUser("root")
                .password("123").roles("vip1","vip2","vip3");
        //当密码没加密就有可能会出现一个500错误:PasswodEncoder,认为你的密码不安全,因为可以反编译
        //在security5.0+新增了很多加密方法,
        //通过.passwordEncoder(new BCryptPasswordEncoder())设置加密的方式
        //再通过.password(new BCryptPasswordEncoder().encode("123456"))进行编码
        
    }
}

jdbc认证:

在这里插入图片描述

shiro

  1. 导入依赖:

    <!--整合spring就不用添加这个包,否则会导致ShiroFilterFactoryBean这个找不到-->
    <!--<dependency>
    	<groupId>org.apache.shiro</groupId>
    	<artifactId>shiro-core</artifactId>
    	<version>1.4.1</version>
    </dependency>-->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.4.1</version>
    </dependency>
    
  2. 配置文件:shiro.ini

  3. 快速开始

//固定套路,通过工厂设置安全管理
Factory<SecurityManager> factory=new IniSecurityManagerFactory("classpath:shiro.ini");
SecurityManager securityManager=factory.getInstance;
SecurityUtils.setSecurityManager(securityManager);
//具体操作
Subject currentUser=SecurityUtils.getSubject();//获取用户
Session session=currentUser.getSession();//获取session
if(!currentUser.isAuthenticated()){}//判断当前用户是否被认证
currentUser.getPrincipal();//获取当前用户的认证
currentUser.hasRole("admin");//判断当前用户是否是这个角色
currentUser.isPermitted("admin");//判断当前用户是否有这个权限
currentUser.louout();//注销

实际写项目:

shiro有三大对象:

  • Subject:用户,currentUser
  • SecurityManager: 用户管理
  • Realm:连接数据

配置的话要倒着配,先连接数据,再设置用户管理,最后才进行用户一些登录或登出获取session的操作

  1. UserRealm.java,用来编写查询的一些方法和认证授权的逻辑

    首先得继承AuthorizingRealm这个类,重写doGetAuthorizationInfo(授权),doGetAuthenticationInfo(认证)两个方法

    package com.zhb.config;
    
    import com.zhb.service.EmpService;
    import org.apache.catalina.security.SecurityUtil;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.*;
    import org.apache.shiro.authz.AuthorizationInfo;
    import org.apache.shiro.authz.SimpleAuthorizationInfo;
    import org.apache.shiro.realm.AuthorizingRealm;
    import org.apache.shiro.subject.PrincipalCollection;
    import org.apache.shiro.subject.Subject;
    import org.springframework.beans.factory.annotation.Autowired;
    
    import java.util.List;
    
    public class UserRealm extends AuthorizingRealm {
        @Autowired
        EmpService empService;
        //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            //授权操作
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            //当ShiroConfig进行设置权限阻拦时就会跳到这么方法
            //假如root为0,管理员为1,普通用户为2,下面这个操作就是代表对权限值是0进行授权放行
            //而1和2就会被阻拦
            //拿到当前登录对象
            Subject user= SecurityUtils.getSubject();
            //从这获取到认证传过来的授权值,这里是个object,获取过来是什么可以进行强转
            String principal = (String)user.getPrincipal();
            //设置当前用户的权限,是什么就是什么
            info.addStringPermission(principal);
            return info;
        }
        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            //获取输入的用户和密码
              UsernamePasswordToken userToken = (UsernamePasswordToken) token;
            //获取密码·
            List<String> passwords = empService.selectPassword(userToken.getUsername());
            if (passwords == null && passwords.isEmpty()) {
                return null;//return null就会抛出UnknownAccountException异常
            }
            //查到用户后设置session
            Subject currentUser = SecurityUtils.getSubject();
           currentUser.getSession().setAttribute("loginUser",userToken.getUsername());
            //密码认证,shiro来做,返回简单的加密方式
            //第一个参数是principal,用来向授权传递参数,这里伪造一个“0”,实际应该通过数据库获取权限值
                for (String password : passwords) {
                    return new SimpleAuthenticationInfo("0", password, "");
            }
            return null;
        }
    }
    
    
  2. ShiroConfig.java:总配置,集成到spring的bean中

    需要创建三个bean,注意要添加@Bean注解添加到spring容器中

    1. ShiroFilterFactoryBean
    2. DefaultWebSecurityManager
    3. UserRealm
    package com.zhb.springboot02.config;
    
    import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.context.annotation.Bean;
    import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
      public class ShiroConfig {
        @Bean
        //ShiroFilterFactoryBean
        public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager defaultWebSecurityManager){
            ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
            //设置安全管理器
            bean.setSecurityManager(defaultWebSecurityManager);
            //添加shiro的内置过滤器
            /*
            	anon:无需认证就可以访问
            	authc:必须认证才能访问
            	user:必须拥有“记住我”这个功能才能用
            	perms:拥有对某个资源的权限才能访问
            	role:拥有某个角色权限才能访问
            */
            //被拦截后,会自动跳到登录页面,但跟SpringSecurity不一样,它的login.html必须自己写
            Map<String,String> filterMap=new LinkedHashMap<>();
            filterMap.put("/user/add/","anon");//这个路径所有人都能访问
            filterMap.put("/user/update","perms[0]");//这个请求的操作只有权限为0的用户可以做
            bean.setFilterChainDefinitionMap(filterMap);
            //设置登录跳转的请求
            bean.setLoginUrl("/index");
            //设置未授权后会跳转的请求
            bean.setUnauthorizedUrl("/noauth");
    
            return bean;
    
        }
        //DafaultWebSecurityManager:第二步
        @Bean(name = "securityManager")
        public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            //关联realm
            securityManager.setRealm(userRealm);
            return securityManager;
        }
    
        //创建 realm对象,需要自定义:第一步
        @Bean
     public UserRealm userRealm(){
            return new UserRealm();
     }
    }
    
    

    在controller中验证登录:

    @RequestMapping("/login")
        public String login(String username, String password, Model model) {
            Subject currentUser = SecurityUtils.getSubject();
            //对用户名密码进行加密封装
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
            //登陆验证
            try {
                currentUser.login(token);
                return "index";
            } catch (UnknownAccountException e) {//用户名不存在
                model.addAttribute("msg", "用户名不存在");
                return "login";
         } catch (IncorrectCredentialsException e) {//密码错误
                model.addAttribute("msg", "密码错误");
             return "login";
            }
        }
    

    thymeleaf整合shiro:

    1. 导入依赖

      <!-- thymeleaf整合shiro -->
      <dependency>
          <groupId>com.github.theborakompanioni</groupId>
          <artifactId>thymeleaf-extras-shiro</artifactId>
          <version>2.0.0</version>
      </dependency>
      
      
    2. 可以在ShiroConfig中配置一下,注册个bean

      @Bean
          //配置ShiroDialect,用来整合shiro和thymeleaf
          public ShiroDialect getShiroDialect(){
              return new ShiroDialect();
          }
      
    3. html页面使用

    <!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>Thymeleaf整合Shiro</title>
    </head>
    <body>
    <!--从session中获取值,没有值就显示登录按钮-->
    <div th:if="${session.loginUser==null}">
        <a th:href="@{/login}">登录</a>
    </div>
    <!--用户拥有0这个权限才会显示删除这个链接-->
    <div shiro:hasPermission="0">
        <a th:href="@{user/delete}">删除</a>
    </div>
    <!--用户拥有1这个权限才会显示查找这个链接-->
    <div shiro:hasPermission="1">
        <a th:href="@{user/update}">查找</a>
    </div>
    </body>
    </html>
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

想吃饼干吗

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

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

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

打赏作者

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

抵扣说明:

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

余额充值