Shiro-SpringBoot集成入门案例

代码包括基于注解权限和加密加盐
项目结构
在这里插入图片描述
1.新建maven工程,并导入依赖

 <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.0.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--springboot集成Junit 的启动依赖-->
        <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>
        <!--thymeleaf启动依赖,它是一个前端模板引擎,完全替代jsp-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
        <!--引入的是shiro与spring的集成-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.1</version>
        </dependency>
        <!--aop 的起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
        <!--thymeleaf shiro 根据权限标签显示-->
        <!--shiro与themeleaf集成-->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>
    </dependencies>

2.在resource文件夹下新建application.properties

#日志输出级别
logging.level.root=debug

3.在com.aaa下新建启动类

package com.aaa;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

4.新建自定义realm

package com.aaa.realm;

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.util.ByteSource;

public class UserRealm extends AuthorizingRealm {
    // 获取认证信息
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        String username = (String) authenticationToken.getPrincipal();
        System.out.println("username=="+username);


        // 需要自己取数据库校验当前用户名是否存在 如果不存在,用改手动方式抛出
        if (!username.equals("root")){
            throw  new UnknownAccountException();
        }


        // 根据据用户名 去数据库查询密码
        // 假装去数据获取对应用户名的密码
        String passwordFromDB = "123456";
        //数据库真实的密码
        //String passwordFromDB="db5f14348f3016b9d53c66db0ed6bb8e";
        //加盐
        ByteSource salt=ByteSource.Util.bytes(username);

        // 得到用户  真实的数据哭的用户名 密码认证信息
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username,passwordFromDB,this.getName());

        //返回给securityMange 进行认证
        return authenticationInfo;
    }

    // 授权
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        String username = (String) principalCollection.getPrimaryPrincipal();

        System.out.println("username:"+username);


        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        // 去数据库查询 root 相关的权限 和  角色
        if (username.endsWith("root")){

            // 设置当前用户角色
             authorizationInfo.addRole("boss");

            // 给当前用户设置权限
            authorizationInfo.addStringPermission("goods:add");
            authorizationInfo.addStringPermission("goods:delete");
            authorizationInfo.addStringPermission("user:delete");


        }

        // 返回个securityManager 当前用户的角色 和权限
        return authorizationInfo;
    }

}




5.在com.aaa 新建shiro 的配置类,新建Config文件夹,创建Shiroconfig类

package com.aaa.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.aaa.realm.UserRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
@Configuration// 表明当前类是一个配置类 相当于beans.xml 文件
public class Shiroconfig {
    @Bean // 1.将创建的UserRealm 加入到容器
    public UserRealm getUserRealm(HashedCredentialsMatcher matcher){
        UserRealm userRealm=new UserRealm();
        //将userRealm和matcher绑定
        userRealm.setCredentialsMatcher(matcher);
        return userRealm;
    }
    /*@Bean//将用户传来的密码加密,并获取SimpleAuthenticationInfo中的盐和迭代1000次,就是当前用户的登录的加密密码
    public HashedCredentialsMatcher getHashedCredentialsMatcher(){
        HashedCredentialsMatcher credentialsMatcher=new HashedCredentialsMatcher();
        //算法名
        credentialsMatcher.setHashAlgorithmName("MD5");
        //加密迭代次数
        credentialsMatcher.setHashIterations(1000);
        return credentialsMatcher;
    }*/
    @Bean// 2.向容器加入 SecurityManager     getSecurityManager(UserRealm userRealm)
    // 当创建SecurityManager时,回去容器中去查找一个UserRealm类型的bean
    public SecurityManager getSecurityManager(UserRealm userRealm){
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);
        return securityManager;
    }
    @Bean//设置 shiro 过滤器:作用就是过滤拦截 鉴权当前用户是否有 对应的角色和权限
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
        // 将 securityManager 和 拦截器进行绑定
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //没有登录跳转的页面
        shiroFilterFactoryBean.setLoginUrl("/user/toLongin");
        //认证成功跳转的页面
        shiroFilterFactoryBean.setSuccessUrl("/user/toIndex");
        //登录会权限不足跳转的页面,注解的权限或者角色不能直接跳转权限不足页面,需要手动设置
        shiroFilterFactoryBean.setUnauthorizedUrl("/user/unauthorized");
        Map<String, String> filterChainDefinitionMap = new HashMap<>();
        filterChainDefinitionMap.put("/user/login","anon");
        //配置游客路径,不登录也可以访问
        filterChainDefinitionMap.put("/guest/*","anon");
        //访问当前路径,当前必须拥有root角色,roles[root,manager],表示必须拥有root,manager角色
        filterChainDefinitionMap.put("/user/add","roles[root]");
        //访问当前路径必须拥有user:delete 权限
        filterChainDefinitionMap.put("/user/delete","perms[user:delete]");
        // 拦截所有路径 *****   一定要写在再最后
        filterChainDefinitionMap.put("/**","authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;


    }
  /*  @Bean  //  处理基于注解的权限   @RequiresRoles @RequiresParam   @RequiresGuest 。。。
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(SecurityManager securityManager){


        AuthorizationAttributeSourceAdvisor attributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();

        //将 AuthorizationAttributeSourceAdvisor 和 SecurityManager
        attributeSourceAdvisor.setSecurityManager(securityManager);

        return attributeSourceAdvisor;
    }

    @Bean  // <aop:aspectj-autoproxy/> 开启aop 注解,像容器注入一个 DefaultAdvisorAutoProxyCreator
    @ConditionalOnMissingBean  //当容器中没有当前DefaultAdvisorAutoProxyCreator 实例时,注入,如果有就不注入
    DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){

        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();

        // 使用 cglib 完成代理
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);

        return defaultAdvisorAutoProxyCreator;
    }
    @Bean// 当前异常 处理的就是  shiro基于注解的鉴权时,不满足权限需要抓住异常
    SimpleMappingExceptionResolver simpleMappingExceptionResolver(){
        SimpleMappingExceptionResolver resolver=new SimpleMappingExceptionResolver();
        // Properties 就是读取配置文件的键值对
        Properties property = new Properties();
        // key 就是要捕捉 异常的权限定名
        property.setProperty("org.apache.shiro.authz.AuthorizationException","/403.html");
        resolver.setExceptionMappings(property);
        return resolver;
    }
    @Bean//ShiroDialect整合shiro-thymeleaf
    ShiroDialect getShiroDialect(){
        ShiroDialect shiroDialect=new ShiroDialect();
        return shiroDialect;
    }*/
}

6.配置用户登录,创建controller

package com.aaa.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/user")
public class UserController {
    @RequestMapping("/toLongin")
    public String toLongin(){
        return "login";
    }
    @RequestMapping("/toIndex")
    public String toIndex(){

        return "index";
    }
    @RequestMapping("/login")
    public String login(String username,String password){
        //获取当前用户
        Subject subject= SecurityUtils.getSubject();
        AuthenticationToken token=new UsernamePasswordToken(username,password);
        subject.login(token);
        //如果登录成功
        if (subject.isAuthenticated()){
            return "index";
        }else {
            return "login";
        }
    }
    @RequestMapping("/unauthorized")
    public String unauthorized(){

        return "403";
    }
    @RequestMapping("/add")
    public String addUser(){
        return "addUser";
    }
    @RequestMapping("/delete")
    public String deleteUser(){
        return "delete";
    }
    @RequestMapping("/logout")
    public String logout(){
        Subject subject=SecurityUtils.getSubject();
        if (subject.isAuthenticated()){
            subject.logout();
        }
         return "login";
    }
}

7在resource文件夹下新建templates文件夹创建和controller层对应的html界面

在这里插入图片描述
8 测试,浏览器输入 http://localhost:8080,自动跳转到http://localhost:8080/user/toLogin
在这里插入图片描述
输入账户 root 密码12345
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值