02.SpringBoot3+JDK17+Shiro+Basic认证方式

SpringBoot3+JDK17+Shiro+Basic认证方式

依赖

注意: 由于JDK17使用的是Jakarta EE规范,而截止2023年12月29日Shiro2.0还处于(alpha)测试阶段,所以只能使用目前最新的版本shiro1.13,但是Shiro1.13版本目前默认使用的是Java EE规范,所以不能直接引入shiro-spring-boot-web-starter依赖

<dependencies>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-spring</artifactId>
			<classifier>jakarta</classifier>
			<version>1.13.0</version>
			<exclusions>
				<exclusion>
					<groupId>org.apache.shiro</groupId>
					<artifactId>shiro-core</artifactId>
				</exclusion>
				<exclusion>
					<groupId>org.apache.shiro</groupId>
					<artifactId>shiro-web</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-core</artifactId>
			<classifier>jakarta</classifier>
			<version>1.13.0</version>
		</dependency>

		<dependency>
			<groupId>org.apache.shiro</groupId>
			<artifactId>shiro-web</artifactId>
			<classifier>jakarta</classifier>
			<version>1.13.0</version>
			<exclusions>
				<exclusion>
					<groupId>org.apache.shiro</groupId>
					<artifactId>shiro-core</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.33</version>
		</dependency>

		<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>3.5.3.2</version>
		</dependency>

	</dependencies>

涉及表结构(核心字段)

  1. 用户表(sys_user)

    FieldTypeNullKeyDefaultExtraComment
    user_idbigintNOPRINULLauto_increment
    usernamevarchar(50)NOUNI登录用户名
    namevarchar(128)YESNULL姓名
    passwordvarchar(100)YESNULL密码
  2. 角色表(sys_role)

    FieldTypeNullKeyDefaultExtraComment
    role_idbigintNOPRINULLauto_increment
    role_namevarchar(100)YESNULL角色名称
    remarkvarchar(100)YESNULL备注
  3. 权限表/菜单表(sys_menu)

    FieldTypeNullKeyDefaultExtraComment
    perm_idbigint unsignedNOPRINULLauto_increment
    permsvarchar(500)YESNULL授权(多个用逗号分隔,如:user:list,user:create)
  4. 用户角色表(sys_user_role)

    FieldTypeNullKeyDefaultExtraComment
    idbigintNOPRINULLauto_increment
    user_idbigintYESNULL用户ID
    role_idbigintYESNULL角色ID
  5. 角色权限表(sys_role_menu)

    FieldTypeNullKeyDefaultExtraComment
    idbigintNOPRINULLauto_increment
    role_idbigintYESNULL角色ID
    perm_idbigintYESNULL权限ID

springboot配置

server:
  port: 端口号
spring:
  datasource:
    type: com.mysql.cj.jdbc.MysqlDataSource
    username: 数据库账号
    password: 数据库密码
    url: jdbc:mysql://localhost:3306/数据库名?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&allowMultiQueries=true
mybatis-plus:
  global-config:
    banner: off
logging:
  level:
    org.apache.shiro.authc.AbstractAuthenticator: debug

shiro配置

  1. 开启shiro注解支持

    注意:如果不配置这两货,使用shiro的注解时会失效

    @Configuration
    public class ShiroConfig {
        @Bean
        public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
            DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
            defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
            return defaultAdvisorAutoProxyCreator;
        }
        
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
            advisor.setSecurityManager(securityManager);
            return advisor;
        }
    }
    
  2. 配置LifecycleBeanPostProcessor

    @Configuration
    public class ShiroConfig {
        /**
         * 用于管理shiro组件的生命周期
         * @return
         */
        @Bean("lifecycleBeanPostProcessor")
        public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
            return new LifecycleBeanPostProcessor();
        }
    }
    
  3. 配置SecurityManager

    @Configuration
    public class ShiroConfig {
        @Bean("securityManager")
        public SecurityManager securityManager(JdbcRealm jdbcRealm) {
            return new DefaultWebSecurityManager(jdbcRealm);
        }
    }
    
  4. 配置Realm

    注意1:由于我使用的是内置的JDBCRealm实现认证逻辑的,所以配置了数据源,在springboot的yml文件中配置好数据源,直接注入就好

    注意2:认证逻辑可以查看JDBCRealm中的doGetAuthenticationInfo方法,JDBCRealm默认查询的表是users(用户表)、user_roles(用户角色表)、roles_permissions(角色权限表)这三张表。如果你的表名不同,修改对应的sql(以下配置中又修改示例);

    注意3:realm可以自定义,也可以选择其他Realm。

        @Bean("jdbcRealm")
        public JdbcRealm jdbcRealm() {
            JdbcRealm jdbcRealm = new JdbcRealm();
            //修改查询用户的sql
            String authenticationQuery = "select password from sys_user where username = ?";
            //修改查询用户角色的sql
            String userRolesQuery = "select t2.role_id from sys_user t1,sys_user_role t2 where t1.user_id = t2.user_id and t1.username = ?";
            //修改查询角色权限的sql
            String permissionsQuery = "select perms from sys_menu t1,sys_role_menu t2 where t1.menu_id = t2.menu_id and role_id = ?";
            //设置允许查询权限(默认是false)
            jdbcRealm.setPermissionsLookupEnabled(true);
            jdbcRealm.setAuthenticationQuery(authenticationQuery);
            jdbcRealm.setUserRolesQuery(userRolesQuery);
            jdbcRealm.setPermissionsQuery(permissionsQuery);
            //设置数据源
            jdbcRealm.setDataSource(dataSource);
            return jdbcRealm;
        }
    
  5. 配置过滤器链

    @Configuration
    public class ShiroConfig {
        @Bean("shiroFilter")
        public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
            ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
            Map<String, String> filterMap = new LinkedHashMap<>();
            filterMap.put("/shiro/first", "anon");//设置不需要认证的url
            filterMap.put("/**","authcBasic");//设置需要Basic方式认证的url
            shiroFilter.setFilterChainDefinitionMap(filterMap);
            shiroFilter.setSecurityManager(securityManager);
            shiroFilter.setGlobalFilters(Arrays.asList("noSessionCreation"));//设置无状态服务(禁用会话)
            return shiroFilter;
        }
    }
    
  6. 整体的配置如下:

    @Configuration
    public class ShiroConfig {
        @Autowired
        private DataSource dataSource;
    
        /**
         * 用于管理shiro组件的生命周期
         *
         * @return
         */
        @Bean("lifecycleBeanPostProcessor")
        public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
            return new LifecycleBeanPostProcessor();
        }
    
        @Bean("jdbcRealm")
        public JdbcRealm jdbcRealm() {
            JdbcRealm jdbcRealm = new JdbcRealm();
            //修改查询用户的sql
            String authenticationQuery = "select password from sys_user where username = ?";
            //修改查询用户角色的sql
            String userRolesQuery = "select t2.role_id from sys_user t1,sys_user_role t2 where t1.user_id = t2.user_id and t1.username = ?";
            //修改查询角色权限的sql
            String permissionsQuery = "select perms from sys_menu t1,sys_role_menu t2 where t1.menu_id = t2.menu_id and role_id = ?";
            //设置允许查询权限(默认是false)
            jdbcRealm.setPermissionsLookupEnabled(true);
            jdbcRealm.setAuthenticationQuery(authenticationQuery);
            jdbcRealm.setUserRolesQuery(userRolesQuery);
            jdbcRealm.setPermissionsQuery(permissionsQuery);
            //设置数据源
            jdbcRealm.setDataSource(dataSource);
            return jdbcRealm;
        }
    
        @Bean("securityManager")
        public SecurityManager securityManager(JdbcRealm jdbcRealm) {
            return new DefaultWebSecurityManager(jdbcRealm);
        }
    
    
        @Bean("shiroFilter")
        public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
            ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
            Map<String, String> filterMap = new LinkedHashMap<>();
            filterMap.put("/shiro/anon", "anon");//设置不需要认证的url
            filterMap.put("/**", "authcBasic");//设置需要Basic方式认证的url
            shiroFilter.setFilterChainDefinitionMap(filterMap);
            shiroFilter.setSecurityManager(securityManager);
            shiroFilter.setGlobalFilters(Arrays.asList("noSessionCreation"));//设置无状态服务(禁用会话)
            return shiroFilter;
        }
    
    
        @Bean
        public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
            DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator=new DefaultAdvisorAutoProxyCreator();
            defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
            return defaultAdvisorAutoProxyCreator;
        }
    
        @Bean
        public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
            AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
            advisor.setSecurityManager(securityManager);
            return advisor;
        }
    
    }
    
    

异常处理配置

@ControllerAdvice
@Slf4j
public class ExceptionHandlerConfig {
    @ExceptionHandler(AuthorizationException.class)
    @ResponseBody
    public String handleException(AuthorizationException e) {
        log.info("AuthorizationException was thrown", e);
        return "授权失败";
    }

    @ExceptionHandler(AuthenticationException.class)
    @ResponseBody
    public String handleException(AuthenticationException e) {
        log.info("AuthenticationException was thrown", e);
        return "登录失败";
    }
}

测试类(controller)

@RestController
@RequestMapping("/shiro")
public class ShiroController {
    @GetMapping("/anon")
    public String anon() {
        return "不需要认证授权的url";
    }

    @GetMapping("/authentication")
    public String authentication() {
        return "认证成功";
    }

    @RequiresPermissions("sys:perm:read")
    @GetMapping("/permRead")
    public String permRead() {
        return "授权:读";
    }

    @RequiresPermissions("sys:perm:write")
    @GetMapping("/permWrite")
    public String permWrite() {
        return "授权:写";
    }

    //这里是角色id
    @RequiresRoles("1")
    @GetMapping("/roleSys")
    public String roleSys() {
        return "授权:系统管理员";
    }

    //这里是角色id
    @RequiresRoles("2")
    @GetMapping("/roleCom")
    public String roleCom() {
        return "授权:普通管理员";
    }

    //用户的信息
    @GetMapping("/info")
    public String info() {
        Subject subject = SecurityUtils.getSubject();
        Object principal = subject.getPrincipal();
        boolean role1 = subject.hasRole("1");
        boolean role2 = subject.hasRole("2");
        boolean write = subject.isPermitted("sys:perm:write");
        boolean read = subject.isPermitted("sys:perm:read");
        return "principal :" + principal + " write:" + write + " read:" + read + " role1:" + role1 + " role2:" + role2;
    }
}

测试

**注意1:**可以使用postman测试,也可以直接浏览器测试。博主图方便直接浏览器测试了
**注意2:**测试的用户名test002,该用户是普通管理员角色(角色id为2),只有读的权限没有写的权限

  • 验证不需要认证的url:shiro/anon
    shiro/anon
  • 验证需要认证的url:shiro/authentication
    shiro/authentication
  • 验证需要特定角色才能访问的url:shiro/roleSysshiro/roleCom
    shiro/roleSys
    shiro/roleCom
  • 验证需要特定权限才能访问的url(前提已经认证,如果没有认证需要先认证,也就是登录):shiro/permReadshiro/permWrite
    shiro/permRead
    shiro/permWrite
  • 获取用户的基本信息(前提已经认证,如果没有认证需要先认证,也就是登录):shiro/info
    shiro/info

源码

最后贴出源码,希望给个赞!谢谢

在Linux系统下,我们可以使用Docker来部署Spring Boot 3和JDK 17。 首先,我们需要在Linux中安装Docker。可以根据具体的Linux发行版来选择不同的安装方式。安装完成后,我们可以通过运行以下命令来验证Docker安装是否成功: ``` docker --version ``` 接下来,我们需要创建一个Docker镜像来运行我们的Spring Boot 3应用程序。首先,我们需要创建一个Dockerfile,可以使用任何文本编辑器来创建一个名为“Dockerfile”的文件。在Dockerfile中,我们可以定义我们的镜像的构建过程。以下是一个简单的Dockerfile示例: ``` FROM openjdk:17-jdk-alpine WORKDIR /app COPY target/springboot3-app.jar /app CMD ["java", "-jar", "springboot3-app.jar"] ``` 在这个Dockerfile中,我们首先选择了一个基础镜像(openjdk:17-jdk-alpine),其中包含了JDK 17的安装。然后,我们定义了工作目录为“/app”,将Spring Boot 3应用程序的JAR文件复制到工作目录中,并使用CMD命令定义了镜像启动时要运行的命令。 在创建了Dockerfile后,我们可以使用以下命令来构建Docker镜像: ``` docker build -t springboot3-app . ``` 这将会在当前目录下构建一个名为“springboot3-app”的Docker镜像。 最后,我们可以使用以下命令来运行我们的应用程序容器: ``` docker run -p 8080:8080 springboot3-app ``` 这将会将容器的8080端口映射到主机的8080端口,并运行我们的Spring Boot 3应用程序。 通过以上步骤,我们可以在Linux系统中使用Docker快速部署和运行Spring Boot 3和JDK 17
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值