springBoot+springSecurity 数据库动态管理用户、角色、权限(二)
序:
本文使用springboot+mybatis+SpringSecurity 实现数据库动态的管理用户、角色、权限管理
本文细分角色和权限,并将用户、角色、权限和资源均采用数据库存储,并且自定义滤器,代替原有的FilterSecurityInterceptor过滤器,
并分别实现AccessDecisionManager、InvocationSecurityMetadataSourceService和UserDetailsService,并在配置文件中进行相应配置。
spring security的简单原理:
使用众多的拦截器对url拦截,以此来管理权限。但是这么多拦截器,笔者不可能对其一一来讲,主要讲里面核心流程的两个。
首先,权限管理离不开登陆验证的,所以登陆验证拦截器AuthenticationProcessingFilter要讲;
还有就是对访问的资源管理吧,所以资源管理拦截器AbstractSecurityInterceptor要讲;
但拦截器里面的实现需要一些组件来实现,所以就有了AuthenticationManager、accessDecisionManager等组件来支撑。
现在先大概过一遍整个流程,用户登陆,会被AuthenticationProcessingFilter拦截,调用AuthenticationManager的实现,而且AuthenticationManager会调用ProviderManager来获取用户验证信息(不同的Provider调用的服务不同,因为这些信息可以是在数据库上,可以是在LDAP服务器上,可以是xml配置文件上等),如果验证通过后会将用户的权限信息封装一个User放到spring的全局缓存SecurityContextHolder中,以备后面访问资源时使用。
访问资源(即授权管理),访问url时,会通过AbstractSecurityInterceptor拦截器拦截,其中会调用FilterInvocationSecurityMetadataSource的方法来获取被拦截url所需的全部权限,在调用授权管理器AccessDecisionManager,这个授权管理器会通过spring的全局缓存SecurityContextHolder获取用户的权限信息,还会获取被拦截的url和被拦截url所需的全部权限,然后根据所配的策略(有:一票决定,一票否定,少数服从多数等),如果权限足够,则返回,权限不够则报错并调用权限不足页面。
重要
本文设计和代码是基于 上一篇博客(请点击)
springboot+mybatis+SpringSecurity 实现用户角色数据库管理
进行修改。
本文目录:
1:数据库表设计
2:权限表的业务
3:springSecurity 配置修改
4:修改home.html 文件
5:修改HomeController.java 文件
6:测试检验
目录结构如下:
1:数据库表设计
由于本文增加了权限表所以本文的数据库表为5个分别是: 用户表、角色表、权限表、用户角色中间表、角色权限中间表
初始化数据
- 注意:Sys_permission 表的url通配符为两颗星,比如说 /user下的所有url,应该写成 /user/**;
- 权限的名字可以随意起名
- insert into SYS_USER (id,username, password) values (1,'admin', 'admin');
- insert into SYS_USER (id,username, password) values (2,'abel', 'abel');
- insert into SYS_ROLE(id,name) values(1,'ROLE_ADMIN');
- insert into SYS_ROLE(id,name) values(2,'ROLE_USER');
- insert into SYS_ROLE_USER(SYS_USER_ID,ROLES_ID) values(1,1);
- insert into SYS_ROLE_USER(SYS_USER_ID,ROLES_ID) values(2,2);
- BEGIN;
- INSERT INTO `Sys_permission` VALUES ('1', 'ROLE_HOME', 'home', '/', null), ('2', 'ROLE_ADMIN', 'ABel', '/admin', null);
- COMMIT;
- BEGIN;
- INSERT INTO `Sys_permission_role` VALUES ('1', '1', '1'), ('2', '1', '2'), ('3', '2', '1');
- COMMIT;
- insert into SYS_USER (id,username, password) values (1,'admin', 'admin');
2:权限表的业务代码
2.1 java bean
Permission.java
- package com.us.example.domain;
- /**
- * Created by yangyibo on 17/1/20.
- */
- public class Permission {
- private int id;
- //权限名称
- private String name;
- //权限描述
- private String descritpion;
- //授权链接
- private String url;
- //父节点id
- private int pid;
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getDescritpion() {
- return descritpion;
- }
- public void setDescritpion(String descritpion) {
- this.descritpion = descritpion;
- }
- public String getUrl() {
- return url;
- }
- public void setUrl(String url) {
- this.url = url;
- }
- public int getPid() {
- return pid;
- }
- public void setPid(int pid) {
- this.pid = pid;
- }
- }
2.2 dao 层
在 com.us.example.dao 包下新建PermissionDao.java 文件。
PermissionDao.java
- package com.us.example.dao;
- import com.us.example.config.MyBatisRepository;
- import com.us.example.domain.Permission;
- import java.util.List;
- /**
- * Created by yangyibo on 17/1/20.
- */
- public interface PermissionDao {
- public List<Permission> findAll();
- public List<Permission> findByAdminUserId(int userId);
- }
- package com.us.example.dao;
在src/resource/mapper目录下新建对应的mapper.xml 文件
PermissionDaoMapper.xml
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
- <mapper namespace="com.us.example.dao.PermissionDao">
- <select id="findAll" resultType="com.us.example.domain.Permission">
- SELECT * from Sys_permission ;
- </select>
- <select id="findByAdminUserId" parameterType="int" resultType="com.us.example.domain.Permission">
- select p.*
- from Sys_User u
- LEFT JOIN sys_role_user sru on u.id= sru.Sys_User_id
- LEFT JOIN Sys_Role r on sru.Sys_Role_id=r.id
- LEFT JOIN Sys_permission_role spr on spr.role_id=r.id
- LEFT JOIN Sys_permission p on p.id =spr.permission_id
- where u.id=#{userId}
- </select>
- </mapper>
- <?xml version="1.0" encoding="UTF-8" ?>
3:springSecurity 配置修改
3.1 修改 WebSecurityConfig.java
修改com.us.example.config包下的 WebSecurityConfig.java 文件如下:
- package com.us.example.config;
- import com.us.example.service.CustomUserService;
- import com.us.example.service.MyFilterSecurityInterceptor;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
- import org.springframework.security.config.annotation.web.builders.HttpSecurity;
- import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
- import org.springframework.security.core.userdetails.UserDetailsService;
- import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
- /**
- * Created by yangyibo on 17/1/18.
- */
- @Configuration
- @EnableWebSecurity
- public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
- @Autowired
- private MyFilterSecurityInterceptor myFilterSecurityInterceptor;
- @Bean
- UserDetailsService customUserService(){ //注册UserDetailsService 的bean
- return new CustomUserService();
- }
- @Override
- protected void configure(AuthenticationManagerBuilder auth) throws Exception {
- auth.userDetailsService(customUserService()); //user Details Service验证
- }
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http.authorizeRequests()
- .anyRequest().authenticated() //任何请求,登录后可以访问
- .and()
- .formLogin()
- .loginPage("/login")
- .failureUrl("/login?error")
- .permitAll() //登录页面用户任意访问
- .and()
- .logout().permitAll(); //注销行为任意访问
- http.addFilterBefore(myFilterSecurityInterceptor, FilterSecurityInterceptor.class);
- }
- }
3.2 修改CustomUserService
修改CustomUserService.java 内容如下:
- package com.us.example.service;
- import com.us.example.dao.PermissionDao;
- import com.us.example.dao.UserDao;
- import com.us.example.domain.Permission;
- import com.us.example.domain.SysRole;
- import com.us.example.domain.SysUser;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.security.core.GrantedAuthority;
- import org.springframework.security.core.authority.SimpleGrantedAuthority;
- 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.ArrayList;
- import java.util.List;
- /**
- * Created by yangyibo on 17/1/18.
- */
- @Service
- public class CustomUserService implements UserDetailsService { //自定义UserDetailsService 接口
- @Autowired
- UserDao userDao;
- @Autowired
- PermissionDao permissionDao;
- public UserDetails loadUserByUsername(String username) {
- SysUser user = userDao.findByUserName(username);
- if (user != null) {
- List<Permission> permissions = permissionDao.findByAdminUserId(user.getId());
- List<GrantedAuthority> grantedAuthorities = new ArrayList <>();
- for (Permission permission : permissions) {
- if (permission != null && permission.getName()!=null) {
- GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getName());
- //1:此处将权限信息添加到 GrantedAuthority 对象中,在后面进行全权限验证时会使用GrantedAuthority 对象。
- grantedAuthorities.add(grantedAuthority);
- }
- }
- return new User(user.getUsername(), user.getPassword(), grantedAuthorities);
- } else {
- throw new UsernameNotFoundException("admin: " + username + " do not exist!");
- }
- }
- }
3.3 新增MyAccessDecisionManager
在com.us.example.service 包下新增
MyAccessDecisionManager.java 文件
- package com.us.example.service;
- import org.springframework.security.access.AccessDecisionManager;
- import org.springframework.security.access.AccessDeniedException;
- import org.springframework.security.access.ConfigAttribute;
- import org.springframework.security.authentication.InsufficientAuthenticationException;
- import org.springframework.security.core.Authentication;
- import org.springframework.security.core.GrantedAuthority;
- import org.springframework.stereotype.Service;
- import java.util.Collection;
- import java.util.Iterator;
- /**
- * Created by yangyibo on 17/1/19.
- */
- @Service
- public class MyAccessDecisionManager implements AccessDecisionManager {
- // decide 方法是判定是否拥有权限的决策方法,
- //authentication 是释CustomUserService中循环添加到 GrantedAuthority 对象中的权限信息集合.
- //object 包含客户端发起的请求的requset信息,可转换为 HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
- //configAttributes 为MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法返回的结果,此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。
- @Override
- public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
- if(null== configAttributes || configAttributes.size() <=0) {
- return;
- }
- ConfigAttribute c;
- String needRole;
- for(Iterator<ConfigAttribute> iter = configAttributes.iterator(); iter.hasNext(); ) {
- c = iter.next();
- needRole = c.getAttribute();
- for(GrantedAuthority ga : authentication.getAuthorities()) {//authentication 为在注释1 中循环添加到 GrantedAuthority 对象中的权限信息集合
- if(needRole.trim().equals(ga.getAuthority())) {
- return;
- }
- }
- }
- throw new AccessDeniedException("no right");
- }
- @Override
- public boolean supports(ConfigAttribute attribute) {
- return true;
- }
- @Override
- public boolean supports(Class<?> clazz) {
- return true;
- }
- }
3.4 新增 MyFilterSecurityInterceptor
在com.us.example.service 包下新增
MyFilterSecurityInterceptor.java 文件
- package com.us.example.service;
- import javax.servlet.Filter;
- import javax.servlet.FilterChain;
- import javax.servlet.FilterConfig;
- import javax.servlet.ServletException;
- import javax.servlet.ServletRequest;
- import javax.servlet.ServletResponse;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.security.access.SecurityMetadataSource;
- import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
- import org.springframework.security.access.intercept.InterceptorStatusToken;
- import org.springframework.security.web.FilterInvocation;
- import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
- import org.springframework.stereotype.Service;
- import java.io.IOException;
- /**
- * Created by yangyibo on 17/1/19.
- */
- @Service
- public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {
- @Autowired
- private FilterInvocationSecurityMetadataSource securityMetadataSource;
- @Autowired
- public void setMyAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager) {
- super.setAccessDecisionManager(myAccessDecisionManager);
- }
- @Override
- public void init(FilterConfig filterConfig) throws ServletException {
- }
- @Override
- public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
- FilterInvocation fi = new FilterInvocation(request, response, chain);
- invoke(fi);
- }
- public void invoke(FilterInvocation fi) throws IOException, ServletException {
- //fi里面有一个被拦截的url
- //里面调用MyInvocationSecurityMetadataSource的getAttributes(Object object)这个方法获取fi对应的所有权限
- //再调用MyAccessDecisionManager的decide方法来校验用户的权限是否足够
- InterceptorStatusToken token = super.beforeInvocation(fi);
- try {
- //执行下一个拦截器
- fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
- } finally {
- super.afterInvocation(token, null);
- }
- }
- @Override
- public void destroy() {
- }
- @Override
- public Class<?> getSecureObjectClass() {
- return FilterInvocation.class;
- }
- @Override
- public SecurityMetadataSource obtainSecurityMetadataSource() {
- return this.securityMetadataSource;
- }
- }
- package com.us.example.service;
3.5 新增 MyInvocationSecurityMetadataSourceService
在com.us.example.service 包下新增MyInvocationSecurityMetadataSourceService.java文件
- package com.us.example.service;
- import com.us.example.dao.PermissionDao;
- import com.us.example.domain.Permission;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.security.access.ConfigAttribute;
- import org.springframework.security.access.SecurityConfig;
- import org.springframework.security.web.FilterInvocation;
- import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
- import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
- import org.springframework.stereotype.Service;
- import javax.servlet.http.HttpServletRequest;
- import java.util.*;
- /**
- * Created by yangyibo on 17/1/19.
- */
- @Service
- public class MyInvocationSecurityMetadataSourceService implements
- FilterInvocationSecurityMetadataSource {
- @Autowired
- private PermissionDao permissionDao;
- private HashMap<String, Collection<ConfigAttribute>> map =null;
- /**
- * 加载权限表中所有权限
- */
- public void loadResourceDefine(){
- map = new HashMap<>();
- Collection<ConfigAttribute> array;
- ConfigAttribute cfg;
- List<Permission> permissions = permissionDao.findAll();
- for(Permission permission : permissions) {
- array = new ArrayList<>();
- cfg = new SecurityConfig(permission.getName());
- //此处只添加了用户的名字,其实还可以添加更多权限的信息,例如请求方法到ConfigAttribute的集合中去。此处添加的信息将会作为MyAccessDecisionManager类的decide的第三个参数。
- array.add(cfg);
- //用权限的getUrl() 作为map的key,用ConfigAttribute的集合作为 value,
- map.put(permission.getUrl(), array);
- }
- }
- //此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。
- @Override
- public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
- if(map ==null) loadResourceDefine();
- //object 中包含用户请求的request 信息
- HttpServletRequest request = ((FilterInvocation) object).getHttpRequest();
- AntPathRequestMatcher matcher;
- String resUrl;
- for(Iterator<String> iter = map.keySet().iterator(); iter.hasNext(); ) {
- resUrl = iter.next();
- matcher = new AntPathRequestMatcher(resUrl);
- if(matcher.matches(request)) {
- return map.get(resUrl);
- }
- }
- return null;
- }
- @Override
- public Collection<ConfigAttribute> getAllConfigAttributes() {
- return null;
- }
- @Override
- public boolean supports(Class<?> clazz) {
- return true;
- }
- }
4:修改home.html 文件
修改src/resources/templates目录下 的home.html
- <!DOCTYPE html>
- <html xmlns:th="http://www.thymeleaf.org"
- xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
- <head>
- <meta content="text/html;charset=UTF-8"/>
- <title sec:authentication="name"></title>
- <link rel="stylesheet" th:href="@{css/bootstrap.min.css}" />
- <style type="text/css">
- body {
- padding-top: 50px;
- }
- .starter-template {
- padding: 40px 15px;
- text-align: center;
- }
- </style>
- </head>
- <body>
- <nav class="navbar navbar-inverse navbar-fixed-top">
- <div class="container">
- <div class="navbar-header">
- <a class="navbar-brand" href="#">Spring Security演示</a>
- </div>
- <div id="navbar" class="collapse navbar-collapse">
- <ul class="nav navbar-nav">
- <li><a th:href="@{/}"> 首页 </a></li>
- <li><a th:href="@{/admin}"> admin </a></li>
- </ul>
- </div><!--/.nav-collapse -->
- </div>
- </nav>
- <div class="container">
- <div class="starter-template">
- <h1 th:text="${msg.title}"></h1>
- <p class="bg-primary" th:text="${msg.content}"></p>
- <div sec:authorize="hasRole('ROLE_HOME')"> <!-- 用户类型为ROLE_ADMIN 显示 -->
- <p class="bg-info" th:text="${msg.etraInfo}"></p>
- </div>
- <div sec:authorize="hasRole('ROLE_ADMIN')"> <!-- 用户类型为ROLE_ADMIN 显示 -->
- <p class="bg-info">恭喜您,您有 ROLE_ADMIN 权限 </p>
- </div>
- <form th:action="@{/logout}" method="post">
- <input type="submit" class="btn btn-primary" value="注销"/>
- </form>
- </div>
- </div>
- </body>
- </html>
- <!DOCTYPE html>
5:修改HomeController.java 文件
- package com.us.example.controller;
- import com.us.example.domain.Msg;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.ResponseBody;
- /**
- * Created by yangyibo on 17/1/18.
- */
- @Controller
- public class HomeController {
- @RequestMapping("/")
- public String index(Model model){
- Msg msg = new Msg("测试标题","测试内容","欢迎来到HOME页面,您拥有 ROLE_HOME 权限");
- model.addAttribute("msg", msg);
- return "home";
- }
- @RequestMapping("/admin")
- @ResponseBody
- public String hello(){
- return "hello admin";
- }
- }
6.测试检验
启动访问 http://localhost:8080/ 到登录页面
- 由于数据库的配置 admin 用户拥有 访问 home和admin 页面的权限。
- abel 用户只有访问 home 的权限
- 1
- 2
- 3
使用admin 登录
点击 admin 按钮 会反回结果 “hello admin“
使用abel 用户登录 点击 点击 admin 按钮 页面会报403
源码地址:https://github.com/527515025/springBoot
参考资料:
http://www.tuicool.com/articles/jq6fuur#c-23220
http://blog.csdn.net/u012367513/article/details/38866465
springBoot+springSecurity 数据库动态管理用户、角色、权限(二)的更多相关文章
- springBoot+springSecurity 数据库动态管理用户、角色、权限
使用spring Security3的四种方法概述 那么在Spring Security3的使用中,有4种方法: 一种是全部利用配置文件,将用户.权限.资源(url)硬编码在xml文件中,已经实现过, ...
- SpringBoot学习- 10、设计用户角色权限表
SpringBoot学习足迹 前几节已经基本了解了SpringBoot框架常用的技术,其他的消息队列,定时器等技术暂时用不到,真正项目中如果基于微信系,阿里系开发的话,还要了解平台专用的技术知识,学习 ...
- [.Net MVC] 用户角色权限管理_使用CLK.AspNet.Identity
项目:后台管理平台 意义:一个完整的管理平台需要提供用户注册.登录等功能,以及认证和授权功能. 一.为何使用CLK.AspNet.Identity 首先简要说明所采取的权限控制方式.这里采用了基于角色 ...
- ASP.NET MVC+EF框架+EasyUI实现权限管理系列(21)-用户角色权限基本的实现说明
原文:ASP.NET MVC+EF框架+EasyUI实现权限管理系列(21)-用户角色权限基本的实现说明 ASP.NET MVC+EF框架+EasyUI实现权限管系列 (开篇) (1):框 ...
- java权限管理与用户角色权限设计
java权限管理与用户角色权限设计 实现业务系统中的用户权限管理 B/S系统中的权限比C/S中的更显的重要,C/S系统因为具有特殊的客户端,所以访问用户的权限检测可以通过客户端实现或通过客户端+服务器 ...
- Asp.Net MVC+BootStrap+EF6.0实现简单的用户角色权限管理
这是本人第一次写,写的不好的地方还忘包含.写这个的主要原因是想通过这个来学习下EF的CodeFirst模式,本来也想用AngularJs来玩玩的,但是自己只会普通的绑定,对指令这些不是很熟悉,所以就基 ...
- Asp.Net MVC+BootStrap+EF6.0实现简单的用户角色权限管理10
今天把用户的菜单显示和页面的按钮显示都做好了,下面先来个效果图 接下来说下我实现的方法: 首先我在每个方法前面都加了这个属性, /// <summary> /// 表示当前Action请求 ...
- spring-boot-plus V1.4.0发布 集成用户角色权限部门管理
RBAC用户角色权限 用户角色权限部门管理核心接口介绍 Shiro权限配置
- spring security中动态更新用户的权限
在程序的执行过程中,有时有这么一种需求,需要动态的更新某些角色的权限或某些人对应的权限,当前在线的用户拥有这个角色或拥有这个权限时,在不退出系统的情况下,需要动态的改变的他所拥有的权限. 需求:张三 ...
随机推荐
- 在vue中使用async/await遇到的坑
最近无聊在搞一些新的东西,今天就遇到一个async/await的坑: 因为我用的不是vue官方的脚手架,所以遇到这样的问题: await is a reserved word 这样的警告,我猜应该是缺 ...
- php文件上传错误信息说明对照表
php文件上传错误信息说明对照表: UPLOAD_ERR_OK:其值为0,没有错误发生,文件上传成功UPLOAD_ERR_INI_SIZE:其值为1,上传的文件超过了php.ini中upload_ma ...
- event.target和event.currentTarget的区别----0605加深理解
target:触发事件的元素.currentTarget:事件绑定的元素.两者在没有冒泡的情况下,是一样的值,但在用了事件委托的情况下,就不一样了,例如: <ul id="ulT&qu ...
- 如何在一个线程环境中使用一个线程非安全的java类
在开发过程中 当我们拿到一个线程非安全的java类的时候,我们可以额外创建这个类的管理类 并在管理类中控制同步 比如 一个非线程安全的Pair类 package test.thread.sx.test ...
- 使用elasticdump导入导出数据
一.安装elasticdump 终端中输入 npm install elasticdump -g -g表示全局可用,直接在终端输入 elasticdump --version,出现版本信息即表示安装成 ...
- 使用svn未响应卡死的几个原因,commit时checkout时
1.commit 时 很可能是:检索文件内容过多导致,解决:不要在最外层文件夹目录下commit 2.checkout时 很可能是:地址错误
- mysql注入大全及防御
0.明白存在的位置:get型 post型 cookie型 http头注入 1.先测试注入点,注册框.搜索框.地址栏啥的,判断是字符型,搜索型还是数字型 字符型 1' and '1'='1 成功, 1' ...
- laravel5.8 Auth::guide
// 使用下面这个命令Laravel会自动为我们生成Auth路由和认证模块.跟着代码往下解读. php artisan make:auth // Http/Controllers/Auth/Login ...
- 搭建docker+k8s踩过的坑
问题一: # yum install -y etcd kubernetes Error: docker-ce-cli conflicts with :docker--.gitb2f74b2.el7.c ...
- Linux学习--第十三天--日志、系统运行级别、grub加密
日志 rsyslogd取代了syslogd. /var/log/cron #定时任务相关日志 /var/log/cups #打印信息相关日志 /var/log/dmesg #开机内核自检相关日志,dm ...