权限目前最常用的有两种,一种就是 Apache Shiro ,另一种是 Spring Security。其实两种权限框架都是大同小异,会其中一种就很好学习另外一种;今天就讲解一下 Spring 的 Security;

security搭建(Security权限入门文档)(1)

首先说一下常见的表关系

一对一

如果两张表存在一对一的关系,即A表 name,pic ,mail,age 中的一条数据最多只对应B表(公司,住址,户籍(频率低),详情介绍(大))中的一条数据,反之亦然。此时完全可以设计成一张表。

即使可以合成一张表,在有些公司中还是有分成两张表的情况。


一对多

学校与班级就是一对多的关系 多的一方使用外键维护关系

大学中,学生与课程的关系就是多对多,一个学生可以正在学习多门课程,一门课程也可以有多个学生正在学习。


多对多

大学中,学生与课程的关系就是多对多,一个学生可以正在学习多门课程,一门课程也可以有多个学生正在学习。


准备数据库表
  1. 用户表
  2. 角色表
  3. 用户_角色 中间表
  4. 权限表
  5. 角色_权限 中间表

初步接触

1.导包

<!-- security 权限包 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>

2.准备 Controller

@Controller public class LoginController extends BaseController { @RequestMapping("/index") @ResponseBody public String indexLogin(){ return "老蔫~关注一波!"; }

3.配置yml

spring: security: user: name: laonian password: 123456

4.访问测试 (直接 访问 我这里是 http://localhost/login)

security搭建(Security权限入门文档)(2)

这个登录密码是自带的

security搭建(Security权限入门文档)(3)

security搭建(Security权限入门文档)(4)

这 就是简易演示登录效果,就是你导包,security 会自动装配 ,但是现实项目中 肯定不会这么搞,不可能在 yml 配置账户密码,也可以存在内存中在配置类中搭配账户密码 ,但也有意义,写在代码里 没啥卵用;所以要修改


正式版(从数据库读取用户信息)

1.pom.xml

<!-- security 权限包 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.20</version> <scope>provided</scope> </dependency> <!--数据库驱动,可根据自己需要自行删减--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql-connector-java.version}</version> </dependency> <!--spring boot依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>


2.到了mybatis 就要搭配数据源 yml

# Mysql数据库 spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/user?autoReconnect=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL&useSSL=false&serverTimezone=CTT username: root password: 121212 filters: wall,mergeStat data-source-name: gunsdb mybatis-plus: configuration: map-underscore-to-camel-case: true # 是否开启自动驼峰命名 # xml 扫描 可用逗号或斜杠 分隔(告诉Mapper 所对应的XML文件位置) mapper-locations: classpath:cn/zx/modular/mapper/xml/*.xml,classpath:cn/zx/modular/mapper/xml/*.xml global-config: db-config: id-type: auto # 主键类型 AUTO:数据库ID自增 type-aliases-package: cn.zx.modular.entity #MyBaits 别名包扫描路径,通过该属性可以给包中的类注册别名


3.启动类

/** * SpringBoot启动类 * * @SpringBootApplication 自动扫描 cn.zx 下的所有包 (package cn.zx) * @Componentscan 指定扫描 * @EnableAutoConfiguration 开启自动扫描 */ @SpringBootApplication(exclude = {WebAutoConfiguration.class}) @EnableScheduling @EnableCaching public class GunsApplication { private final static Logger logger = LoggerFactory.getLogger(GunsApplication.class); /** * 启动方法 */ public static void main(String[] args) { SpringApplication.run(GunsApplication.class,args); logger.info(GunsApplication.class.getSimpleName() " is success !"); } }


4.用户实体类

/** * 用户表 * * easypoi excel 操作 * @Excel: 代表这个字段要生成到excel中去 * @name: 这个excel的表头名称 * @width: 这一列的宽度设置 * * * Serializable * Serializable接口是启用其序列化功能的接口。实现java.io.Serializable 接口的类是可序列化的。没有实现此接口的类将不能使它们的任意状态被序列化或逆序列化。 * 1、存储对象在存储介质中,以便在下次使用的时候,可以很快捷的重建一个副本;2、便于数据传输,尤其是在远程调用的时候。 * UserDetails * security 核心包里的,不管你用户名字段叫什么,只管你在getUsername把你的用户名字段返回去。去掉差异化, */ @Data @TableName("user") public class UserPo implements Serializable , UserDetails { /** 用户ID */ private Long id; /** 账户 */ private String userName; /** 用户密码 */ private String password; /** 盐值 */ private String salt; @Excel(name = "用户名称") private String name; @Excel(name = "电话号",width = 20) private String phone; @Excel(name = "邮件",width = 20) private String email; /** type 1-文本 2-图片 3-函数 10-数字 默认文本 */ @Excel(name = "头像",type = 2,width = 20) private String portrait; /** 时间格式 */ @Excel(name = "生日",format = "yyyy-MM-dd") private String birthday; /** true - 男 false - 女 */ @Excel(name = "性别",replace = {"男_true","女_false"}) private Boolean sex; /** 1-启用 2-禁用 3-违规 */ @Excel(name = "账号状态") private int status; /** 一对多的情况 比如部门等 */ @ExcelEntity private Level level; /** 创建时间 */ @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(shape = JsonFormat.Shape.STRING,pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT 8") private String crateDate; /** * <? extends GrantedAuthority> 表示 Collection 装GrantedAuthority子类 * <? super GrantedAuthority> 表示 Collection 装GrantedAuthority父类 * */ @Override public Collection<? extends GrantedAuthority> getAuthorities() { return null; } /** 获取用户名 */ @Override public String getUsername() { return this.userName; } /** 看账号是否未过期 */ @Override public boolean isAccountNonExpired() { return true; } /** 是否未锁定*/ @Override public boolean isAccountNonLocked() { return true; } /** 证书未过期 */ @Override public boolean isCredentialsNonExpired() { return true; } /** 是否被禁用*/ @Override public boolean isEnabled() { if (this.status != 1){ return false; } return true; } }


5.权限类

/** * @author laonian * @date 2021-12-30 13:27 * 菜单表 */ @TableName("menu") @Data public class Menu implements GrantedAuthority , Serializable { private static final long serialVersionUID = 1L; @TableId(value = "id",type = IdType.ID_WORKER) private Long id; @TableField("code") private String code; private String name; private String status; private Integer type; private String uri; private Date createTime; private Integer sort; @Override public String getAuthority() { return this.uri; } }


6.Mapper

@Mapper public interface UserMapper extends BaseMapper<UserPo> { /** 通过名字查询信息 */ UserPo getUserByName(String name); /** 查询用户所有权限*/ List<Menu> getMenuByUserId(Long userId); }


7.XML

<!-- 通过名字查询信息 --> <select id="getUserByName" resultType="cn.zx.modular.entity.UserPo"> select * from user where user_name = #{name} </select> <!-- 查询用户所有权限 --> <select id="getMenuByUserId" resultType="cn.zx.modular.entity.Menu"> SELECT * FROM menu m WHERE m.id in( SELECT menu_id FROM menu_role WHERE status = 'ENABLE' AND role_id in(SELECT role_id FROM user_role WHERE user_id = #{userId} ) ) </select> </mapper>


8.Service

public interface UserService extends IService<UserPo> { UserPo getUserByName(String name); List<Menu> getMenuByUserId(Long userId); }

@Service public class UserServiceImpl extends ServiceImpl<UserMapper, UserPo> implements UserService { @Resource private UserMapper userMapper; @Override public UserPo getUserByName(String name) { UserPo userByName = userMapper.getUserByName(name); //断言 Assert.isTrue(userByName!=null,"您输入的账户不存在"); return userByName; } @Override public List<Menu> getMenuByUserId(Long userId) { return userMapper.getMenuByUserId(userId); } }


9.自定义 Service 有用户的信息也有用户权限

/** * @author laonian * @date 2021-12-30 19:44 */ @Service("userDetailsService") public class MyUserDetailService implements UserDetailsService { @Autowired UserService userService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { UserPo user = userService.getUserByName(username); List<Menu> menuByUserList = userService.getMenuByUserId(user.getId()); HashSet<Menu> menus = new HashSet<>(menuByUserList); user.setAuthorities(menus); return user; } }


10.重新定义 SecurityConfig

/** * @author laonian * @date 2021-12-30 19:34 */ @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsService userDetailsService; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/css/**", "/js/**", "/fonts/**").permitAll() //都可以访问 .anyRequest().authenticated() // 任何请求都需要认证 .and() .formLogin() //基于Form表单登录验证 .and() .userDetailsService(userDetailsService); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }


11.Controller

@PreAuthorize("hasAuthority('/index')") @RequestMapping("/index") @ResponseBody public String indexLogin(){ return "老蔫~关注一波!"; }


自己试效果吧 大概就算入门了

security搭建(Security权限入门文档)(5)

你的善良必须有点锋芒否则等于零留个关注 么么哒!!!,