回顶部

springboot+shiro

1.springboot整合shiro

pom.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3          xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
 4     <modelVersion>4.0.0</modelVersion>
 5     <parent>
 6         <groupId>org.springframework.boot</groupId>
 7         <artifactId>spring-boot-starter-parent</artifactId>
 8         <version>2.2.1.RELEASE</version>
 9         <relativePath/> <!-- lookup parent from repository -->
10     </parent>
11     <groupId>com.qiao</groupId>
12     <artifactId>hello-shiro</artifactId>
13     <version>0.0.1-SNAPSHOT</version>
14     <name>hello-shiro</name>
15     <description>Demo project for Spring Boot</description>
16 
17     <properties>
18         <java.version>1.8</java.version>
19     </properties>
20 
21     <dependencies>
22         <dependency>
23             <groupId>org.springframework.boot</groupId>
24             <artifactId>spring-boot-starter-web</artifactId>
25         </dependency>
26 
27         <dependency>
28             <groupId>org.springframework.boot</groupId>
29             <artifactId>spring-boot-starter-test</artifactId>
30             <scope>test</scope>
31             <exclusions>
32                 <exclusion>
33                     <groupId>org.junit.vintage</groupId>
34                     <artifactId>junit-vintage-engine</artifactId>
35                 </exclusion>
36             </exclusions>
37         </dependency>
38         <!-- shiro thymeleaf整合 -->
39         <dependency>
40             <groupId>com.github.theborakompanioni</groupId>
41             <artifactId>thymeleaf-extras-shiro</artifactId>
42             <version>2.0.0</version>
43         </dependency>
44         <dependency>
45             <groupId>org.projectlombok</groupId>
46             <artifactId>lombok</artifactId>
47         </dependency>
48         <!-- 引入mysql驱动包 -->
49         <dependency>
50             <groupId>mysql</groupId>
51             <artifactId>mysql-connector-java</artifactId>
52             <version>5.1.27</version>
53         </dependency>
54         <!-- 引入Druid依赖,阿里巴巴所提供的数据源 -->
55         <dependency>
56             <groupId>com.alibaba</groupId>
57             <artifactId>druid</artifactId>
58             <version>1.0.29</version>
59         </dependency>
60         <dependency>
61             <groupId>org.mybatis.spring.boot</groupId>
62             <artifactId>mybatis-spring-boot-starter</artifactId>
63             <version>2.1.0</version>
64         </dependency>
65         <dependency>
66             <groupId>org.springframework.boot</groupId>
67             <artifactId>spring-boot-starter-thymeleaf</artifactId>
68         </dependency>
69         <dependency>
70             <groupId>org.apache.shiro</groupId>
71             <artifactId>shiro-spring</artifactId>
72             <version>1.4.1</version>
73         </dependency>
74     </dependencies>
75 
76     <build>
77         <plugins>
78             <plugin>
79                 <groupId>org.springframework.boot</groupId>
80                 <artifactId>spring-boot-maven-plugin</artifactId>
81             </plugin>
82 
83         </plugins>
84 
85     </build>
86 
87 </project>
View Code

其中shiro整合spring的依赖是

1 <dependency>
2     <groupId>org.apache.shiro</groupId>
3     <artifactId>shiro-spring</artifactId>
4     <version>1.4.1</version>
5 </dependency>

shiro和thymeleaf整合的依赖是

1  <dependency>
2      <groupId>com.github.theborakompanioni</groupId>
3      <artifactId>thymeleaf-extras-shiro</artifactId>
4      <version>2.0.0</version>
5   </dependency>

2.shiro核心的API

  1.Subject:主体,当前用户,与当前应用进行交互。所有Subject都要绑定到SercurityManager。

  2.SecurityManager:安全管理器 ,管理所有的Subject,所有关于安全的操作都会与之交互。

  3.Realm:域,Shiro从Realm获取授权,认证,安全管理器认证用户身份就需要从Realm获取用户进行比较。

  使用Shiro需要自定义Realm继承AuthorizingRealm

  覆写两个方法即可

  

   AuthenticationInfo 用于认证

  AuthorizationInfo 用于授权

3.使用shiro

配置ShiroConfig

 1 @Configuration
 2 public class ShiroConfig {
 3     //ShiroFilterFactoryBean 3.
 4     @Bean
 5     public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
 6         ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
 7         //设置安全管理器
 8         bean.setSecurityManager(securityManager);
 9         //添加shiro的内置管理器
10         /**
11          * anon:无需认证即可访问
12          * authc:必须认证才能访问
13          * user:必须拥有 记住我 功能
14          * perms:拥有对某个资源的权限才能访问
15          * role:拥有某个角色权限才能访问
16          * filter.put("/user/add", "authc");
17          * filter.put("/user/update", "authc");
18          */
19         //拦截
20         Map<String, String> filter = new LinkedHashMap<>();
21         //授权 必须是user:add权限的才能访问
22         filter.put("/user/add", "perms[user:add]");
23         //授权 必须是user:add权限的才能访问
24         filter.put("/user/update", "perms[user:update]");
25         filter.put("/user/*", "authc");
26         bean.setFilterChainDefinitionMap(filter);
27         //设置登录的请求
28         bean.setLoginUrl("/toLogin");
29         //设置未授权请求页面
30         bean.setUnauthorizedUrl("/unAuthor");
31         return bean;
32     }
33 
34     //DefaultWebSecurityManager 2.
35     @Bean(name = "securityManager")
36     public DefaultWebSecurityManager getDefaultWebSecurityManager(UserRealm userRealm){
37         DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
38         //关联UserRealm
39         securityManager.setRealm(userRealm);
40         return securityManager;
41     }
42 
43     //创建realm类,自定义
44     @Bean
45     public UserRealm userRealm(){
46         return new UserRealm();
47     }
48 
49     //整合shiroDialect 用于thymeleaf和shiro标签配合使用
50     @Bean
51     public ShiroDialect shiroDialect(){
52         return new ShiroDialect();
53     }
54 }

自定义UserRealm

 1 public class UserRealm extends AuthorizingRealm {
 2     @Autowired
 3     UserService userService;
 4     //授权
 5     @Override
 6     protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
 7         System.out.println("执行授权==》doGetAuthorizationInfo");
 8 
 9         SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
10 
11         //拿到当前登录的这个对象
12         Subject subject = SecurityUtils.getSubject();
13         User currentUser = (User) subject.getPrincipal();
14         //如果没有权限,权限为null,就返回null
15         if (currentUser.getPerms() == null){
16             return null;
17         }
18         //设置权限~从数据库查寻
19         info.addStringPermission(currentUser.getPerms());
20         return info;
21     }
22     //认证
23     @Override
24     protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
25             throws AuthenticationException {
26         System.out.println("执行认证==》AuthenticationInfo");
27        //连接真实的数据库
28         UsernamePasswordToken userToken = (UsernamePasswordToken) token;
29         User user = userService.queryUserByName(userToken.getUsername());
30         //把登录用户塞进shiro的session shiro有自己独立的session~这也是为什么shiro可以脱离web使用
31         Subject subject = SecurityUtils.getSubject();
32         Session session = subject.getSession();
33         session.setAttribute("loginUser", user);
34         if(user == null){
35             throw new UnknownAccountException();
36         }
37         //盐值
38         String saltPassword = ShiroUtil.saltPassword(userToken.getPassword(), user.getSaltValue());
39         // userToken.getPassword() 获取用户输入的密码
40         if (!user.getPwd().equals(saltPassword)){
41             throw new IncorrectCredentialsException();
42         }
43         //密码认证,由shiro做~ 为了防止密码泄露  第4个参数是realm名称
44         return new SimpleAuthenticationInfo(user, userToken.getPassword(), ByteSource.Util.bytes(user.getSaltValue()), this.getName());
45     }
46 }

需要密码加密,创建工具类ShiroUtil

 1 public class ShiroUtil {
 2     public static String createSalt(){
 3         //生成32的随机盐值
 4         return UUID.randomUUID().toString().replaceAll("-", "");
 5     }
 6     /**
 7      * @param srcPwd    原始密码
 8      * @param saltValue 盐值
 9      */
10     public static String saltPassword(Object srcPwd, String saltValue){
11         return new SimpleHash("MD5", srcPwd, saltValue, 1024).toString();
12     }
13 }

创建实体类User

 1 @Data
 2 @AllArgsConstructor
 3 @NoArgsConstructor
 4 public class User {
 5     private Integer id;
 6     private String name;
 7     private String pwd;
 8     private String perms;
 9     /**
10      * 盐值
11      */
12     private String saltValue;
13 
14 }

我这里使用的mybatis,创建UserMapper接口,直接使用注解写sql(不喜欢XML)

1 @Repository
2 @Mapper
3 public interface UserMapper {
4     @Select("select * from mybatis.user where name = #{name}")
5     public User queryUserByName(String name);
6     @Insert("insert into mybatis.user(name,pwd,perms,saltValue) values(#{name},#{pwd},#{perms},#{saltValue})")
7     public void insertUser(User user);
8 }

创建Service接口和实现类,用于获取数据

1 public interface UserService {
2     public User queryUserByName(String name);
3     public void insertUser(User user);
4 }
 1 @Service
 2 public class UserServiceImpl implements UserService {
 3     @Autowired
 4     UserMapper userMapper;
 5     @Override
 6     public User queryUserByName(String name) {
 7         return userMapper.queryUserByName(name);
 8     }
 9 
10     @Override
11     public void insertUser(User user) {
12         userMapper.insertUser(user);
13     }
14 }

创建一个简陋的主页、登录和注册页面

index.html

 1 <!DOCTYPE html>
 2 <html lang="en" xmlns:th="http://www.thymeleaf.org"
 3       xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
 4 <head>
 5     <meta charset="UTF-8">
 6     <title>首页</title>
 7 </head>
 8 <body>
 9     <h1>首页</h1>
10     <div th:if="${session.loginUser==null}">
11         <a th:href="@{/toLogin}">登录</a>
12     </div>
13     <div th:if="${session.loginUser==null}">
14         <a th:href="@{/toRegister}">注册</a>
15     </div>
16     <div th:if="${session.loginUser!=null}">
17         <a th:href="@{/logout}">退出</a>
18     </div>
19     <p>hello,shiro</p>
20     <div shiro:hasPermission="user:add">
21         <a th:href="@{/user/add}">add</a>
22     </div>
23     <div shiro:hasPermission="user:update">
24     <a th:href="@{/user/update}">update</a>
25     </div>
26 </body>
27 </html>

   xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro" 在thymeleaf中使用shiro标签的命名空间

login.html

 1 <!DOCTYPE html>
 2 <html lang="en" xmlns:th="http://www.thymeleaf.org">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>登录</title>
 6 </head>
 7 <body>
 8 <p th:text="${msg}" style="color: red;"></p>
 9 <form th:action="@{/login}" method="post">
10     <p>用户名:<input type="text" name="username"></p>
11     <p>&emsp;码:<input type="text" name="password"></p>
12     <input type="submit">
13 </form>
14 </body>
15 </html>

register.html

 1 <!DOCTYPE html>
 2 <html lang="en" xmlns:th="http://www.thymeleaf.org">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>注册</title>
 6 </head>
 7 <body>
 8 <h1>注册</h1>
 9 <form th:action="@{/register}" method="post">
10     <p>用户名:<input type="text" name="username"></p>
11     <p>&emsp;码:<input type="text" name="password"></p>
12     <input type="submit">
13 </form>
14 </body>
15 </html>

yml配置文件

 1 spring:
 2   datasource:
 3     username: root
 4     password: 123456
 5     #?serverTimezone=UTC解决时区的报错
 6     url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
 7     driver-class-name: com.mysql.jdbc.Driver
 8     type: com.alibaba.druid.pool.DruidDataSource
 9 
10     #Spring Boot 默认是不注入这些属性值的,需要自己绑定
11     #druid 数据源专有配置
12     initialSize: 5
13     minIdle: 5
14     maxActive: 20
15     maxWait: 60000
16     timeBetweenEvictionRunsMillis: 60000
17     minEvictableIdleTimeMillis: 300000
18     validationQuery: SELECT 1 FROM DUAL
19     testWhileIdle: true
20     testOnBorrow: false
21     testOnReturn: false
22     poolPreparedStatements: true
23 
24     #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
25     #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
26     #则导入 log4j 依赖即可,Maven 地址: https://mvnrepository.com/artifact/log4j/log4j
27     filters: stat,wall,log4j
28     maxPoolPreparedStatementPerConnectionSize: 20
29     useGlobalDataSourceStat: true
30     connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

数据表

非原创,仅是在学习西部狂神-秦疆的课程的基础上加了撒盐加密的功能

附上参考代码,继续努力~ https://github.com/Sevenwsq/springboot-shiro.git

posted @ 2019-11-19 20:11  一生。  阅读(644)  评论(0编辑  收藏  举报