SpringSecurity和Shiro快速上手

SpringSecurity

1、Spring Security介绍

介绍

Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。它是用于保护基于Spring的应用程序的实际标准。

特征

  • 对身份验证和授权的全面且可扩展的支持
  • 防止攻击,例如会话固定,点击劫持,跨站点请求伪造等
  • Servlet API集成
  • 与Spring Web MVC的可选集成
  • 等等…

2、使用

针对springboot项目,常见的配置方案

/*
	SecurityConfig配置类
	@EnableWebSecurity 开启配置验证
*/
@EnableWebSecurity 
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    AdminSer adminSer; //管理员服务层
	
    /*	
    	添加管理员账号到SecurityConfig的认证集合中,SecurityConfig会自动根据已存在的账号安排对应的权限
    	添加账号用法
    	auth.inMemoryAuthentication().withUser("用户名").passwordEncoder(密码编码模式).password("密码").roles("角色权限")
    */
    @Override //认证
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        ArrayList<Admin> allAdmin = adminSer.getAllAdmin(); //获取所有管理员账号
        for (Admin admin : allAdmin) {
            auth.inMemoryAuthentication()  
                    .withUser(String.valueOf(admin.getAdminId())) //用户名
                    .passwordEncoder(new BCryptPasswordEncoder()) //密码编码(加密模式)模式
                    .password(new BCryptPasswordEncoder().encode(admin.getPassword())) //设置密码
                    .roles(admin.getRoleName()); //角色权限
        }
    }

    
    /*
    	根据用户的账号权限,决定用户是否有权限进行访问该接口或资源
 		工作流程:
 			当用户在登入页面进行登入时,会被"授权"拦截,并将账号和密码发给"认证","认证"在自己的认证集合中判断该账号是否存在,如果不存在"授权"将重定向到登入页面(默认情况下),如果存在返回该账号的权限,"授权"根据权限放行(允许用户访问)对应的资源和接口,如果没有对应权限将被重定向到登入页面(默认情况下)。
    */
    @Override //授权
    protected void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
                .antMatchers("/") //antMatchers 资源路径,还可以这样子写antMatchers("/", "/home")
            		.permitAll()  //所有人都可以访问
                .antMatchers("/admin/**").hasRole("admin")  //hasRole:访问要求的角色权限
                .antMatchers("/master/**").hasRole("master") //hasRole:访问要求的角色权限
                .and() //连接符,这样子才可用继续使用链式编程
                .formLogin() //登入页面配置
                    .passwordParameter("password") //规定接受的密码参数
                    .usernameParameter("username") //规定接受的用户名参数
                    .permitAll() //所有人都可以访问
                    .and() 
                .csrf().disable(); //csrf()防止伪站点攻击,disable()启动网站保护
        
        		/*
        		.and
        		.rememberMe()//验证成功后记住我 原理是用户信息存在cookies,下次访问不需要再输入账号密码
          			.rememberMeParameter("remember");//规定接受记住我的参数
          		.and()//分割
          		.logout()//注销
          			.logoutSuccessUrl("/")//更改注销后跳转的页面
          			.permitAll()//所有人可以访问
        		*/
        ;
    }
}

想要深入学习可以观看下面两个大佬的博客

https://blog.csdn.net/andy_zhang2007/article/details/90511688

https://wangsong.blog.csdn.net/article/details/106068685


Shiro

官方

1、介绍

Shiro是一个功能强大且易于使用的Java安全框架,用于执行身份验证,授权,加密和会话管理。使用Shiro易于理解的API,您可以快速轻松地保护任何应用程序-从最小的移动应用程序到最大的Web和企业应用程序

2、特征

  • 易于使用

    ​ 易于使用是该项目的最终目标。应用程序安全性可能非常令人困惑和沮丧,并被视为“必要的邪恶”。如果您使它易于使用,以使新手程序员可以开始使用它,那么就不必再痛苦了。

  • 全面

    ​ Apache Shiro声称没有其他具有范围广度的安全框架,因此它很可能是满足安全需求的“一站式服务”。

  • 灵活

    ​ Apache Shiro可以在任何应用程序环境中工作。尽管它可以在Web,EJB和IoC环境中运行,但并不需要它们。Shiro也不要求任何规范,甚至没有很多依赖性。

  • 具有Web功能

    ​ Apache Shiro具有出色的Web应用程序支持,允许您基于应用程序URL和Web协议(例如REST)创建灵活的安全策略,同时还提供一组JSP库来控制页面输出。

  • 可插拔

    ​ Shiro干净的API和设计模式使它易于与许多其他框架和应用程序集成。您会看到Shiro与Spring,Grails,Wicket,Tapestry,Mule,Apache Camel,Vaadin等框架无缝集成。

  • 支持

    ​ Apache Shiro是Apache Software FoundationApache软件基金会)的一部分,该组织被证明以其社区的最大利益行事。项目开发和用户群体友好的公民随时可以提供帮助。如果需要,像Katasoft这样的商业公司也可以提供专业的支持和服务。

2、核心组件

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9GBjKu3n-1625228240900)(F:\笔记\图片\SpringSecurity和Shiro\shiro构造.png)]

  1. Subject:

    Subject`它本质上是当前正在执行的用户的特定于安全性的“视图”。虽然“用户”这个词通常意味着一个人,但是它可以是一个人,但它也可以代表第三方服务,守护进程帐户,定时任务或任何类似的东西 ,总之,它可基本上以是任何与软件交互的东西。

    Subject实例都绑定(并要求)到 SecurityManager。当您与一个Subject进行交互时,最后都会转换为与 SecurityManager的交互。

  2. SecurityManager

    SecurityManager是Shiro架构的核心,充当一种“综合的”对象,协调其内部安全组件。但是,一旦为应用程序配置好了SecurityManager及其内部组件对象,它通常不会再被开发人员调用,应用程序开发人员几乎将所有时间花在Subject的API上。

    我们稍后将SecurityManager详细讨论。但目前最重要的要意识到,当您与Subject进行交互时,实际上在幕后是SecurityManager完成所有Subject安全操作。这反映在上面的基本流程图中。

  3. Realms

    领域充当Shiro与应用程序安全数据之间的“桥梁”或“连接器”。当实际与安全相关的数据(如用户帐户)进行交互,以执行身份验证(登录)和授权(访问控制)时,Shiro会从为应用程序配置的一个或多个Realm中查找许多这些程序的安全数据。

详细介绍网站

3、使用

针对springboot项目

  1. 导入依赖

    <!--shiro-->
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring-boot-web-starter</artifactId>
        <version>1.5.3</version>
    </dependency>
    
    <!--thymeleaf,不导入这个,访问请求可能会报错-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    
  2. 创建配置类

    创建Realm

    public class UserRealm extends AuthorizingRealm {
        @Override //授权 当用户进入需要授权页面时触发
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            System.out.println("进入授权");
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            //拿到user对象 (获取正在获取授权的用户)
            Subject subject = SecurityUtils.getSubject();
            User user = (User) subject.getPrincipal();
            
            if(user.getUsername().equals("admin")){
                info.addStringPermission("admin:v1");//设置当前用户的权限
            }
            return info;
        }
    
        @Override //认证 当用户认证时触发
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken aToken) throws AuthenticationException {
            UsernamePasswordToken token = (UsernamePasswordToken) aToken;
            User user = new User("admin","123");
            System.out.println("进入认证,用户名:"+token.getUsername()+"   密码:"+token.getPassword());
          //账号认证,密码验证shiro来做
            if(!token.getUsername().equals(user.getUsername())){
                return null; //用户不存在返回null,返回null就是转跳登入页面重新登入
            }else {
                return new SimpleAuthenticationInfo(user,user.getPassword(),"");//这里的user是用来给授权调用的
            }
    
        }
    }
    

    创建配置类

    @Configuration
    public class ShiroConfig {
        @Bean
        public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("dwsm") DefaultWebSecurityManager dwsm){
            ShiroFilterFactoryBean sffb = new ShiroFilterFactoryBean();
    
            Map<String, String> filterMap = new LinkedHashMap<>();//存放过滤器
            /*
             anon:无需认证就可以访问
             authc:必须认证才可访问
             user:必须拥有 记住我 功能才能访问
             perms:拥有 某资源的权限 才能访问
             role:拥有 某个角色权限 才能访问
             */
            filterMap.put("/user","authc");
            filterMap.put("/admin","perms[admin:v1]");//添加某资源的权限
            sffb.setFilterChainDefinitionMap(filterMap);//设置路径过滤器
            sffb.setSecurityManager(dwsm); //设置安全管理器
            sffb.setLoginUrl("/tologin");//设置登入页面,跳转/login请求
            return sffb;
        }
    
        @Bean("dwsm")
        public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
            DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager();
            dwsm.setRealm(userRealm); //绑定Realms
            return dwsm;
        }
    
        @Bean //创建配置好的Realm
        public UserRealm userRealm(){
            return new UserRealm();
        }
    }
    
  3. 创建视图

    • login.html

      <!DOCTYPE html>
      <!--login.html-->
      <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
      <head>
          <meta charset="UTF-8">
          <title>Title</title>
      </head>
      <body>
          <form action="/login">
              <p><input type="text" name="username"></p>
              <p><input type="password" name="password"></p>
              <p><input type="submit"></p>
              <p th:text="${msg}"></p>
          </form>
      </body>
      </html>
      
    • user.html,内容自定义

    • index.html,内容自定义

    • admin.html,内容自定义

  4. 创建controller类

    @Controller
    public class MyController {
        @RequestMapping("/tologin")
        public String toLogin(){
            return "login"; //需要对应的login.html
        }
    
        @RequestMapping("/user")
        public String toUser(){
            return "user";//需要对应的user.html,内容自定义
        }
    
        @RequestMapping({"/","/index"})
        public String toIndex(){
            return "index";//需要对应的index.html,内容自定义
        }
    
        @RequestMapping("/login")
        public String Login(Model model, @RequestParam("username") String username,@RequestParam("password")  String password){
            Subject subject = SecurityUtils.getSubject();
            UsernamePasswordToken token = new UsernamePasswordToken(username,password);
            try {
                subject.login(token);//执行登入认证,成功就往下走,失败抛出异常
                return "user";
            }catch (UnknownAccountException e){//用户名不存在
                model.addAttribute("msg","用户名不存在");
                return "login";
            }catch (IncorrectCredentialsException e){//密码错误
                model.addAttribute("msg","密码错误");
                return "login";
            }
        }
        
        @RequestMapping("/admin")
        public String toAdmin(){
            return "admin";//需要对应的admin.html,内容自定义
        }
    }
    
上一篇:03 Shrio身份认证示例


下一篇:springboot整合shiro