背景
上一part中掌握了如何使用常用数据源,jdbc、druid和mybatis
在part1中为了防止用户在未登陆用户下访问到员工管理页面,用过滤器的方式实现了对该类请求的拦截。在本part中整合常用安全框架,以简单配置代替编码实现拦截器等其它安全功能。
整合框架及所实现功能移步左侧一级标题
项目地址(源码自取↓):
整合SpringSecurity:https://github.com/codersliu/springboot06-springsecurity
整合Shiro:https://github.com/codersliu/springboot08-shiro
整合SpringSecurity
新建项目,导入以下依赖↓
导入resources/static/qinjiang和resources/templates下的静态资源
application.properties下关闭thymeleaf缓存
1
| spring.thymeleaf.cache=false
|
新建controller/RouteController实现页面跳转
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| package com.sliu.springboot06springsecurity.controller;
import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;
@Controller public class RouteController {
@RequestMapping({"/", "/index", "/index.html"}) public String index(){ return "index"; }
@RequestMapping("/toLogin") public String toLogin(){ return "views/login"; }
@RequestMapping("/level1/{id}") public String level1(@PathVariable("id") int id){ return "views/level1/"+id; }
@RequestMapping("/level2/{id}") public String level2(@PathVariable("id") int id){ return "views/level2/"+id; }
@RequestMapping("/level3/{id}") public String level3(@PathVariable("id") int id){ return "views/level3/"+id; } }
|
测试时要注释掉pom.xml下SpringSecurity依赖,引入依赖会自动实现用户登录状态的过滤。
最终页面如↓
测试完成后取取消SpringSecurity依赖注释
授权和认证
新建config/SecurityConfig类,实现WebSecurity
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| package com.sliu.springboot06springsecurity.config;
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.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/").permitAll() .antMatchers("/level1/**").hasRole("vip1") .antMatchers("/level2/**").hasRole("vip2") .antMatchers("/level3/**").hasRole("vip3");
http.formLogin(); }
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication() .withUser("sliu").password("{noop}123456").roles("vip1", "vip2") .and() .withUser("root").password("{noop}123456").roles("vip1", "vip2", "vip3") .and() .withUser("guest").password("{noop}123456").roles("vip1"); }
}
|
注销和权限控制
该模块涉及前端知识角度,快速过一遍
config/SecurityConfig下开启注销功能(configure方法下添加)
1 2
| http.logout().logoutSuccessUrl("/");
|
index.html中登陆按钮下添加注销按钮
1 2 3
| <a class="item" th:href="@{/logout}"> <i class="address card icon"></i> 注销 </a>
|
注销搞定!
接下来完成在对应权限登陆后,仅现实当前vip权限能够访问的资源,例如:sliu权限为vip1和vip2,那么在登陆完成后,主页不应该显示level3相关可操作项。
pom.xml下导入thymeleaf-springSecurity整合包
1 2 3 4
| <dependency> <groupId>org.thymeleaf.extras</groupId> <artifactId>thymeleaf-extras-springsecurity5</artifactId> </dependency>
|
修改index.html实现
在用户未登陆时仅显示登陆按钮,用户已登录显示用户名、注销按钮
导入命名空间
1
| <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
|
html下主要两处修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
| <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="https://www.thymeleaf.org/thymeleaf-extras-springsecurity5"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <title>首页</title> <link href="https://cdn.bootcss.com/semantic-ui/2.4.1/semantic.min.css" rel="stylesheet"> <link th:href="@{/qinjiang/css/qinstyle.css}" rel="stylesheet"> </head> <body>
<div class="ui container">
<div class="ui segment" id="index-header-nav" th:fragment="nav-menu"> <div class="ui secondary menu"> <a class="item" th:href="@{/index}">首页</a>
<div class="right menu">
<div sec:authorize="!isAuthenticated()"> <a class="item" th:href="@{/toLogin}"> <i class="address card icon"></i> 登录 </a> </div>
<div sec:authorize="isAuthenticated()"> <a class="item" th:href="@{/logout}"> <i class="address card icon"></i> 注销 </a> </div> <div sec:authorize="isAuthenticated()"> <a class="item"> 用户名:<span sec:authentication="name"></span>
</a> </div>
</div> </div> </div>
<div class="ui segment" style="text-align: center"> <h3>Spring Security Study by 秦疆</h3> </div>
<div> <br> <div class="ui three column stackable grid"> <div class="column" sec:authorize="hasRole('vip1')"> <div class="ui raised segment"> <div class="ui"> <div class="content"> <h5 class="content">Level 1</h5> <hr> <div><a th:href="@{/level1/1}"><i class="bullhorn icon"></i> Level-1-1</a></div> <div><a th:href="@{/level1/2}"><i class="bullhorn icon"></i> Level-1-2</a></div> <div><a th:href="@{/level1/3}"><i class="bullhorn icon"></i> Level-1-3</a></div> </div> </div> </div> </div>
<div class="column" sec:authorize="hasRole('vip2')"> <div class="ui raised segment"> <div class="ui"> <div class="content"> <h5 class="content">Level 2</h5> <hr> <div><a th:href="@{/level2/1}"><i class="bullhorn icon"></i> Level-2-1</a></div> <div><a th:href="@{/level2/2}"><i class="bullhorn icon"></i> Level-2-2</a></div> <div><a th:href="@{/level2/3}"><i class="bullhorn icon"></i> Level-2-3</a></div> </div> </div> </div> </div>
<div class="column" sec:authorize="hasRole('vip3')"> <div class="ui raised segment"> <div class="ui"> <div class="content"> <h5 class="content">Level 3</h5> <hr> <div><a th:href="@{/level3/1}"><i class="bullhorn icon"></i> Level-3-1</a></div> <div><a th:href="@{/level3/2}"><i class="bullhorn icon"></i> Level-3-2</a></div> <div><a th:href="@{/level3/3}"><i class="bullhorn icon"></i> Level-3-3</a></div> </div> </div> </div> </div>
</div> </div> </div>
<script th:src="@{/qinjiang/js/jquery-3.1.1.min.js}"></script> <script th:src="@{/qinjiang/js/semantic.min.js}"></script>
</body> </html>
|
SecurityConfig下config方法中开启防止网站攻击
1 2
| http.csrf().disable();
|
最终效果图↓:
记住我和首页定制
开启remember
me功能,通过cookie保存登陆状态,浏览器关闭后,下次访问无需再次登陆。
SecurityConfig类下config函数内添加
1 2
| http.rememberMe().rememberMeParameter("remember");
|
首页定制在config函数下添加:
1 2 3
|
http.formLogin().loginPage("/toLogin").usernameParameter("user").passwordParameter("pwd").loginProcessingUrl("/login");
|
整合shiro
环境搭建
shiro官网下载安装包
以下三个概念对于理解shiro如何运行非常重要:
(1)Subject 用户
(2)SecurityManager 管理所有用户
(3)Realm 连接数据
1.导入shiro核心依赖
pom.xml中导入依赖
1 2 3 4 5
| <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.9.0</version> </dependency>
|
新建src/main/java/com.xxx.shirospringboot/config/ShiroConfig.java用于配置shiro
2.编写shiro核心配置
该类核心框架如下
1 2 3 4 5 6 7 8 9 10 11 12 13
| package com.sliu.shirospringboot.config;
import org.springframework.context.annotation.Configuration;
@Configuration public class ShiroConfig {
}
|
依次从下向上实现对应模块
(1)创建realm对象
新建config/UserRealm.java自定义Realm
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| package com.sliu.shirospringboot.config;
import org.apache.shiro.authc.AuthenticationException; import org.apache.shiro.authc.AuthenticationInfo; import org.apache.shiro.authc.AuthenticationToken; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection;
public class UserRealm extends AuthorizingRealm {
@Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("执行了授权======>doGetAuthorizationInfo"); return null; }
@Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { System.out.println("执行了认证权======>doGetAuthenticationInfo"); return null; } }
|
(2)ShiroConfig中将自定义UserRealm放入容器Bean中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| package com.sliu.shirospringboot.config;
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;
@Configuration public class ShiroConfig {
@Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); bean.setSecurityManager(defaultWebSecurityManager); return bean; }
@Bean(name = "securityManager") public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(userRealm()); return securityManager; }
@Bean(name = "userRealm") public UserRealm userRealm(){ return new UserRealm(); } }
|
Shiro登陆拦截
要实现对用户的登陆拦截,避免未认证用户进入系统,shiro中需要对自定义配置ShiroConfig中的getShiroFilterFactoryBean中进行过滤器的配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); bean.setSecurityManager(defaultWebSecurityManager);
Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/user/*", "authc"); bean.setFilterChainDefinitionMap(filterMap);
bean.setLoginUrl("/login"); return bean; }
|
Shiro用户认证
MyController.java内引入常规登陆规范检查
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @RequestMapping("/login") public String login(String username, String password, Model model){ Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
try { subject.login(token); return "index"; }catch (UnknownAccountException e){ model.addAttribute("msg", "用户名错误"); return "login"; }catch (IncorrectCredentialsException e){ model.addAttribute("msg", "密码错误"); return "login"; }
}
|
自定义UserRealm中配置认证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("执行了认证======>doGetAuthenticationInfo");
String name = "root"; String password = "123456";
UsernamePasswordToken userToken = (UsernamePasswordToken) token; if(!userToken.getUsername().equals(name)){ return null; }
return new SimpleAuthenticationInfo("",password,""); }
|
整合mybatis
pom.xml中引入连接数据库依赖
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.12</version> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.2</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency>
|
新建application.yml配置数据源
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| spring: datasource: username: root password: 123456 url: jdbc:mysql://localhost:3306/company?useUnicode=true&characterEnconding=utf-8 driver-class-name: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource initial-size: 5 min-idle: 5 max-active: 20 max-wait: 60000 time-between-eviction-runs-millis: 60000 min-evictable-idle-time-millis: 300000 validation-query: SELECT 1 FROM DUAL test-while-idle: true test-on-borrow: false test-on-return: false pool-prepared-statements: true max-pool-prepared-statement-per-connection-size: 20 filters: stat,wall,log4j use-global-data-source-stat: true connect-properties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
|
application.properties下配置
1 2
| mybatis.type-aliases-package=com.sliu.shirospringboot.pojo mybatis.mapper-locations=classpath:mapper/*.xml
|
新建pojo/User.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package com.sliu.shirospringboot.pojo;
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;
@Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String username; private String password; }
|
新建com.sliu.shirospringboot/mapper/UserMapper接口
1 2 3 4 5 6 7 8 9 10 11
| package com.sliu.shirospringboot.mapper;
import com.sliu.shirospringboot.pojo.User; import org.apache.ibatis.annotations.Mapper; import org.springframework.stereotype.Repository;
@Repository @Mapper public interface UserMapper { public User queryUserByName(String username); }
|
新建resources/mapper/UserMappper.xml
1 2 3 4 5 6 7 8 9
| <?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.sliu.shirospringboot.mapper.UserMapper"> <select id="queryUserByName" parameterType="String" resultType="User"> select * from user where username =#{username} </select> </mapper>
|
新建service/userService接口和实现类service/UserServiceImpl
1 2 3 4 5 6 7
| package com.sliu.shirospringboot.service;
import com.sliu.shirospringboot.pojo.User;
public interface UserService { public User queryUserByName(String name); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com.sliu.shirospringboot.service;
import com.sliu.shirospringboot.mapper.UserMapper; import com.sliu.shirospringboot.pojo.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service;
@Service public class UserServiceImpl implements UserService{ @Autowired UserMapper userMapper;
@Override public User queryUserByName(String name) { return userMapper.queryUserByName(name); } }
|
修改自定义UserRealm下认证为数据库获取
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| package com.sliu.shirospringboot.config;
import com.sliu.shirospringboot.pojo.User; import com.sliu.shirospringboot.service.UserService; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; import org.apache.shiro.authz.AuthorizationInfo; import org.apache.shiro.realm.AuthorizingRealm; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.Subject; import org.springframework.beans.factory.annotation.Autowired;
public class UserRealm extends AuthorizingRealm { @Autowired UserService userService;
@Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("执行了授权======>doGetAuthorizationInfo"); return null; }
@Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("执行了认证======>doGetAuthenticationInfo");
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
User user = userService.queryUserByName(userToken.getUsername()); if(user==null){ return null; }
return new SimpleAuthenticationInfo("",user.getPassword(),""); } }
|
Shiro请求授权
(1)设置权限
添加认证信息
这里需要留意的点在于以下两个授权的先后顺序,写反了导致所有用户都能访问到/user/add,调bug一小时
1 2 3 4
| filterMap.put("/user/add", "perms[user:add]");
filterMap.put("/user/*", "authc");
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| package com.sliu.shirospringboot.config;
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.LinkedHashMap; import java.util.Map;
@Configuration public class ShiroConfig {
@Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){ ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean(); bean.setSecurityManager(defaultWebSecurityManager);
Map<String, String> filterMap = new LinkedHashMap<>(); filterMap.put("/user/add", "perms[user:add]");
filterMap.put("/user/update", "perms[user:update]");
filterMap.put("/user/*", "authc");
bean.setFilterChainDefinitionMap(filterMap);
bean.setLoginUrl("/toLogin");
bean.setUnauthorizedUrl("/unauthor"); return bean; }
@Bean(name = "securityManager") public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(userRealm()); return securityManager; }
@Bean(name = "userRealm") public UserRealm userRealm(){ return new UserRealm(); } }
|
(2)授予用户权限
为了方便权限管理,修改数据库user表,添加一个perm字段用于存储用户权限信息,表结构如下
修改pojo/User.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| package com.sliu.shirospringboot.pojo;
import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;
@Data @AllArgsConstructor @NoArgsConstructor public class User { private int id; private String username; private String password; private String perm; }
|
自定义UserRealm通过获取当前Subject附带的User对象获取当前用户权限perm信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| package com.sliu.shirospringboot.config;
import com.sliu.shirospringboot.pojo.User; import com.sliu.shirospringboot.service.UserService; import org.apache.shiro.SecurityUtils; import org.apache.shiro.authc.*; 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.apache.shiro.subject.Subject; import org.springframework.beans.factory.annotation.Autowired;
public class UserRealm extends AuthorizingRealm { @Autowired UserService userService;
@Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { System.out.println("执行了授权======>doGetAuthorizationInfo"); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
Subject subject = SecurityUtils.getSubject(); User currentUser = (User) subject.getPrincipal();
info.addStringPermission(currentUser.getPerm());
return info; }
@Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("执行了认证======>doGetAuthenticationInfo");
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
User user = userService.queryUserByName(userToken.getUsername()); if(user==null){ return null; }
return new SimpleAuthenticationInfo(user, user.getPassword(),""); } }
|
Shiro整合Thymeleaf
该部分功能实现对应权限仅显示对于功能页(即如果sliu仅拥有add权限,登陆主页后,应仅显示add操作按钮,而隐藏update操作按钮)
pom.xml中导入shiro-thymeleaf整合依赖包
1 2 3 4 5
| <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.1.0</version> </dependency>
|
ShiroConfig中进行配置整合
1 2 3 4 5
| @Bean public ShiroDialect getShiroDialect(){ return new ShiroDialect(); }
|
!!!以下为部分前端知识
修改主页html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <!DOCTYPE html> <html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h1>首页</h1> <p> <a th:href="@{/toLogin}">登陆</a> </p> <p th:text="${msg}"></p> <hr> <div shiro:hasPermission="user:add"> <a th:href="@{/user/add}">add</a> </div>
<div shiro:hasPermission="user:update"> <a th:href="@{/user/update}">update</a> </div> </body> </html>
|
实现效果如下
当前在登陆上存在的问题是,登陆成功后仍然显示登陆按钮。通过在登陆认证时设置当前用户的Session,前端判断Session为空时才显示登陆按钮
自定义UserRealm类下添加认证时设置Session
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { System.out.println("执行了认证======>doGetAuthenticationInfo");
UsernamePasswordToken userToken = (UsernamePasswordToken) token;
User user = userService.queryUserByName(userToken.getUsername()); if(user==null){ return null; } Subject currentSubject = SecurityUtils.getSubject(); Session session = currentSubject.getSession(); session.setAttribute("loginUser", user);
return new SimpleAuthenticationInfo(user, user.getPassword(),""); }
|
index.html下添加判断session是否为空
1 2 3
| <div th:if="${session.loginUser==null}"> <a th:href="@{/toLogin}">登陆</a> </div>
|
成功登陆后不再显示登陆按钮
总结
本part中整合了常用安全框架SpringSecurity和Shiro,介绍了两种框架下如何实现用户的授权和认证
认证授权搞定√