Spring Boot学习
官网:https://spring.io/projects/spring-boot#overview
文档:https://docs.spring.io/spring-boot/docs/2.2.6.RELEASE/reference/html/
参考视频:【狂神说Java】SpringBoot最新教程IDEA版通俗易懂_哔哩哔哩_bilibili
项目完整参考代码:lexiaoyuan/SpringBootStudy: My Spring Boot study notes (github.com)、SpringBootStudy: 我的Spring Boot学习笔记 (gitee.com)
Spring Boot整合Shiro
环境搭建
- 新建一个Spring Boot项目,引入web和thymeleaf的模块依赖
- 再在
pom.xml
中引入shiro-spring的整合依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.5.2</version>
</dependency>
- 在templates目录下新建
index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>首页</h1>
<p th:text="${msg}"></p>
<a th:href="@{/user/add}">add</a>
<a th:href="@{/user/update}">update</a>
</body>
</html>
- 在templates目录下新建user目录,在user目录下新建
add.html
和update.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>add</h3>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>update</h3>
</body>
</html>
- 新建一个controller包,在controller包下新建一个
MyController.java
@Controller
public class MyController {
@GetMapping({"/", "/index"})
public String hello(Model model) {
model.addAttribute("msg","Hello Shiro");
return "index";
}
@GetMapping("/user/add")
public String add() {
return "user/add";
}
@GetMapping("/user/update")
public String update() {
return "user/update";
}
}
- 新建一个config包,config包下新建一个
UserRealm.java
// 自定义的Realm,extends AuthorizingRealm
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("执行了===》认证doGetAuthorizationInfo");
return null;
}
}
- 在config包下新建一个
ShiroConfig.java
@Configuration
public class ShiroConfig {
// 3. 创建ShiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 设置安全管理器
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
return shiroFilterFactoryBean;
}
// 2. 创建DefaultWebSecurityManager
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 关联UserRealm
securityManager.setRealm(userRealm);
return securityManager;
}
// 1. 创建realm对象,需要自定义类
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
}
- 运行项目,测试,访问:http://localhost:8080/
- 点击add和update链接,均可正常跳转,环境OK!
登录拦截
- 添加shiro的内置过滤器
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
// 设置安全管理器
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
// 添加shiro的内置过滤器
/**
* anon: 无需认证就可以访问
* authc: 必须认证了才能访问
* user: 必须有记住我功能才能访问
* perms: 拥有对某个资源的权限才能访问
* role:拥有某个角色权限才能访问
*/
// 登录拦截
Map<String, String> filterMap = new LinkedHashMap<>();
//filterMap.put("/user/add", "authc");
//filterMap.put("/user/update", "authc");
filterMap.put("/user/*", "authc"); // 支持通配符
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
- 测试:重新运行项目,访问:http://localhost:8080/,点击add和update链接都会报错,表示拦截成功!
- 设置登录请求
// 设置登录请求
shiroFilterFactoryBean.setLoginUrl("/toLogin");
- 在templates目录下写一个
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3>登录</h3>
<div>
<form action="">
<p>用户名:<input type="text" name="username" required></p>
<p>密码:<input type="password" name="password" required></p>
<p><input type="submit" value="登录"></p>
</form>
</div>
</body>
</html>
- 在
MyController.java
中写一个/toLogin
接受请求
@GetMapping("/toLogin")
public String toLogin(){
return "login";
}
- 测试:运行项目,访问:http://localhost:8080/,点击add和update链接都跳转到登录页面,表示设置登录页面成功!
用户认证
- 在
MyController.java
中的新建login方法接受login请求,并接受登录信息
@PostMapping("/login")
public String login(String username, String password, Model model) {
// 1. 封装用户的登录数据
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
// 2. 获取当前用户
Subject currentUser = SecurityUtils.getSubject();
// 3. 身份认证
try {
currentUser.login(token); // 执行登录方法,如果没有异常说明OK了
return "index";
} catch (UnknownAccountException uae) {
model.addAttribute("msg", "用户名错误");
return "login";
} catch (IncorrectCredentialsException ice) {
model.addAttribute("msg", "密码错误");
return "login";
}
}
- 用户名和密码认证,在
UserRealm.java
中定义
// 认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了===》认证doGetAuthorizationInfo");
// 用户名、密码认证,从数据库取
String username = "lexiaoyuan";
String password = "123456";
UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
if (!userToken.getUsername().equals(username)) {
return null; // 抛出异常 UnknownAccountException
}
// 密码认证,shiro做
return new SimpleAuthenticationInfo("",password,"");
}
- 测试:运行项目,访问:http://localhost:8080/,点击add或update链接,都会进入登录页面,
输入错误的用户名,点击登录,会提示
输入正确的用户名,错误的密码,点击登录,会提示
输入正确的用户名和密码,点击登录,会进入首页,
再点击add或update链接均可正常访问
- 同时在控制台可以看到,每次登录都会执行一次认证操作
- ok,用户认证完成!
未完待续……