关于spring-boot集成shiro的步骤及代码解析

陈淳
2023-12-01

1.创建一个spring-boot项目

2.导入依赖

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring-boot-web-starter</artifactId>
    <version>1.4.1</version>
</dependency>

<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.8.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.22</version>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.48</version>
    </dependency>
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.12</version>
    </dependency>

3.配置

        3.1

@Configuration
public class SecurityConfig {

    @Bean
    public Realm shiroRealm(){
        return new ShiroRealm();
    }

    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition(){
        DefaultShiroFilterChainDefinition sfcd= new DefaultShiroFilterChainDefinition();

        sfcd.addPathDefinition("/","anon");
        sfcd.addPathDefinition("/login","anon");
        sfcd.addPathDefinition("/login.html","anon");
        sfcd.addPathDefinition("/css","anon");
        sfcd.addPathDefinition("/js","anon");

        sfcd.addPathDefinition("html","anon");
        sfcd.addPathDefinition("/logout","logout");
        sfcd.addPathDefinition("/**","user");

        return sfcd;
    }

    @Bean
    public static DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setUsePrefix(true);
        return defaultAdvisorAutoProxyCreator;
    }
}

        3.2.yml配置

spring:
  application:
    name: shiro_boot
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/shiro?characterEncoding=utf8&useSSL=false&serverTimezone=UTC
    password: 123456
    username: root
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8
  mvc:
    format:
      date: yyyy-MM-dd HH:mm:ss

mybatis-plus:
  configuration:
    log-impl: org.apache.ibatis.logging.slf4j.Slf4jImpl
    map-underscore-to-camel-case: true
  type-aliases-package: com.woniuxuy.shiro_boot.model

shiro:
  loginUrl: /login.html

server:
  port: 80

4.实现shiroRealm

public class ShiroRealm extends AuthorizingRealm {
    private static JdbcTemplate jdbcTemplate=null;

    @Resource
    UserTableMapper userTableMapper;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {


        //授权的前提是  认证  =>  得到用户信息
        //授权信息包含    角色 + 权限
        //授权: 根据用户去查询  角色 + 权限  => 入参:用户 出参:角色 + 权限

        UserTable user = (UserTable) principalCollection.getPrimaryPrincipal();
        System.out.println(">>>>>>>>1 "+user);
        // 根据用户查询角色

        List<RoleTable> roleList = jdbcTemplate.query("select r.* from user_table u join user_roles ur on u.user_id = ur.user_id join role_table r on r.role_id = ur.rolse_id where u.user_id = ?"
                , new BeanPropertyRowMapper<RoleTable>(RoleTable.class)
                , user.getUserId());
        System.out.println(">>>>>>>>2 "+roleList);

        Set<String> strRoles = roleList.stream()
                .map(r -> r.getRole())
                .collect(Collectors.toSet());
        System.out.println(">>>>>>>>3 "+strRoles);


        //根据角色查询权限  1,2
        String joined = roleList.stream().map(role -> "" + role.getRoleId()).collect(Collectors.joining(","));
        System.out.println(">>>>>>>>4 "+joined);

        List<String> permissions = jdbcTemplate.query("sselect p.permission from permission_roles rp join permission_table p on rp.permission_id=p.permission_id\n" +
                "where rp.rolse_id in (" + joined + ")", new SingleColumnRowMapper<>(String.class));
        System.out.println(">>>>>>>>5 "+permissions);

        SimpleAuthorizationInfo authzInfo = new SimpleAuthorizationInfo();
        authzInfo.setRoles(strRoles);
        authzInfo.setStringPermissions(new HashSet<>(permissions));

        System.out.println(">>>>>>>>6 "+authzInfo);

        return authzInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("进入获取认证信息方法:"+token);
        Object user = token.getPrincipal();

        //查询用户
        QueryWrapper<UserTable> wrapper = new QueryWrapper<>();
        wrapper.eq(user!=null,"user_name",user);
        UserTable userTable = userTableMapper.selectOne(wrapper);

        if(userTable==null){
            throw new UnknownAccountException(user+"用户不存在");
        }

        //获取到用户名
        Object username = token.getPrincipal();
        //查询用户
        //适配返回对象, 用户、密码、Realm名字
        return new SimpleAuthenticationInfo(userTable,userTable.getUserPwd(),ShiroRealm.class.getName());
    }
    }

5.登录接口

@RestController
    @Slf4j
    public class LoginController {

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

            Subject subject = SecurityUtils.getSubject();
            subject.login(new UsernamePasswordToken(username,password));

            return Result.success();
        }

        @GetMapping("/pay")
        public Result pay(){
            return Result.success();
        }
    }

 类似资料: