spring-boot整合shiro作权限认证
【更新】看到很多博客写 shiro权限认证的,都是一半的代码,复制上根本不能使用,依赖文件对于小白来说,更是不知道使用什么依赖,所以我把相应的java文件的包 都一并带上
spring-shiro属于轻量级权限框架,即使spring-security更新换代,市场上大多数企业还是选择shiro
废话不多说 引入pom文件相关依赖
- <!--日志管理-->
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- <version>1.7.16</version>
- </dependency>
- <!--shiro权限框架-->
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-spring</artifactId>
- <version>1.3.2</version>
- </dependency>
导入之后 相关依赖包就会自动加载 shiro-core、shiro-spring、shiro-web等等 依赖版本还得根据shiro集成的spring版本进行加载(注意版本号)
设计登录认证,就少不三张表。没做过登录认证的小白 仔细看,我在Shiro配置中,尽量的去加入注释说明
先贴上我的 用户,角色,权限 三张表的 java 对象
需求分析为:用户角色 - 多对多
角色权限 - 多对多
注意:直接复制的同学,三张表的注解,各位可以忽略删除 也可以学习使用 Spring-Data-Jpa 底层是 Hibernate,建表和查询方便
三个关系告诉你了,其实只需要最后关联的是 : 用户 - 权限 这里不需要 role角色表(实际项目中可以选择需要)
- import lombok.Data;
- import lombok.ToString;
- @Data
- @ToString
- public class User {
- /**
- *
- * This field was generated by MyBatis Generator.
- * This field corresponds to the database column tb_users.user_id
- *
- * @mbg.generated
- */
- private Integer userId;
- /**
- *
- * This field was generated by MyBatis Generator.
- * This field corresponds to the database column tb_users.user_name
- *
- * @mbg.generated
- */
- private String userName;
- /**
- *
- * This field was generated by MyBatis Generator.
- * This field corresponds to the database column tb_users.password
- *
- * @mbg.generated
- */
- private String password;
- /**
- *
- * This field was generated by MyBatis Generator.
- * This field corresponds to the database column tb_users.phone
- *
- * @mbg.generated
- */
- private String phone;
- /**
- *
- * This field was generated by MyBatis Generator.
- * This field corresponds to the database column tb_users.email
- *
- * @mbg.generated
- */
- private String email;
- /**
- *
- * This field was generated by MyBatis Generator.
- * This field corresponds to the database column tb_users.status
- *
- * @mbg.generated
- */
- private Integer status;
- private String salt;
- public String getSalt() {
- return salt;
- }
- public void setSalt(String salt) {
- this.salt = salt;
- }
- /**
- *
- * This field was generated by MyBatis Generator.
- * This field corresponds to the database column tb_users.note
- *
- * @mbg.generated
- */
- private String note;
- /**
- *
- * This field was generated by MyBatis Generator.
- * This field corresponds to the database column tb_users.create_time
- *
- * @mbg.generated
- */
- private String createTime;
- /**
- *
- * This field was generated by MyBatis Generator.
- * This field corresponds to the database column tb_users.update_time
- *
- * @mbg.generated
- */
- private String updateTime;
- /**
- * This method was generated by MyBatis Generator.
- * This method returns the value of the database column tb_users.user_id
- *
- * @return the value of tb_users.user_id
- *
- * @mbg.generated
- */
- public Integer getUserId() {
- return userId;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method sets the value of the database column tb_users.user_id
- *
- * @param userId the value for tb_users.user_id
- *
- * @mbg.generated
- */
- public void setUserId(Integer userId) {
- this.userId = userId;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method returns the value of the database column tb_users.user_name
- *
- * @return the value of tb_users.user_name
- *
- * @mbg.generated
- */
- public String getUserName() {
- return userName;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method sets the value of the database column tb_users.user_name
- *
- * @param userName the value for tb_users.user_name
- *
- * @mbg.generated
- */
- public void setUserName(String userName) {
- this.userName = userName == null ? null : userName.trim();
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method returns the value of the database column tb_users.password
- *
- * @return the value of tb_users.password
- *
- * @mbg.generated
- */
- public String getPassword() {
- return password;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method sets the value of the database column tb_users.password
- *
- * @param password the value for tb_users.password
- *
- * @mbg.generated
- */
- public void setPassword(String password) {
- this.password = password == null ? null : password.trim();
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method returns the value of the database column tb_users.phone
- *
- * @return the value of tb_users.phone
- *
- * @mbg.generated
- */
- public String getPhone() {
- return phone;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method sets the value of the database column tb_users.phone
- *
- * @param phone the value for tb_users.phone
- *
- * @mbg.generated
- */
- public void setPhone(String phone) {
- this.phone = phone == null ? null : phone.trim();
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method returns the value of the database column tb_users.email
- *
- * @return the value of tb_users.email
- *
- * @mbg.generated
- */
- public String getEmail() {
- return email;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method sets the value of the database column tb_users.email
- *
- * @param email the value for tb_users.email
- *
- * @mbg.generated
- */
- public void setEmail(String email) {
- this.email = email == null ? null : email.trim();
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method returns the value of the database column tb_users.status
- *
- * @return the value of tb_users.status
- *
- * @mbg.generated
- */
- public Integer getStatus() {
- return status;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method sets the value of the database column tb_users.status
- *
- * @param status the value for tb_users.status
- *
- * @mbg.generated
- */
- public void setStatus(Integer status) {
- this.status = status;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method returns the value of the database column tb_users.note
- *
- * @return the value of tb_users.note
- *
- * @mbg.generated
- */
- public String getNote() {
- return note;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method sets the value of the database column tb_users.note
- *
- * @param note the value for tb_users.note
- *
- * @mbg.generated
- */
- public void setNote(String note) {
- this.note = note == null ? null : note.trim();
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method returns the value of the database column tb_users.create_time
- *
- * @return the value of tb_users.create_time
- *
- * @mbg.generated
- */
- public String getCreateTime() {
- return createTime;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method sets the value of the database column tb_users.create_time
- *
- * @param createTime the value for tb_users.create_time
- *
- * @mbg.generated
- */
- public void setCreateTime(String createTime) {
- this.createTime = createTime;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method returns the value of the database column tb_users.update_time
- *
- * @return the value of tb_users.update_time
- *
- * @mbg.generated
- */
- public String getUpdateTime() {
- return updateTime;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method sets the value of the database column tb_users.update_time
- *
- * @param updateTime the value for tb_users.update_time
- *
- * @mbg.generated
- */
- public void setUpdateTime(String updateTime) {
- this.updateTime = updateTime;
- }
- }
User
- import lombok.Data;
- import lombok.ToString;
- import java.util.Date;
- /**
- * @author wusiwee
- * @date 2020/4/3 10:58
- */
- @Data
- @ToString
- public class Permission {
- /**
- *
- * This field was generated by MyBatis Generator.
- * This field corresponds to the database column tb_functions.func_id
- *
- * @mbg.generated
- */
- private Integer funcId;
- /**
- *
- * This field was generated by MyBatis Generator.
- * This field corresponds to the database column tb_functions.func_name
- *
- * @mbg.generated
- */
- private String funcName;
- /**
- *
- * This field was generated by MyBatis Generator.
- * This field corresponds to the database column tb_functions.func_url
- *
- * @mbg.generated
- */
- private String funcUrl;
- /**
- *
- * This field was generated by MyBatis Generator.
- * This field corresponds to the database column tb_functions.func_code
- *
- * @mbg.generated
- */
- private String funcCode;
- /**
- *
- * This field was generated by MyBatis Generator.
- * This field corresponds to the database column tb_functions.parent_id
- *
- * @mbg.generated
- */
- private Integer parentId;
- /**
- *
- * This field was generated by MyBatis Generator.
- * This field corresponds to the database column tb_functions.func_type
- *
- * @mbg.generated
- */
- private Integer funcType;
- /**
- *
- * This field was generated by MyBatis Generator.
- * This field corresponds to the database column tb_functions.status
- *
- * @mbg.generated
- */
- private Integer status;
- /**
- *
- * This field was generated by MyBatis Generator.
- * This field corresponds to the database column tb_functions.sort_num
- *
- * @mbg.generated
- */
- private Integer sortNum;
- /**
- *
- * This field was generated by MyBatis Generator.
- * This field corresponds to the database column tb_functions.create_time
- *
- * @mbg.generated
- */
- private Date createTime;
- /**
- *
- * This field was generated by MyBatis Generator.
- * This field corresponds to the database column tb_functions.update_time
- *
- * @mbg.generated
- */
- private Date updateTime;
- /**
- * This method was generated by MyBatis Generator.
- * This method returns the value of the database column tb_functions.func_id
- *
- * @return the value of tb_functions.func_id
- *
- * @mbg.generated
- */
- public Integer getFuncId() {
- return funcId;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method sets the value of the database column tb_functions.func_id
- *
- * @param funcId the value for tb_functions.func_id
- *
- * @mbg.generated
- */
- public void setFuncId(Integer funcId) {
- this.funcId = funcId;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method returns the value of the database column tb_functions.func_name
- *
- * @return the value of tb_functions.func_name
- *
- * @mbg.generated
- */
- public String getFuncName() {
- return funcName;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method sets the value of the database column tb_functions.func_name
- *
- * @param funcName the value for tb_functions.func_name
- *
- * @mbg.generated
- */
- public void setFuncName(String funcName) {
- this.funcName = funcName == null ? null : funcName.trim();
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method returns the value of the database column tb_functions.func_url
- *
- * @return the value of tb_functions.func_url
- *
- * @mbg.generated
- */
- public String getFuncUrl() {
- return funcUrl;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method sets the value of the database column tb_functions.func_url
- *
- * @param funcUrl the value for tb_functions.func_url
- *
- * @mbg.generated
- */
- public void setFuncUrl(String funcUrl) {
- this.funcUrl = funcUrl == null ? null : funcUrl.trim();
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method returns the value of the database column tb_functions.func_code
- *
- * @return the value of tb_functions.func_code
- *
- * @mbg.generated
- */
- public String getFuncCode() {
- return funcCode;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method sets the value of the database column tb_functions.func_code
- *
- * @param funcCode the value for tb_functions.func_code
- *
- * @mbg.generated
- */
- public void setFuncCode(String funcCode) {
- this.funcCode = funcCode == null ? null : funcCode.trim();
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method returns the value of the database column tb_functions.parent_id
- *
- * @return the value of tb_functions.parent_id
- *
- * @mbg.generated
- */
- public Integer getParentId() {
- return parentId;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method sets the value of the database column tb_functions.parent_id
- *
- * @param parentId the value for tb_functions.parent_id
- *
- * @mbg.generated
- */
- public void setParentId(Integer parentId) {
- this.parentId = parentId;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method returns the value of the database column tb_functions.func_type
- *
- * @return the value of tb_functions.func_type
- *
- * @mbg.generated
- */
- public Integer getFuncType() {
- return funcType;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method sets the value of the database column tb_functions.func_type
- *
- * @param funcType the value for tb_functions.func_type
- *
- * @mbg.generated
- */
- public void setFuncType(Integer funcType) {
- this.funcType = funcType;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method returns the value of the database column tb_functions.status
- *
- * @return the value of tb_functions.status
- *
- * @mbg.generated
- */
- public Integer getStatus() {
- return status;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method sets the value of the database column tb_functions.status
- *
- * @param status the value for tb_functions.status
- *
- * @mbg.generated
- */
- public void setStatus(Integer status) {
- this.status = status;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method returns the value of the database column tb_functions.sort_num
- *
- * @return the value of tb_functions.sort_num
- *
- * @mbg.generated
- */
- public Integer getSortNum() {
- return sortNum;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method sets the value of the database column tb_functions.sort_num
- *
- * @param sortNum the value for tb_functions.sort_num
- *
- * @mbg.generated
- */
- public void setSortNum(Integer sortNum) {
- this.sortNum = sortNum;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method returns the value of the database column tb_functions.create_time
- *
- * @return the value of tb_functions.create_time
- *
- * @mbg.generated
- */
- public Date getCreateTime() {
- return createTime;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method sets the value of the database column tb_functions.create_time
- *
- * @param createTime the value for tb_functions.create_time
- *
- * @mbg.generated
- */
- public void setCreateTime(Date createTime) {
- this.createTime = createTime;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method returns the value of the database column tb_functions.update_time
- *
- * @return the value of tb_functions.update_time
- *
- * @mbg.generated
- */
- public Date getUpdateTime() {
- return updateTime;
- }
- /**
- * This method was generated by MyBatis Generator.
- * This method sets the value of the database column tb_functions.update_time
- *
- * @param updateTime the value for tb_functions.update_time
- *
- * @mbg.generated
- */
- public void setUpdateTime(Date updateTime) {
- this.updateTime = updateTime;
- }
- }
Permission
开始进入Shiro篇
一:自定义Reaml域,用于实现自身认证体系,大白话:什么样的认证规则,我都可以来定
创建Reaml对象 继承 AuthorizingRealm 实现
授权方法
- doGetAuthorizationInfo(PrincipalCollection principals){}
认证方法
- doGetAuthenticationInfo(AuthenticationToken token){}
- import com.bear.entity.Permission;
- import com.bear.entity.User;
- import com.bear.service.PermissionService;
- import com.bear.service.UserService;
- import org.apache.shiro.authc.AuthenticationException;
- import org.apache.shiro.authc.AuthenticationInfo;
- import org.apache.shiro.authc.AuthenticationToken;
- import org.apache.shiro.authc.SimpleAuthenticationInfo;
- import org.apache.shiro.authz.AuthorizationInfo;
- import org.apache.shiro.authz.SimpleAuthorizationInfo;
- import org.apache.shiro.realm.AuthorizingRealm;
- import org.apache.shiro.subject.PrincipalCollection;
- import org.springframework.beans.factory.annotation.Autowired;
- import java.util.ArrayList;
- import java.util.List;
- /**
- * @author wusw
- * @version 1.0
- * @date 2020/4/2 19:46
- */
- public class ShiroReaml extends AuthorizingRealm {
- /**
- * 注入userService 服务层 用户与数据库数据查询
- */
- @Autowired
- private UserService userService;
- /**
- * 注入permissionService 服务层 用户与数据库数据查询
- */
- @Autowired
- private PermissionService permissionService;
- /**
- * 授权
- * @param principalCollection
- * @return
- */
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
- //这个User对应下面认证方法的 返回的第一个参数 ew SimpleAuthenticationInfo(user, user.getPassword(), "shiroReaml")
- User user = (User)principalCollection.getPrimaryPrincipal();
- //查询用户相关权限
- List<Permission> permissionList = permissionService.findPermissionByUserId(user.getUserId());
- //授权对象
- SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
- //创建一个List<String> 用于接收权限信息
- ArrayList<String> list = new ArrayList<>();
- for (Permission permission : permissionList) {
- //添加权限String字符串:存值示例: "admin:*","admin:list"...
- info.addStringPermission(permission.getFuncCode());
- }
- return info;
- }
- /**
- * 认证
- * @param token
- * @return
- * @throws AuthenticationException
- */
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
- //这一块toString返回 username 是login方法在 newUserNamePassword(username,password)创建的token封装成的
- String username = token.getPrincipal().toString();
- //打印一下,项目中 尽量不要使用System.out.println(),最好使用log日志进行记录
- System.out.println("认证获取的username:"+username);
- //查询数据库用户是否存在 不存在则抛异常 Shiro会自动认证失败
- User user = this.userService.findByUsername(username);
- //参数一 可以传 username,user对象 等等 我这里是user对象 对应上面授权方法principalCollection获取的值
- //参数二 用户密码
- //参数三 shiroReaml 名称要与 shiroConfig配置中的 Reaml 的注入Bean保持一致
- SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, user.getPassword(), "shiroReaml");
- return authenticationInfo;
- }
- }
二:Shiro配置 加上注解 @Configuration 让springboot识别它为一个配置类
注意:打字太多,我把相应规则的 url 贴上,供大家参考
- import org.apache.shiro.mgt.SecurityManager;
- import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
- import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
- import org.springframework.beans.factory.annotation.Qualifier;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import java.util.HashMap;
- /**
- * 请注意看每个方法上的注释
- * @author wusw
- * @version 1.0
- * @date 2020/4/2 19:41
- */
- @Configuration
- public class ShiroConfig {
- /**
- * 添加创建 securityMeneger 工厂注入Bean
- * @param securityManager 注解Qualifier中的名字 和下面 DefaultWebSecurityManager 的Bean的名字相同
- * @return
- */
- @Bean
- public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("securityManager") SecurityManager securityManager){
- ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
- filterFactoryBean.setSecurityManager(securityManager);
- //设置权限过滤器集合 key-value 形式
- // key :访问路径 正常/**写在最下面,执行顺序是从上至下,这里是个大坑,一不小心,程序就凉凉了呢~
- // value:anon(可以匿名访问),authc(认证后才能访问),logout(退出后自动清除session)
- HashMap<String, String> map = new HashMap<>();
- map.put("/bear/login","anon");
- map.put("/bear/logout","logout");
- map.put("/**","authc");
- filterFactoryBean.setLoginUrl("/bear/toLogin");
- filterFactoryBean.setUnauthorizedUrl("/bear/401");
- filterFactoryBean.setSuccessUrl("/bear/index");
- //将map集合 传给过滤器
- filterFactoryBean.setFilterChainDefinitionMap(map);
- return filterFactoryBean;
- }
- /**
- * 创建 securityMeneger 类的注入Bean
- * @param shiroReaml 注解Qualifier中的名字 和下面 ShiroReaml的Bean的名字相同
- * @return
- */
- @Bean("securityManager")
- public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("shiroReaml") ShiroReaml shiroReaml){
- DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
- securityManager.setRealm(shiroReaml);
- return securityManager;
- }
- /**
- * 创建自定义域 reaml注入Bean
- * @return
- */
- @Bean("shiroReaml")
- public ShiroReaml shiroReaml(){
- return new ShiroReaml();
- }
- }
主要已经搞定,贴上相关service,controller,以及yml配置文件,dao层交互我使用的是mybaties相关pom依赖各位小伙伴自己导入 xml中namespase和type路径请自行导入
- # 数据库的配置信息
- spring:
- datasource:
- driver-class-name: com.mysql.cj.jdbc.Driver
- url: jdbc:mysql://0.0.0.0/db?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=Hongkong&verifyServerCertificate=false
- username: ***
- password: ***
- type: com.alibaba.druid.pool.DruidDataSource
- thymeleaf:
- mode: HTML5
- encoding: UTF-8
- servlet:
- content-type: text/html
- mvc:
- static-path-pattern: /**
- # mybatis的配置信息
- mybatis:
- config-location: classpath:mybatis/config/mybatis-config.xml
- mapper-locations: classpath:mybatis/mapper/*.xml
- server:
- port: 8081
applicaiton.yml
- <?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.bear.dao.IUserMapper">
- <resultMap id="BaseResultMap" type="com.bear.entity.User">
- <!--
- WARNING - @mbg.generated
- This element is automatically generated by MyBatis Generator, do not modify.
- -->
- <id column="user_id" jdbcType="INTEGER" property="userId" />
- <result column="user_name" jdbcType="VARCHAR" property="userName" />
- <result column="password" jdbcType="VARCHAR" property="password" />
- <result column="phone" jdbcType="VARCHAR" property="phone" />
- <result column="email" jdbcType="VARCHAR" property="email" />
- <result column="salt" jdbcType="VARCHAR" property="salt" />
- <result column="status" jdbcType="INTEGER" property="status" />
- <result column="note" jdbcType="VARCHAR" property="note" />
- <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
- <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
- </resultMap>
- <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
- <!--
- WARNING - @mbg.generated
- This element is automatically generated by MyBatis Generator, do not modify.
- -->
- delete from tb_users
- where user_id = #{userId,jdbcType=INTEGER}
- </delete>
- <insert id="insert" parameterType="com.bear.entity.User">
- insert into tb_users (user_id, user_name, password,
- phone, email, status,
- note, create_time, update_time
- )
- values (#{userId,jdbcType=INTEGER}, #{userName,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR},
- #{phone,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR}, #{status,jdbcType=INTEGER},
- #{note,jdbcType=VARCHAR}, #{createTime,jdbcType=TIMESTAMP}, #{updateTime,jdbcType=TIMESTAMP}
- )
- </insert>
- <update id="updateByPrimaryKey" parameterType="com.bear.entity.User">
- <!--
- WARNING - @mbg.generated
- This element is automatically generated by MyBatis Generator, do not modify.
- -->
- update tb_users
- set user_name = #{userName,jdbcType=VARCHAR},
- password = #{password,jdbcType=VARCHAR},
- phone = #{phone,jdbcType=VARCHAR},
- email = #{email,jdbcType=VARCHAR},
- status = #{status,jdbcType=INTEGER},
- note = #{note,jdbcType=VARCHAR},
- create_time = #{createTime,jdbcType=TIMESTAMP},
- update_time = #{updateTime,jdbcType=TIMESTAMP}
- where user_id = #{userId,jdbcType=INTEGER}
- </update>
- <!-- <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
- select user_id, user_name, password, phone, email, status, note, create_time, update_time
- from tb_users
- where user_id = #{userId,jdbcType=INTEGER}
- </select>-->
- <select id="findAll" resultMap="BaseResultMap">
- select user_id, user_name, password, phone, email, status, note, create_time, update_time
- from tb_users
- </select>
- <!-- 根据用户名密码查询 -->
- <select id="findByUsername" resultMap="BaseResultMap">
- select * from tb_users where user_name = #{username}
- </select>
- <!-- 根据分页查询 -->
- <!-- <select id="findByPage" resultMap="BaseResultMap">
- select * from tb_users limit #{page},#{rows}
- </select>
- <!– 统计总记录数 –>
- <select id="totalCount" resultType="long">
- select count(*) from tb_users
- </select>
- <!– 根据ID查询 –>
- <select id="findById" resultMap="BaseResultMap">
- select * from tb_users where user_id = #{userId}
- </select>-->
- </mapper>
IUserMappler.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.bear.dao.IPermissionMapper">
- <resultMap id="BaseResultMap" type="com.bear.entity.Permission">
- <!-- WARNING - @mbg.generated This element is automatically generated by
- MyBatis Generator, do not modify. -->
- <id column="func_id" jdbcType="INTEGER" property="funcId" />
- <result column="func_name" jdbcType="VARCHAR" property="funcName" />
- <result column="func_url" jdbcType="VARCHAR" property="funcUrl" />
- <result column="func_code" jdbcType="VARCHAR" property="funcCode" />
- <result column="parent_id" jdbcType="INTEGER" property="parentId" />
- <result column="func_type" jdbcType="INTEGER" property="funcType" />
- <result column="status" jdbcType="INTEGER" property="status" />
- <result column="sort_num" jdbcType="INTEGER" property="sortNum" />
- <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
- <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
- </resultMap>
- <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
- <!-- WARNING - @mbg.generated This element is automatically generated by
- MyBatis Generator, do not modify. -->
- delete from tb_functions
- where func_id = #{funcId,jdbcType=INTEGER}
- </delete>
- <insert id="insert" parameterType="com.bear.entity.Permission">
- <!-- WARNING - @mbg.generated This element is automatically generated by
- MyBatis Generator, do not modify. -->
- insert into tb_functions (func_id, func_name, func_url,
- func_code,
- parent_id, func_type,
- status, sort_num, create_time,
- update_time)
- values
- (#{funcId,jdbcType=INTEGER}, #{funcName,jdbcType=VARCHAR},
- #{funcUrl,jdbcType=VARCHAR},
- #{funcCode,jdbcType=VARCHAR},
- #{parentId,jdbcType=INTEGER}, #{funcType,jdbcType=INTEGER},
- #{status,jdbcType=INTEGER}, #{sortNum,jdbcType=INTEGER},
- #{createTime,jdbcType=TIMESTAMP},
- #{updateTime,jdbcType=TIMESTAMP})
- </insert>
- <update id="updateByPrimaryKey" parameterType="com.bear.entity.Permission">
- <!-- WARNING - @mbg.generated This element is automatically generated by
- MyBatis Generator, do not modify. -->
- update tb_functions
- set func_name = #{funcName,jdbcType=VARCHAR},
- func_url = #{funcUrl,jdbcType=VARCHAR},
- func_code =
- #{funcCode,jdbcType=VARCHAR},
- parent_id = #{parentId,jdbcType=INTEGER},
- func_type = #{funcType,jdbcType=INTEGER},
- status =
- #{status,jdbcType=INTEGER},
- sort_num = #{sortNum,jdbcType=INTEGER},
- create_time = #{createTime,jdbcType=TIMESTAMP},
- update_time =
- #{updateTime,jdbcType=TIMESTAMP}
- where func_id =
- #{funcId,jdbcType=INTEGER}
- </update>
- <select id="selectByPrimaryKey" parameterType="java.lang.Integer"
- resultMap="BaseResultMap">
- <!-- WARNING - @mbg.generated This element is automatically generated by
- MyBatis Generator, do not modify. -->
- select func_id, func_name, func_url, func_code, parent_id, func_type,
- status, sort_num,
- create_time, update_time
- from tb_functions
- where
- func_id = #{funcId,jdbcType=INTEGER}
- </select>
- <select id="selectAll" resultMap="BaseResultMap">
- <!-- WARNING - @mbg.generated This element is automatically generated by
- MyBatis Generator, do not modify. -->
- select func_id, func_name, func_url, func_code, parent_id, func_type,
- status, sort_num,
- create_time, update_time
- from tb_functions
- </select>
- <select id="findByRoleIds" resultMap="BaseResultMap"
- parameterType="java.util.List">
- select distinct f.* from tb_functions f , tb_role_function rf where
- f.func_id = rf.func_id and rf.role_id in
- <foreach collection="list" item="id" open="(" close=")"
- separator=",">
- #{id}
- </foreach>
- and f.func_type = 0
- </select>
- <select id="findPermissionByUserId" resultMap="BaseResultMap"
- parameterType="int">
- select
- DISTINCT
- f.*
- from
- tb_users u,tb_user_role ur,tb_roles r,tb_functions f,tb_role_function rf
- where
- u.user_id = ur.user_id and
- r.role_id = ur.role_id and
- f.func_id = rf.func_id and
- r.role_id = rf.role_id and
- u.user_id = #{userId}
- </select>
- </mapper>
IPermissionMapper
dao层:
- import org.apache.ibatis.annotations.Mapper;
- import java.util.List;
- @Mapper
- public interface IUserMapper {
- /**
- * 根据用户名查找用户
- * @param username
- * @return
- */
- User findByUsername(String username);
- /**
- * 更新
- * @param user
- */
- void updateByPrimaryKey(User user);
- /**
- * 新增
- * @param user
- */
- void insert(User user);
- /**
- * 根据id删除用户(后期修改为改变状态)
- * @param id
- */
- void deleteByPrimaryKey(Integer id);
- /**
- * 查询所有用户列表
- * @return
- */
- List<User> findAll();
- }
IUserMapper
- import org.apache.ibatis.annotations.Mapper;
- import java.util.List;
- /**
- * @author wusiwee
- * @date 2020/4/3 11:00
- */
- @Mapper
- public interface IPermissionMapper {
- /**
- * 根据user id查询用户权限
- * @param userId
- * @return
- */
- List<Permission> findPermissionByUserId(Integer userId);
- }
IPermissionMapper
service层:
- import java.util.List;
- public interface UserService {
- User findByUsername(String username);
- List<User> findAll();
- }
UserService
- import com.bear.dao.IUserMapper;
- import com.bear.entity.User;
- import com.bear.service.UserService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import java.util.List;
- @Service
- public class UserServiceImpl implements UserService {
- @Autowired
- private IUserMapper userMapper;
- @Override
- public User findByUsername(String username) {
- User result = null;
- if (username != null) {
- result = this.userMapper.findByUsername(username);
- }
- return result;
- }
- @Override
- public List<User> findAll() {
- return this.userMapper.findAll();
- }
- }
UserServiceImpl
- import com.bear.entity.Permission;
- import java.util.List;
- /**
- * @author wusiwee
- * @date 2020/4/3 11:02
- */
- public interface PermissionService {
- List<Permission> findPermissionByUserId(Integer userId);
- }
PermissionService
- import com.bear.dao.IPermissionMapper;
- import com.bear.entity.Permission;
- import com.bear.service.PermissionService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Service;
- import java.util.List;
- /**
- * @author wusiwee
- * @date 2020/4/3 11:02
- */
- @Service
- public class PermissionServiceImpl implements PermissionService {
- @Autowired
- private IPermissionMapper permissionMapper;
- @Override
- public List<Permission> findPermissionByUserId(Integer userId) {
- List<Permission> result = null;
- if (userId != null) {
- result = this.permissionMapper.findPermissionByUserId(userId);
- }
- return result;
- }
- }
PermissionServiceImpl
controller层(注意Login方法的subject为shiro登录使用):
- 注解@RequiresPermissions("system:*")为校验用户是否有权限,没有此权限则不允许访问此方法 跳转401
- import com.bear.service.UserService;
- import org.apache.commons.lang3.StringUtils;
- import org.apache.shiro.SecurityUtils;
- import org.apache.shiro.authc.UsernamePasswordToken;
- import org.apache.shiro.authz.annotation.RequiresPermissions;
- import org.apache.shiro.subject.Subject;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.stereotype.Controller;
- import org.springframework.ui.Model;
- import org.springframework.web.bind.annotation.GetMapping;
- import org.springframework.web.bind.annotation.RequestMapping;
- @Controller
- @RequestMapping("/bear")
- public class LoginController {
- @Autowired
- private UserService userService;
- @GetMapping("toLogin")
- public String toLogin(){
- return "login";
- }
- @GetMapping("/login")
- public String login(String username, String password, Model model){
- if (!StringUtils.isEmpty(username) && !StringUtils.isEmpty(password)){
- //进行登录验证
- Subject subject = SecurityUtils.getSubject();
- UsernamePasswordToken token = new UsernamePasswordToken(username, password);
- try {
- subject.login(token);
- //认证
- boolean authenticated = subject.isAuthenticated();
- if (authenticated){
- //获取当前对象,存入session
- User user = (User)subject.getPrincipal();
- subject.getSession().setAttribute("user",user);
- System.out.println("登陆成功");
- return "redirect:index";
- }else {
- model.addAttribute("msg","登录认证失败!");
- return "login";
- }
- }catch (Exception e){
- model.addAttribute("msg","登录认证失败!");
- return "login";
- }
- }
- return "login";
- }
- @RequestMapping("/index")
- public String index(Model model){
- model.addAttribute("userList",this.userService.findAll());
- return "index";
- }
- @RequestMapping("/logout")
- public String index(){
- return "redirect:login";
- }
- @RequestMapping("/401")
- public String fours(){
- return "401";
- }
- @RequiresPermissions("system")
- @RequestMapping("/success")
- public String success(){
- return "success";
- }
- }
LoginController
html 页面:
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <meta charset="UTF-8">
- <title>成功页面</title>
- </head>
- <body>
- SUCCESS!
- </body>
- </html>
success页面
- <!DOCTYPE html>
- <html lang="en" xmlns:th="http://www.thymeleaf.org">
- <head>
- <meta charset="UTF-8">
- <title>登录页面</title>
- </head>
- <body>
- <h2>欢迎来到登录页面!</h2>
- <form action="/bear/login" method="GET" name="loginForm">
- 登录用户:<input type="text" name="username" value=""><br/>
- 登录密码:<input type="text" name="password" value=""><br/>
- <input type="submit" name="log" value="登录">
- </form>
- <!--/*@thymesVar id="msg" type="at"*/-->
- <div th:text="${msg}"></div>
- </body>
- </html>
login页面
- <!DOCTYPE html>
- <html lang="en" xmlns:th="http://www.thymeleaf.org">
- <head>
- <meta charset="UTF-8">
- <title>首面</title>
- </head>
- <style>
- table{
- border: 1px solid grey;
- border-collapse: collapse;
- }
- table td{
- border: 1px solid grey;
- border-collapse: collapse;
- }
- </style>
- <body>
- <h2>用户列表页面</h2>
- <table>
- <tr>
- <td>用户ID</td>
- <td>用户名</td>
- <td>手机号</td>
- <td>邮箱</td>
- <td>状态</td>
- <td>创建时间</td>
- </tr>
- <tr th:each="user:${userList}">
- <td th:text="${user.userId}"></td>
- <td th:text="${user.userName}"></td>
- <td th:text="${user.phone}"></td>
- <td th:text="${user.email}"></td>
- <td th:text="${user.status == 1?'正常':'失效'}">正常</td>
- <td th:text="${user.createTime}"></td>
- </tr>
- </table>
- <form action="/bear/logout" method="get">
- <input type="submit" value="退出">
- </form>
- </body>
- </html>
index页面
- <!DOCTYPE html>
- <html lang="en" xmlns:th="http://www.thymeleaf.org">
- <head>
- <meta charset="UTF-8">
- <title>401没有认证</title>
- </head>
- <body>
- <h2>抱歉,您的权限不足或认证失败,请重新登录!</h2>
- </body>
- </html>
401没有权限页面
配置完成
启动运行Applicaiton.java,最后一行,启动成功
- . ____ _ __ _ _
- /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
- ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
- \\/ ___)| |_)| | | | | || (_| | ) ) ) )
- ' |____| .__|_| |_|_| |_\__, | / / / /
- =========|_|==============|___/=/_/_/_/
- :: Spring Boot :: (v2.2.6.RELEASE)
- 2020-04-07 15:11:42.580 INFO 14672 --- [ main] com.bear.PublicApplication : Starting PublicApplication on shands-siwee with PID 14672 (D:\java\GitProjects\bear-world\target\classes started by Shands-New in D:\java\GitProjects\bear-world)
- 2020-04-07 15:11:42.584 INFO 14672 --- [ main] com.bear.PublicApplication : No active profile set, falling back to default profiles: default
- 2020-04-07 15:11:43.534 INFO 14672 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'shiroConfig' of type [com.bear.shiro.ShiroConfig$$EnhancerBySpringCGLIB$$45102fe0] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
- 2020-04-07 15:11:43.599 INFO 14672 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'mybatis-org.mybatis.spring.boot.autoconfigure.MybatisProperties' of type [org.mybatis.spring.boot.autoconfigure.MybatisProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
- 2020-04-07 15:11:43.604 INFO 14672 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration' of type [org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration$$EnhancerBySpringCGLIB$$6a2f2642] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
- 2020-04-07 15:11:43.605 INFO 14672 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Generic' of type [org.springframework.boot.autoconfigure.jdbc.DataSourceConfiguration$Generic] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
- 2020-04-07 15:11:43.617 INFO 14672 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'spring.datasource-org.springframework.boot.autoconfigure.jdbc.DataSourceProperties' of type [org.springframework.boot.autoconfigure.jdbc.DataSourceProperties] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
- 2020-04-07 15:11:43.665 INFO 14672 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'dataSource' of type [com.alibaba.druid.pool.DruidDataSource] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
- 2020-04-07 15:11:43.677 INFO 14672 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker' of type [org.springframework.boot.autoconfigure.jdbc.DataSourceInitializerInvoker] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
- 2020-04-07 15:11:43.923 INFO 14672 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'sqlSessionFactory' of type [org.apache.ibatis.session.defaults.DefaultSqlSessionFactory] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
- 2020-04-07 15:11:43.926 INFO 14672 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'sqlSessionTemplate' of type [org.mybatis.spring.SqlSessionTemplate] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
- 2020-04-07 15:11:43.928 INFO 14672 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'IUserMapper' of type [org.mybatis.spring.mapper.MapperFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
- 2020-04-07 15:11:43.929 INFO 14672 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'IUserMapper' of type [com.sun.proxy.$Proxy63] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
- 2020-04-07 15:11:43.929 INFO 14672 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'userServiceImpl' of type [com.bear.service.impl.UserServiceImpl] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
- 2020-04-07 15:11:43.932 INFO 14672 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'IPermissionMapper' of type [org.mybatis.spring.mapper.MapperFactoryBean] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
- 2020-04-07 15:11:43.932 INFO 14672 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'IPermissionMapper' of type [com.sun.proxy.$Proxy64] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
- 2020-04-07 15:11:43.932 INFO 14672 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'permissionServiceImpl' of type [com.bear.service.impl.PermissionServiceImpl] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
- 2020-04-07 15:11:43.933 INFO 14672 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'shiroReaml' of type [com.bear.shiro.ShiroReaml] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
- 2020-04-07 15:11:44.601 INFO 14672 --- [ main] trationDelegate$BeanPostProcessorChecker : Bean 'securityManager' of type [org.apache.shiro.web.mgt.DefaultWebSecurityManager] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
- 2020-04-07 15:11:44.857 INFO 14672 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8081 (http)
- 2020-04-07 15:11:44.868 INFO 14672 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
- 2020-04-07 15:11:44.868 INFO 14672 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.33]
- 2020-04-07 15:11:45.041 INFO 14672 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
- 2020-04-07 15:11:45.042 INFO 14672 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 2400 ms
- 2020-04-07 15:11:45.231 INFO 14672 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
- 2020-04-07 15:11:45.301 INFO 14672 --- [ main] o.s.b.a.w.s.WelcomePageHandlerMapping : Adding welcome page template: index
- 2020-04-07 15:11:45.356 WARN 14672 --- [ main] org.thymeleaf.templatemode.TemplateMode : [THYMELEAF][main] Template Mode 'HTML5' is deprecated. Using Template Mode 'HTML' instead.
- 2020-04-07 15:11:45.455 INFO 14672 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8081 (http) with context path ''
- 2020-04-07 15:11:45.458 INFO 14672 --- [ main] com.bear.PublicApplication : Started PublicApplication in 3.516 seconds (JVM running for 4.842)
启动程序
测试访问 :localhost:8081/bear/index ——>此时是被拦截的,会自动跳转toLogin到登录页面
spring-boot整合shiro作权限认证的更多相关文章
- Spring Boot 整合 Shiro ,两种方式全总结!
在 Spring Boot 中做权限管理,一般来说,主流的方案是 Spring Security ,但是,仅仅从技术角度来说,也可以使用 Shiro. 今天松哥就来和大家聊聊 Spring Boot ...
- Spring Boot2 系列教程(三十二)Spring Boot 整合 Shiro
在 Spring Boot 中做权限管理,一般来说,主流的方案是 Spring Security ,但是,仅仅从技术角度来说,也可以使用 Shiro. 今天松哥就来和大家聊聊 Spring Boot ...
- Spring Boot 整合 Shiro实现认证及授权管理
Spring Boot Shiro 本示例要内容 基于RBAC,授权.认证 加密.解密 统一异常处理 redis session支持 介绍 Apache Shiro 是一个功能强大且易于使用的Java ...
- Spring boot整合shiro权限管理
Apache Shiro功能框架: Shiro聚焦与应用程序安全领域的四大基石:认证.授权.会话管理和保密. #,认证,也叫作登录,用于验证用户是不是他自己所说的那个人: #,授权,也就是访问控制,比 ...
- spring boot 2 + shiro 实现权限管理
Shiro是一个功能强大且易于使用的Java安全框架,主要功能有身份验证.授权.加密和会话管理.看了网上一些文章,下面2篇文章写得不错.Springboot2.0 集成shiro权限管理 Spring ...
- spring boot整合shiro后,部分注解(Cache缓存、Transaction事务等)失效的问题
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/elonpage/article/details/78965176 前言 整合有缓存.事务的sprin ...
- Spring boot整合shiro框架
ShiroConfiguration package com.energy.common.config; import java.util.LinkedHashMap; import java.uti ...
- spring boot整合shiro出现UnavailableSecurityManagerException
spring boot自带spring security,spring security自然不用说是一个强大的安全框架,但是用惯了shiro,一时半会用不来spring security,所以要在sp ...
- 上手spring boot项目(二)之spring boot整合shiro安全框架
题记:在学习了springboot和thymeleaf之后,想完成一个项目练练手,于是使用springboot+mybatis和thymeleaf完成一个博客系统,在完成的过程中出现的一些问题,将这些 ...
随机推荐
- javascript的DI
学习AngularJS的原因之一就是觉得他的DI很牛叉,为了更好的学习,在研究源码之前,想自己按照自己的思路先实现个DI,希望这个思路能够对学习源码有帮助. (function(){ var conf ...
- HTML5-A*寻路算法
设置起点 设置终点 设置障碍 清除障碍 允许斜向跨越
- 9、IPA通路分析相关网页教程
IPA FAQ: http://ingenuity.force.com/ipa/IPATutorials# ####有各种相关教程和帮助文件. IPA 分析结果展示: http://www.lucid ...
- Entity Framework Code-First(13):Configure Many-to-Many
Configure Many-to-Many relationship: Here, we will learn how to configure Many-to-Many relationship ...
- python远程登录Paramiko模块的安装
最近做云平台的项目,需要使用python来管理所有的主机,我选择了paramiko.它跨平台的,linux和window都可以使用,pssh只支持linux. 1:安装gcc和python-devel ...
- OC官方文档翻译-Values-and-Collections-值与集合类型
查看全部文档翻译,请浏览https://github.com/L1l1thLY/Programming-with-Objective-C-in-Chinese,blog仅收录本人翻译的两章. 简述 O ...
- 清北刷题冲刺 11-02 p.m
函数最值 #include<iostream> #include<cstdio> #include<cstring> #define maxn 100010 usi ...
- Android进阶书籍推荐
版权声明:本文为xing_star原创文章,转载请注明出处! 本文同步自http://javaexception.com/archives/124 Android进阶书籍推荐 端午节前我写了drake ...
- 在 CentOS7 安装 ELK【转】
ELK是一个成熟的日志系统,主要功能有收集.分析.检索,详细见 elastic官网. 本文主要介绍如何在CentOS7下安装最新版本的ELK,当然现在docker已经有完全配置成功的elk容器,安装配 ...
- MarkDown基础语法大全
一.MarkDown是什么? Markdown是一种轻量级的「标记语言」,创始人为约翰·格鲁伯,用简洁的语法代替排版,目前被越来越多的知识工作者.写作爱好者.程序员或研究员广泛使用.其常用的标记符号不 ...