引自:30分钟了解Springboot整合Shiro

前言:06年7月的某日,不才创作了一篇题为《30分钟学会如何使用Shiro》的文章。不在意之间居然斩获了22万的阅读量,许多人因此加了我的联系方式咨询源码工程,只可惜当时并没有专门保留。2年后的今天在机缘巧合之下,我又重拾此话题。希望能带给小伙伴们在Springboot下如何使用Shiro,当然若各位感兴趣我还希望之后能创作一些与它有关的更加深入的知识。作为一个知识分享型博主,我希望能够帮助大家尽快上手。因此我尽可能去除了与整合无关的干扰因素,方便大家只要按照文章的思路就一定能有所收获。

项目结构截图:

项目在结构上没有任何特殊之处,基本就是MVC的传统结构重点需要关注的是3个Entity类、2个Controller类和1个Config类。

首先,提供pom的完整文档结构:

  1. <project xmlns="http://maven.apache.org/POM/4.0.0"
  2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5.  
  6. <groupId>com.learnhow.springboot</groupId>
  7. <artifactId>web</artifactId>
  8. <version>0.0.1-SNAPSHOT</version>
  9. <packaging>jar</packaging>
  10.  
  11. <name>web</name>
  12. <url>http://maven.apache.org</url>
  13.  
  14. <parent>
  15. <groupId>org.springframework.boot</groupId>
  16. <artifactId>spring-boot-starter-parent</artifactId>
  17. <version>2.0.4.RELEASE</version>
  18. <relativePath /> <!-- lookup parent from repository -->
  19. </parent>
  20.  
  21. <properties>
  22. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  23. <java.version>1.8</java.version>
  24. </properties>
  25.  
  26. <dependencies>
  27. <dependency>
  28. <groupId>org.springframework.boot</groupId>
  29. <artifactId>spring-boot-starter</artifactId>
  30. </dependency>
  31. <dependency>
  32. <groupId>org.springframework.boot</groupId>
  33. <artifactId>spring-boot-starter-test</artifactId>
  34. <scope>test</scope>
  35. </dependency>
  36. <dependency>
  37. <groupId>org.springframework.boot</groupId>
  38. <artifactId>spring-boot-starter-web</artifactId>
  39. </dependency>
  40. <dependency>
  41. <groupId>org.springframework.boot</groupId>
  42. <artifactId>spring-boot-starter-data-jpa</artifactId>
  43. </dependency>
  44. <dependency>
  45. <groupId>mysql</groupId>
  46. <artifactId>mysql-connector-java</artifactId>
  47. </dependency>
  48. <dependency>
  49. <groupId>org.apache.shiro</groupId>
  50. <artifactId>shiro-spring</artifactId>
  51. <version>1.4.0</version>
  52. </dependency>
  53. <dependency>
  54. <groupId>org.springframework.boot</groupId>
  55. <artifactId>spring-boot-devtools</artifactId>
  56. <optional>true</optional>
  57. </dependency>
  58. </dependencies>
  59. <build>
  60. <plugins>
  61. <plugin>
  62. <groupId>org.springframework.boot</groupId>
  63. <artifactId>spring-boot-maven-plugin</artifactId>
  64. <configuration>
  65. <fork>true</fork>
  66. </configuration>
  67. </plugin>
  68. </plugins>
  69. </build>
  70. </project>

其次,创建数据库和表结构。由于我们采用jpa作为数据库持久层框架,因此我们将建表的任务交给框架自动完成,我们只需要在entity中写清楚对应关系即可。

在yml文件中配置自动建表,并且写好entity后,执行项目,jpa会执行建表语句。

  1. CREATE DATABASE enceladus; // enceladus是数据库的名称

application.yml

  1. server:
  2. port: 8088
  3. spring:
  4. application:
  5. name: shiro
  6. datasource:
  7. url: jdbc:mysql://192.168.31.37:3306/enceladus
  8. username: root
  9. password: 12345678
  10. driver-class-name: com.mysql.jdbc.Driver
  11. jpa:
  12. database: mysql
  13. showSql: true
  14. hibernate:
  15. ddlAuto: update
  16. properties:
  17. hibernate:
  18. dialect: org.hibernate.dialect.MySQL5Dialect
  19. format_sql: true

最基础的Shiro配置至少需要三张主表分别代表用户(user)、角色(role)、权限(permission),用户和角色,角色与权限之间都是ManyToMany的对应关系,不熟悉实体对应关系的小伙伴可以先去熟悉一下Hibernate。

User.java

  1. package com.learnhow.springboot.web.entity;
  2.  
  3. import java.io.Serializable;
  4. import java.util.List;
  5. import javax.persistence.Entity;
  6. import javax.persistence.FetchType;
  7. import javax.persistence.GeneratedValue;
  8. import javax.persistence.Id;
  9. import javax.persistence.JoinColumn;
  10. import javax.persistence.JoinTable;
  11. import javax.persistence.ManyToMany;
  12. import javax.persistence.Table;
  13.  
  14. /**
  15. * 用户表
  16. */
  17. @Entity
  18. @Table(name = "user_t")
  19. public class User implements Serializable {
  20. private static final long serialVersionUID = -3320971805590503443L;
  21. @Id
  22. @GeneratedValue
  23. private long id;
  24. private String username;
  25. private String password;
  26. private String salt;
  27. @ManyToMany(fetch = FetchType.EAGER)
  28. @JoinTable(name = "user_role_t", joinColumns = { @JoinColumn(name = "uid") }, inverseJoinColumns = {
  29. @JoinColumn(name = "rid") })
  30. private List<SysRole> roles;
  31.  
  32. public long getId() {
  33. return id;
  34. }
  35.  
  36. public void setId(long id) {
  37. this.id = id;
  38. }
  39.  
  40. public String getUsername() {
  41. return username;
  42. }
  43.  
  44. public void setUsername(String username) {
  45. this.username = username;
  46. }
  47.  
  48. public String getPassword() {
  49. return password;
  50. }
  51.  
  52. public void setPassword(String password) {
  53. this.password = password;
  54. }
  55.  
  56. public String getSalt() {
  57. return salt;
  58. }
  59.  
  60. public void setSalt(String salt) {
  61. this.salt = salt;
  62. }
  63.  
  64. public List<SysRole> getRoles() {
  65. return roles;
  66. }
  67.  
  68. public void setRoles(List<SysRole> roles) {
  69. this.roles = roles;
  70. }
  71.  
  72. public String getCredentialsSalt() {
  73. return username + salt + salt;
  74. }
  75.  
  76. @Override
  77. public String toString() {
  78. return "User [id=" + id + ", username=" + username + "]";
  79. }
  80.  
  81. }

User

SysRole.java

  1. package com.learnhow.springboot.web.entity;
  2.  
  3. import java.io.Serializable;
  4. import java.util.List;
  5. import javax.persistence.Entity;
  6. import javax.persistence.FetchType;
  7. import javax.persistence.GeneratedValue;
  8. import javax.persistence.Id;
  9. import javax.persistence.JoinColumn;
  10. import javax.persistence.JoinTable;
  11. import javax.persistence.ManyToMany;
  12. import javax.persistence.Table;
  13.  
  14. /**
  15. * 角色表
  16. */
  17. @Entity
  18. @Table(name = "role_t")
  19. public class SysRole implements Serializable {
  20. private static final long serialVersionUID = -8687790154329829056L;
  21. @Id
  22. @GeneratedValue
  23. private Integer id;
  24. private String role;
  25. @ManyToMany(fetch = FetchType.EAGER)
  26. @JoinTable(name = "role_permission_t", joinColumns = { @JoinColumn(name = "rid") }, inverseJoinColumns = {
  27. @JoinColumn(name = "pid") })
  28. private List<SysPermission> permissions;
  29. @ManyToMany
  30. @JoinTable(name = "user_role_t", joinColumns = { @JoinColumn(name = "rid") }, inverseJoinColumns = {
  31. @JoinColumn(name = "uid") })
  32. private List<User> users;
  33.  
  34. public Integer getId() {
  35. return id;
  36. }
  37.  
  38. public void setId(Integer id) {
  39. this.id = id;
  40. }
  41.  
  42. public String getRole() {
  43. return role;
  44. }
  45.  
  46. public void setRole(String role) {
  47. this.role = role;
  48. }
  49.  
  50. public List<SysPermission> getPermissions() {
  51. return permissions;
  52. }
  53.  
  54. public void setPermissions(List<SysPermission> permissions) {
  55. this.permissions = permissions;
  56. }
  57.  
  58. public List<User> getUsers() {
  59. return users;
  60. }
  61.  
  62. public void setUsers(List<User> users) {
  63. this.users = users;
  64. }
  65.  
  66. }

UserRole

SysPermission.java

  1. package com.learnhow.springboot.web.entity;
  2.  
  3. import java.io.Serializable;
  4. import java.util.List;
  5. import javax.persistence.Entity;
  6. import javax.persistence.GeneratedValue;
  7. import javax.persistence.Id;
  8. import javax.persistence.JoinColumn;
  9. import javax.persistence.JoinTable;
  10. import javax.persistence.ManyToMany;
  11. import javax.persistence.Table;
  12.  
  13. /**
  14. * 权限表
  15. */
  16. @Entity
  17. @Table(name = "permission_t")
  18. public class SysPermission implements Serializable {
  19. private static final long serialVersionUID = 353629772108330570L;
  20. @Id
  21. @GeneratedValue
  22. private Integer id;
  23. private String name;
  24. @ManyToMany
  25. @JoinTable(name = "role_permission_t", joinColumns = { @JoinColumn(name = "pid") }, inverseJoinColumns = {
  26. @JoinColumn(name = "rid") })
  27. private List<SysRole> roles;
  28.  
  29. public Integer getId() {
  30. return id;
  31. }
  32.  
  33. public void setId(Integer id) {
  34. this.id = id;
  35. }
  36.  
  37. public String getName() {
  38. return name;
  39. }
  40.  
  41. public void setName(String name) {
  42. this.name = name;
  43. }
  44.  
  45. public List<SysRole> getRoles() {
  46. return roles;
  47. }
  48.  
  49. public void setRoles(List<SysRole> roles) {
  50. this.roles = roles;
  51. }
  52. }

SysPermission

在注明对应关系以后,jpa会帮助我们创建3张实体表和2张中间表:

最后我们还需要初始化一些基础数据:

  1. INSERT INTO `permission_t` VALUES (1, 'Retrieve');
  2. INSERT INTO `permission_t` VALUES (2, 'Create');
  3. INSERT INTO `permission_t` VALUES (3, 'Update');
  4. INSERT INTO `permission_t` VALUES (4, 'Delete');
  5. INSERT INTO `role_t` VALUES (1, 'guest');
  6. INSERT INTO `role_t` VALUES (2, 'user');
  7. INSERT INTO `role_t` VALUES (3, 'admin');
  8. INSERT INTO `role_permission_t` VALUES (1, 1);
  9. INSERT INTO `role_permission_t` VALUES (1, 2);
  10. INSERT INTO `role_permission_t` VALUES (2, 2);
  11. INSERT INTO `role_permission_t` VALUES (3, 2);
  12. INSERT INTO `role_permission_t` VALUES (1, 3);
  13. INSERT INTO `role_permission_t` VALUES (2, 3);
  14. INSERT INTO `role_permission_t` VALUES (3, 3);
  15. INSERT INTO `role_permission_t` VALUES (4, 3);

至此,前期的准备工作已经完成。下面为了让Shiro能够在项目中生效我们需要通过代码的方式提供配置信息。Shiro的安全管理提供了两个层面的控制:(1)用户认证:需要用户通过登陆证明你是你自己。(2)权限控制:在证明了你是你自己的基础上系统为当前用户赋予权限。后者我们已经在数据库中完成了大部分配置。

用户认证的常规手段就是登陆认证,在目前的情况下我们认为只有用户自己知道登陆密码。不过Shiro为我们做的更多,它还提供了一套能够很方便我们使用的密码散列算法。因为普通的散列技巧可以很容易的通过暴力手段破解,我们可以在散列的过程中加入一定的算法复杂度(增加散列次数与Salt)从而解决这样的问题。

  1. import org.apache.shiro.crypto.RandomNumberGenerator;
  2. import org.apache.shiro.crypto.SecureRandomNumberGenerator;
  3. import org.apache.shiro.crypto.hash.SimpleHash;
  4. import org.apache.shiro.util.ByteSource;
  5.  
  6. import com.learnhow.springboot.web.entity.User;
  7.  
  8. public class PasswordHelper {
  9. private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();
  10. public static final String ALGORITHM_NAME = "md5"; // 基础散列算法
  11. public static final int HASH_ITERATIONS = 2; // 自定义散列次数
  12.  
  13. public void encryptPassword(User user) {
  14. // 随机字符串作为salt因子,实际参与运算的salt我们还引入其它干扰因子
  15. user.setSalt(randomNumberGenerator.nextBytes().toHex());
  16. String newPassword = new SimpleHash(ALGORITHM_NAME, user.getPassword(),
  17. ByteSource.Util.bytes(user.getCredentialsSalt()), HASH_ITERATIONS).toHex();
  18. user.setPassword(newPassword);
  19. }
  20. }

这个类帮助我们解决用户注册的密码散列问题,当然我们还需要使用同样的算法来保证在登陆的时候密码能够被散列成相同的字符串。如果两次散列的结果不同系统就无法完成密码比对,因此在计算散列因子的时候我们不能引入变量,例如我们可以将username作为salt因子加入散列算法,但是不能选择password或datetime,具体原因各位请手动测试。

另外为了帮助Shiro能够正确为当前登陆用户做认证和赋权,我们需要实现自定义的Realm。具体来说就是实现doGetAuthenticationInfo和doGetAuthorizationInfo,这两个方法前者负责登陆认证后者负责提供一个权限信息。

  1. import org.apache.shiro.authc.AuthenticationException;
  2. import org.apache.shiro.authc.AuthenticationInfo;
  3. import org.apache.shiro.authc.AuthenticationToken;
  4. import org.apache.shiro.authc.SimpleAuthenticationInfo;
  5. import org.apache.shiro.authz.AuthorizationInfo;
  6. import org.apache.shiro.authz.SimpleAuthorizationInfo;
  7. import org.apache.shiro.realm.AuthorizingRealm;
  8. import org.apache.shiro.subject.PrincipalCollection;
  9. import org.apache.shiro.util.ByteSource;
  10. import org.springframework.beans.factory.annotation.Autowired;
  11.  
  12. import com.learnhow.springboot.web.entity.SysPermission;
  13. import com.learnhow.springboot.web.entity.SysRole;
  14. import com.learnhow.springboot.web.entity.User;
  15. import com.learnhow.springboot.web.service.UserService;
  16.  
  17. public class EnceladusShiroRealm extends AuthorizingRealm {
  18. @Autowired
  19. private UserService userService;
  20.  
  21. @Override
  22. protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
  23. SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
  24. String username = (String) principals.getPrimaryPrincipal();
  25.  
  26. User user = userService.findUserByName(username);
  27.  
  28. for (SysRole role : user.getRoles()) {
  29. authorizationInfo.addRole(role.getRole());
  30. for (SysPermission permission : role.getPermissions()) {
  31. authorizationInfo.addStringPermission(permission.getName());
  32. }
  33. }
  34. return authorizationInfo;
  35. }
  36.  
  37. @Override
  38. protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
  39. String username = (String) token.getPrincipal();
  40. User user = userService.findUserByName(username);
  41.  
  42. if (user == null) {
  43. return null;
  44. }
  45. SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(),
  46. ByteSource.Util.bytes(user.getCredentialsSalt()), getName());
  47. return authenticationInfo;
  48. }
  49.  
  50. }

还记得前面我们说过,认证的时候我们需要提供相同的散列算法吗?可是在上面的代码里,我们并未提供。那么Shiro是怎么做的呢?AuthorizingRealm是一个抽象类,我们会在另外的配置文件里向它提供基础算法与散列次数这两个变量。

  1. import java.util.HashMap;
  2. import java.util.Map;
  3.  
  4. import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
  5. import org.apache.shiro.mgt.SecurityManager;
  6. import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
  7. import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
  8. import org.springframework.context.annotation.Bean;
  9. import org.springframework.context.annotation.Configuration;
  10.  
  11. @Configuration
  12. public class ShiroConfig {
  13. @Bean
  14. public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
  15. ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
  16. shiroFilterFactoryBean.setSecurityManager(securityManager);
  17.  
  18. Map<String, String> filterChainDefinitionMap = new HashMap<String, String>();
  19. shiroFilterFactoryBean.setLoginUrl("/login");
  20. shiroFilterFactoryBean.setUnauthorizedUrl("/unauthc");
  21. shiroFilterFactoryBean.setSuccessUrl("/home/index");
  22.  
  23. filterChainDefinitionMap.put("/*", "anon");
  24. filterChainDefinitionMap.put("/authc/index", "authc");
  25. filterChainDefinitionMap.put("/authc/admin", "roles[admin]");
  26. filterChainDefinitionMap.put("/authc/renewable", "perms[Create,Update]");
  27. filterChainDefinitionMap.put("/authc/removable", "perms[Delete]");
  28. shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
  29. return shiroFilterFactoryBean;
  30. }
  31.  
  32. @Bean
  33. public HashedCredentialsMatcher hashedCredentialsMatcher() {
  34. HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
  35. hashedCredentialsMatcher.setHashAlgorithmName(PasswordHelper.ALGORITHM_NAME); // 散列算法
  36. hashedCredentialsMatcher.setHashIterations(PasswordHelper.HASH_ITERATIONS); // 散列次数
  37. return hashedCredentialsMatcher;
  38. }
  39.  
  40. @Bean
  41. public EnceladusShiroRealm shiroRealm() {
  42. EnceladusShiroRealm shiroRealm = new EnceladusShiroRealm();
  43. shiroRealm.setCredentialsMatcher(hashedCredentialsMatcher()); // 原来在这里
  44. return shiroRealm;
  45. }
  46.  
  47. @Bean
  48. public SecurityManager securityManager() {
  49. DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
  50. securityManager.setRealm(shiroRealm());
  51. return securityManager;
  52. }
  53.  
  54. @Bean
  55. public PasswordHelper passwordHelper() {
  56. return new PasswordHelper();
  57. }
  58. }

接下来,我们将目光集中到上文的shirFilter方法中。Shiro通过一系列filter来控制访问权限,并在它的内部为我们预先定义了多个过滤器,我们可以直接通过字符串配置这些过滤器。

常用的过滤器如下:

authc:所有已登陆用户可访问

roles:有指定角色的用户可访问,通过[ ]指定具体角色,这里的角色名称与数据库中配置一致

perms:有指定权限的用户可访问,通过[ ]指定具体权限,这里的权限名称与数据库中配置一致

anon:所有用户可访问,通常作为指定页面的静态资源时使用

为了测试方便我们不引入页面配置直接通过rest方式访问

不受权限控制访问的地址

  1. import org.apache.shiro.SecurityUtils;
  2. import org.apache.shiro.authc.IncorrectCredentialsException;
  3. import org.apache.shiro.authc.UnknownAccountException;
  4. import org.apache.shiro.authc.UsernamePasswordToken;
  5. import org.apache.shiro.subject.Subject;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.web.bind.annotation.GetMapping;
  8. import org.springframework.web.bind.annotation.RequestMapping;
  9. import org.springframework.web.bind.annotation.RequestParam;
  10. import org.springframework.web.bind.annotation.RestController;
  11.  
  12. import com.learnhow.springboot.web.PasswordHelper;
  13. import com.learnhow.springboot.web.entity.User;
  14. import com.learnhow.springboot.web.service.UserService;
  15.  
  16. @RestController
  17. @RequestMapping
  18. public class HomeController {
  19. @Autowired
  20. private UserService userService;
  21. @Autowired
  22. private PasswordHelper passwordHelper;
  23.  
  24. @GetMapping("login")
  25. public Object login() {
  26. return "Here is Login page";
  27. }
  28.  
  29. @GetMapping("unauthc")
  30. public Object unauthc() {
  31. return "Here is Unauthc page";
  32. }
  33.  
  34. @GetMapping("doLogin")
  35. public Object doLogin(@RequestParam String username, @RequestParam String password) {
  36. UsernamePasswordToken token = new UsernamePasswordToken(username, password);
  37. Subject subject = SecurityUtils.getSubject();
  38. try {
  39. subject.login(token);
  40. } catch (IncorrectCredentialsException ice) {
  41. return "password error!";
  42. } catch (UnknownAccountException uae) {
  43. return "username error!";
  44. }
  45.  
  46. User user = userService.findUserByName(username);
  47. subject.getSession().setAttribute("user", user);
  48. return "SUCCESS";
  49. }
  50.  
  51. @GetMapping("register")
  52. public Object register(@RequestParam String username, @RequestParam String password) {
  53. User user = new User();
  54. user.setUsername(username);
  55. user.setPassword(password);
  56. passwordHelper.encryptPassword(user);
  57.  
  58. userService.saveUser(user);
  59. return "SUCCESS";
  60. }
  61. }

需要指定权限可以访问的地址

  1. import org.apache.shiro.SecurityUtils;
  2. import org.apache.shiro.subject.Subject;
  3. import org.springframework.web.bind.annotation.GetMapping;
  4. import org.springframework.web.bind.annotation.RequestMapping;
  5. import org.springframework.web.bind.annotation.RestController;
  6.  
  7. import com.learnhow.springboot.web.entity.User;
  8.  
  9. @RestController
  10. @RequestMapping("authc")
  11. public class AuthcController {
  12.  
  13. @GetMapping("index")
  14. public Object index() {
  15. Subject subject = SecurityUtils.getSubject();
  16. User user = (User) subject.getSession().getAttribute("user");
  17. return user.toString();
  18. }
  19.  
  20. @GetMapping("admin")
  21. public Object admin() {
  22. return "Welcome Admin";
  23. }
  24.  
  25. // delete
  26. @GetMapping("removable")
  27. public Object removable() {
  28. return "removable";
  29. }
  30.  
  31. // insert & update
  32. @GetMapping("renewable")
  33. public Object renewable() {
  34. return "renewable";
  35. }
  36. }

详情请参考完整代码:

https://gitee.com/jingxin168/jingxin.git

上手调试:注册用户

转:30分钟了解Springboot整合Shiro的更多相关文章

  1. 30分钟了解Springboot整合Shiro

    项目结构截图: 项目在结构上没有任何特殊之处,基本就是MVC的传统结构重点需要关注的是3个Entity类.2个Controller类和1个Config类. 首先,提供pom的完整文档结构: <p ...

  2. 30分钟学会如何使用Shiro

    本篇内容大多总结自张开涛的<跟我学Shiro>原文地址:http://jinnianshilongnian.iteye.com/blog/2018936 我并没有全部看完,只是选择了一部分 ...

  3. SpringBoot整合Shiro实现权限控制,验证码

    本文介绍 SpringBoot 整合 shiro,相对于 Spring Security 而言,shiro 更加简单,没有那么复杂. 目前我的需求是一个博客系统,有用户和管理员两种角色.一个用户可能有 ...

  4. SpringBoot整合Shiro权限框架实战

    什么是ACL和RBAC ACL Access Control list:访问控制列表 优点:简单易用,开发便捷 缺点:用户和权限直接挂钩,导致在授予时的复杂性,比较分散,不便于管理 例子:常见的文件系 ...

  5. SpringBoot系列十二:SpringBoot整合 Shiro

    声明:本文来源于MLDN培训视频的课堂笔记,写在这里只是为了方便查阅. 1.概念:SpringBoot 整合 Shiro 2.具体内容 Shiro 是现在最为流行的权限认证开发框架,与它起名的只有最初 ...

  6. SpringBoot 整合 Shiro 密码登录与邮件验证码登录(多 Realm 认证)

    导入依赖(pom.xml)  <!--整合Shiro安全框架--> <dependency> <groupId>org.apache.shiro</group ...

  7. 补习系列(6)- springboot 整合 shiro 一指禅

    目标 了解ApacheShiro是什么,能做什么: 通过QuickStart 代码领会 Shiro的关键概念: 能基于SpringBoot 整合Shiro 实现URL安全访问: 掌握基于注解的方法,以 ...

  8. SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建

    SpringBoot整合Shiro实现基于角色的权限访问控制(RBAC)系统简单设计从零搭建 技术栈 : SpringBoot + shiro + jpa + freemark ,因为篇幅原因,这里只 ...

  9. springboot整合Shiro功能案例

    Shiro 核心功能案例讲解 基于SpringBoot 有源码 从实战中学习Shiro的用法.本章使用SpringBoot快速搭建项目.整合SiteMesh框架布局页面.整合Shiro框架实现用身份认 ...

随机推荐

  1. Windows API-----top level window

    原文地址: http://blog.163.com/cumt_xl/blog/static/19071504420136911838683/ Q: What is a top-level window ...

  2. TextView的跑马灯效果(AS开发实战第二章学习笔记)

    TextView的跑马灯效果跑马灯用到的属性与方法说明singleLine 指定文本是否单行显示ellipsize 指定文本超出范围后的省略方式focusable 指定是否获得焦点,跑马灯效果要求设置 ...

  3. springlog记录

    在servlet.xml加入 <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-aut ...

  4. pt-variable-advisor(percona toolkit)

    pt-variable-advisor是一款分析参数,并且给出参数设置建议的一款PT工具,基本语法 pt-variable-advisor [OPTIONS] [DSN] 如下我们可以获取本地参数的一 ...

  5. SVN升级到1.8后 Upgrade working copy

    SVN升级到1.8后没法用了,不能提交,提示说要SVN Upgrade working copy, 但是半天在根目录和.svn所在文件夹上面右键都没有找到这个菜单. 坑爹的…… 最后找到解决办法是:重 ...

  6. linux(centos)设置tomcat开机启动

    方法一: linux 下tomcat开机自启动修改Tomcat/bin/startup.sh 为: export JAVA_HOME=/usr/java/j2sdk1.4.2_08 export CL ...

  7. c# 知识学习

    1.C#基础知识梳理系列 2.详解C#委托,事件与回调函数 3.C#制作Windows service

  8. python接口自动化4-绕过验证码登录(cookie) (转载)

    前言 有些登录的接口会有验证码:短信验证码,图形验证码等,这种登录的话验证码参数可以从后台获取的(或者查数据库最直接). 获取不到也没关系,可以通过添加cookie的方式绕过验证码. 一.抓登录coo ...

  9. laravel 使用EasyWechat 3分钟完成微信支付(以APP支付为例)

    上一篇写了支付宝支付,然后这段时间我又把微信支付给接上了,作为萌新的我还是很有成就感的,哈哈~~好了,该写正事了. 第一步:创建应用及配配置  首先到微信的官方平台注册应用https://pay.we ...

  10. Jmeter(一)工具的简单介绍(z)

    一.JMeter介绍 Apache JMeter是100%纯JAVA桌面应用程序,被设计为用于测试客户端/服务端结构的软件(例如web应用程序).它可以用来测试静态和动态资源的性能,例如:静态文件,J ...