SpringBoot配置security权限管理
gitee:SpringBoot配置security权限管理
数据库表结构在gitee上面有
1. 目录结构
2. maven依赖
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.3.RELEASE</version></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><mybatis.version>2.0.1.RELEASE</mybatis.version><mysql.version>5.1.47</mysql.version></properties><dependencies><!-- 以下是>spring boot依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 以下是>spring security依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!-- 以下是jsp依赖--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><scope>provided</scope></dependency><!--jsp页面使用jstl标签 --><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId><scope>provided</scope></dependency><!--用于编译jsp --><dependency><groupId>org.apache.tomcat.embed</groupId><artifactId>tomcat-embed-jasper</artifactId><scope>provided</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>io.easybest</groupId><artifactId>spring-data-mybatis-boot-starter</artifactId><version>${mybatis.version}</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>${mysql.version}</version></dependency></dependencies>
3.配置文件application.yaml
server:port:8080servlet:context-path: /# 配置试图解析器地址,前后缀spring:application:name: springboot-securitymvc:view:prefix: /WEB-INF/view/suffix: .jspdatasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/spring_securityusername: rootpassword: root
4.entity
用户信息表实体
importlombok.Data;/**
* @author 黔程似景
* @description 用户信息表
* @date 2021/12/11 14:40
**/@DatapublicclassUserDto{privateInteger id;privateString username;privateString password;privateString mobile;}
权限表实体
importlombok.Data;/**
* @author 黔程似景
* @description 权限表
* @date 2021/12/11 14:54
**/@DatapublicclassPermissionDto{privateString id;privateString code;privateString description;privateString url;}
5.配置类
配置登录页面WebConfig
importorg.springframework.context.annotation.Configuration;importorg.springframework.web.servlet.config.annotation.ViewControllerRegistry;importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;/**
* @author 黔程似景
* @description 配置web启动器
* @date 2021/12/11 12:55
**/@ConfigurationpublicclassWebConfigimplementsWebMvcConfigurer{/**
* 重写视图
* @param registry 视图控制
*/@OverridepublicvoidaddViewControllers(ViewControllerRegistry registry){//使用security自带的登录页面
registry.addViewController("/").setViewName("redirect:/login");//自定义登录页面// registry.addViewController("/").setViewName("redirect:/login-view");// registry.addViewController("/login-view").setViewName("/login");}}
配置用户认证权限管理WebSecurityConfig
importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importorg.springframework.security.authentication.dao.DaoAuthenticationProvider;importorg.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;importorg.springframework.security.config.annotation.web.builders.HttpSecurity;importorg.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;importorg.springframework.security.core.userdetails.UserDetailsService;importorg.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;importorg.springframework.security.crypto.password.PasswordEncoder;importjavax.annotation.Resource;/**
* @author 黔程似景
* @description 配置security权限认证
* @date 2021/12/11 13:00
**/@Configuration@EnableGlobalMethodSecurity(securedEnabled=true, prePostEnabled=true)//开启权限注解扫描publicclassWebSecurityConfigextendsWebSecurityConfigurerAdapter{@ResourceprivateUserDetailsService userDetailsService;/**
* 密码编码器
* 1. 不使用加密算法 NoOpPasswordEncoder.getInstance()
* @return 加密编码格式
*/@BeanpublicPasswordEncoderpasswordEncoder(){returnnewBCryptPasswordEncoder();}/**
* 将密码编码器交给UserDetailsService进行使用
*/@BeanpublicDaoAuthenticationProviderdaoAuthenticationProvider(){DaoAuthenticationProvider daoAuthenticationProvider=newDaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
daoAuthenticationProvider.setUserDetailsService(userDetailsService);return daoAuthenticationProvider;}/**
* 安全拦截机制
*/@Overrideprotectedvoidconfigure(HttpSecurity http)throwsException{
http.exceptionHandling().accessDeniedPage("/error.html");//配置没有权限访问跳转的自定义页面
http.csrf().disable()//需要屏蔽掉csrf安全机制,也可以在前端进行屏蔽.authorizeRequests().antMatchers("/r/**").authenticated()//所有/r/**的请求必须通过认证(必须在子配置之后,否则会出现经过此次权限认证后,不在进行验证).anyRequest().permitAll()//除了/r/**的都可以不认证访问.and().formLogin()//允许表单登录// .loginPage("/login-view")//使用自带的不需要在指定登录页面.loginProcessingUrl("/login").successForwardUrl("/login-success").defaultSuccessUrl("/login-success")//自定义退出.and().logout().logoutUrl("/logout")//配置退出地址// .logoutSuccessUrl("/login-view?logout");//退出成功返回页面(使用自带的,删除此行)}}
6.mapper
importcom.qq.entity.PermissionDto;importcom.qq.entity.UserDto;importorg.apache.ibatis.annotations.Param;importorg.apache.ibatis.annotations.Select;importjava.util.List;/**
* @author 黔程似景
* @description 用户mapper
* @date 2021/12/11 14:37
**/publicinterfaceUserMapper{/**
* 根据用户名查询用户信息,只取第一条
*
* @param username 用户名
* @return 用户详情
*/@Select("SELECT * FROM t_user WHERE username = #{username} ORDER BY id ASC LIMIT 1")UserDtogetUserDtoByUsername(@Param("username")String username);/**
* 获取用户权限
*/@Select("SELECT * FROM t_permission WHERE id in ("+"SELECT permission_id from t_role_permission WHERE role_id in ("+"SELECT role_id FROM t_user_role WHERE user_id = #{userId}"+")"+")")List<PermissionDto>getPermissionListByUserId(@Param("userId")Integer userId);}
7.service
importcom.qq.entity.PermissionDto;importcom.qq.entity.UserDto;importcom.qq.mapper.UserMapper;importorg.springframework.security.core.userdetails.User;importorg.springframework.security.core.userdetails.UserDetails;importorg.springframework.security.core.userdetails.UserDetailsService;importorg.springframework.security.core.userdetails.UsernameNotFoundException;importorg.springframework.stereotype.Service;importjavax.annotation.Resource;importjava.util.ArrayList;importjava.util.List;/**
* @author 黔程似景
* @description 进行用户信息注入,权限注入操作
* @date 2021/12/12 9:42
**/@ServicepublicclassUserDetailsServiceImplimplementsUserDetailsService{@ResourceprivateUserMapper userMapper;@OverridepublicUserDetailsloadUserByUsername(String username)throwsUsernameNotFoundException{//根据用户名获取用户信息UserDto userDto= userMapper.getUserDtoByUsername(username);//权限String[] permissionArray=this.getPermissionList(userDto.getId());//设置返回值UserDetails userDetails=null;if(userDto!=null){
userDetails=User.withUsername(username).password(userDto.getPassword()).authorities(permissionArray).build();}return userDetails;}/**
* 获取权限数组
*/privateString[]getPermissionList(Integer userId){List<PermissionDto> permissionDtoList= userMapper.getPermissionListByUserId(userId);List<String> permissionList=newArrayList<>();if(permissionDtoList!=null){
permissionDtoList.forEach(permissionDto-> permissionList.add(permissionDto.getCode()));}String[] permissionArray= permissionList.toArray(newString[]{});return permissionArray;}}
8.controller
importorg.springframework.security.access.prepost.PreAuthorize;importorg.springframework.security.core.Authentication;importorg.springframework.security.core.context.SecurityContextHolder;importorg.springframework.security.core.userdetails.UserDetails;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.RestController;/**
* @author 黔程似景
* @description 有关于登录,测试接口
* @date 2021/12/11 13:17
**/@RestControllerpublicclassLoginController{@GetMapping("/login-success")publicStringloginSuccess(){//提示登录成功return"登录成功!";}@GetMapping("/r/r1")@PreAuthorize("hasAnyAuthority('p1')")//拥有P1权限才可以访问publicStringr1(){returngetUserName()+"访问资源1";}@GetMapping("/r/r2")@PreAuthorize("hasAnyAuthority('p2')")//拥有P2权限才可以访问publicStringr2(){returngetUserName()+"访问资源2";}//获取当前用户信息privateStringgetUserName(){String username;//当前认证通过的用户信息Authentication authentication=SecurityContextHolder.getContext().getAuthentication();//用户身份Object principal= authentication.getPrincipal();if(principal==null){
username="匿名";}if(principalinstanceofUserDetails){UserDetails userDetails=(UserDetails) principal;
username= userDetails.getUsername();}else{
username= principal.toString();}return username;}}
9.自定义登录页面
登录页面
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="utf-8" %>
<html>
<head>
<title>用户登录</title>
</head>
<body>
<form action="login" method="post">
用户名:<input type="text" name="username"><br>
密 码:
<input type="password" name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
权限不足页面
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="utf-8" %>
<html>
<head>
<title>不拥有此权限</title>
</head>
<body>
<h5>权限不够!联系管理员</h5>
</body>
</html>
10.启动类
importorg.mybatis.spring.annotation.MapperScan;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;/**
* springboot项目 启动类
*/@SpringBootApplication@MapperScan("com.qq.mapper")publicclassSecurityApplication{public