spring security 初探(不建议)
总体来说,比shiro要简单的多。这篇文章不好,用到的数据库不适合,看springsecurity的第2篇
https://www.cnblogs.com/zhengqing/p/11670991.html
1. 建立springboot项目,加入spring security的pom。
2. 写配置类,config。
3. 写web的控制器。
4. 写jsp页面
5. 数据库表共5个,
pom
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
配置类
继承web安全配置适配器类,enableGlobalMethodSecurity开启拦截,建立内存用户,用BCrypt动态加密,重写http的配置方法
package cn.taotao.config; @Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) // 开启拦截 public class security extends WebSecurityConfigurerAdapter { @Override @Bean public UserDetailsService userDetailsServiceBean() throws Exception { //return super.userDetailsServiceBean(); InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
// 给用户分配p1资源权限,配合控制器的注解来实现 manager.createUser(User.withUsername("xuyong").password("$2a$10$zBZTNl3yYKoAkH446zbz2OscgPIZ8lMSisSpZs2GFgUrHSM7JlySW").authorities("p1").build()); return manager; } @Bean public PasswordEncoder passwordEncoder(){ //return NoOpPasswordEncoder.getInstance(); return new BCryptPasswordEncoder(); }
// 重写配置类,关键,配置登录的页面,退出的页面 @Override protected void configure(HttpSecurity http) throws Exception { // super.configure(http); http.authorizeRequests()
// .antMatchers("/r/r1").hasAuthority("p1") 这段代码可以在控制器注解中指定 .antMatchers("/**").authenticated() .anyRequest().permitAll() .and() .formLogin() .loginPage("/login-view") .loginProcessingUrl("/login") .successForwardUrl("/login-success") .permitAll() .and() .logout() .logoutUrl("/logout") .logoutSuccessUrl("/login-view") // .logoutRequestMatcher(new AntPathRequestMatcher("logout","GET")) 实现logout,避免csrf报404错误 .permitAll() ; } }
测试类代码,产生Bcrypt的密码
@Test void Bcrty(){ String hashpw = BCrypt.hashpw("123", BCrypt.gensalt()); System.out.println("hashpw:"+ hashpw); // boolean checkpw = BCrypt.checkpw("123", "$2a$10$dbdH8C7VoyCAlJaOAuxZluUTqUNbyi4PHsWi24Y.Uaa2bCwsfOkWG"); // $2a$10$6UWJCso9Z4dBpYjeJH.p8emRO/.UBSdgH1Opyo1mc7QSmvXt28Nxa }
控制器
@Controller public class IndexController { @RequestMapping("/") @ResponseBody public String index() { return "index"; } @ResponseBody @RequestMapping("/r/r1") @PreAuthorize("hasAuthority('p1')") // 实现p1的控制权限 public String r1() { return "r1"; } @ResponseBody @RequestMapping("/r/r2") @PreAuthorize("hasAuthority('p2')") public String r2(){ return "r2"; } @RequestMapping("/login-success") public String loginsuccess(){ return "login-success"; } @RequestMapping("/login-view") public String loginView(){ return "login-view"; } @RequestMapping("/logout-view") public String logout(){ return "logout"; } }
代码html登录页面
<form action="login" method="post" > <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"> username : <input type="text" name="username"> ps:<input type="password" name="password"> <input type="submit"> </form>
#########################################
改造为sql版,建立5张表,
/* SQLyog Ultimate v11.27 (32 bit) MySQL - 5.7.33 : Database - security ********************************************************************* */ /*!40101 SET NAMES utf8 */; /*!40101 SET SQL_MODE=''*/; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; CREATE DATABASE /*!32312 IF NOT EXISTS*/`security` /*!40100 DEFAULT CHARACTER SET utf8 */; USE `security`; /*Table structure for table `t_permission` */ DROP TABLE IF EXISTS `t_permission`; CREATE TABLE `t_permission` ( `id` varchar(32) NOT NULL, `code` varchar(32) DEFAULT NULL, `description` varchar(64) DEFAULT NULL, `url` varchar(128) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*Data for the table `t_permission` */ insert into `t_permission`(`id`,`code`,`description`,`url`) values ('1','p1','测试资源1','/r/r1'),('2','p3','测试资源2','/r/r2'); /*Table structure for table `t_role` */ DROP TABLE IF EXISTS `t_role`; CREATE TABLE `t_role` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `role_name` varchar(255) DEFAULT NULL, `description` varchar(255) DEFAULT NULL, `create_time` datetime DEFAULT NULL, `update_time` datetime DEFAULT NULL, `status` char(1) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*Data for the table `t_role` */ /*Table structure for table `t_role_permission` */ DROP TABLE IF EXISTS `t_role_permission`; CREATE TABLE `t_role_permission` ( `role_id` varchar(128) NOT NULL, `permission_id` varchar(128) NOT NULL, PRIMARY KEY (`role_id`,`permission_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*Data for the table `t_role_permission` */ /*Table structure for table `t_user` */ DROP TABLE IF EXISTS `t_user`; CREATE TABLE `t_user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(255) DEFAULT NULL, `password` varchar(255) DEFAULT NULL, `fullname` varchar(255) DEFAULT NULL, `mobile` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*Data for the table `t_user` */ /*Table structure for table `t_user_role` */ DROP TABLE IF EXISTS `t_user_role`; CREATE TABLE `t_user_role` ( `user_id` varchar(32) NOT NULL, `role_id` varchar(32) NOT NULL, `create_time` datetime DEFAULT NULL, `creator` varchar(255) DEFAULT NULL, PRIMARY KEY (`user_id`,`role_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; /*Data for the table `t_user_role` */ /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
建立这个包,需要屏蔽掉上面第一段中的config 中的UserDetailsService,另外新建类,从数据库中根据id查找权限,得到的是list,然后把list转换为数组,生成UserDetails,返回。
package com.itheima.security.springboot.service; import com.itheima.security.springboot.dao.UserDao; import com.itheima.security.springboot.model.UserDto; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.User; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import java.util.List; /** * @author Administrator * @version 1.0 **/ @Service public class SpringDataUserDetailsService implements UserDetailsService { @Autowired UserDao userDao; //根据 账号查询用户信息 @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { //将来连接数据库根据账号查询用户信息 UserDto userDto = userDao.getUserByUsername(username); if(userDto == null){ //如果用户查不到,返回null,由provider来抛出异常 return null; } //根据用户的id查询用户的权限 List<String> permissions = userDao.findPermissionsByUserId(userDto.getId()); //将permissions转成数组 String[] permissionArray = new String[permissions.size()]; permissions.toArray(permissionArray); UserDetails userDetails = User.withUsername(userDto.getUsername()).password(userDto.getPassword()).authorities(permissionArray).build(); return userDetails; } }
另外需要一个dto的包,对应于上面的那个userDao的查找权限方法
package com.itheima.security.springboot.dao; import com.itheima.security.springboot.model.PermissionDto; import com.itheima.security.springboot.model.UserDto; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import java.util.ArrayList; import java.util.List; /** * @author Administrator * @version 1.0 **/ @Repository public class UserDao { @Autowired JdbcTemplate jdbcTemplate; //根据账号查询用户信息 public UserDto getUserByUsername(String username){ String sql = "select id,username,password,fullname,mobile from t_user where username = ?"; //连接数据库查询用户 List<UserDto> list = jdbcTemplate.query(sql, new Object[]{username}, new BeanPropertyRowMapper<>(UserDto.class)); if(list !=null && list.size()==1){ return list.get(0); } return null; } //根据用户id查询用户权限 public List<String> findPermissionsByUserId(String userId){ String sql = "SELECT * FROM t_permission WHERE id IN(\n" + "\n" + "SELECT permission_id FROM t_role_permission WHERE role_id IN(\n" + " SELECT role_id FROM t_user_role WHERE user_id = ? \n" + ")\n" + ")\n"; List<PermissionDto> list = jdbcTemplate.query(sql, new Object[]{userId}, new BeanPropertyRowMapper<>(PermissionDto.class)); List<String> permissions = new ArrayList<>(); list.forEach(c -> permissions.add(c.getCode())); return permissions; } }