此案例基于SpringBoot整合Mybatis 简单的CRUD操作小案例,阅读过程如有不适,请自行跳转。
1. 表结构
CREATE TABLE `t_user` (
`id` int(20) NOT NULL AUTO_INCREMENT,
`username` varchar(20) DEFAULT NULL,
`password` varchar(100) DEFAULT NULL,
`salt` varchar(100) DEFAULT NULL,
`create_time` datetime DEFAULT NULL,
`state` int(1) DEFAULT NULL,
`last_login_time` datetime DEFAULT NULL,
`nickname` varchar(30) DEFAULT NULL,
`realname` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;
2. SpringBoot整合Shiro认证
2.1 添加依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
2.2 自定义的realm
package com.dbl.gp_dbl_springboot_mybatis.realm;
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;
/**
* descrription:
* <p>
* Create by DbL on 2020/11/4 0004 23:22
*/
public class AuthcRealm extends AuthorizingRealm {
/**
* 认证的方法
*
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
return null;
}
/**
* 授权的方法
*
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
}
2.3 Shiro的配置类
package com.dbl.gp_dbl_springboot_mybatis.realm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import java.util.HashMap;
import java.util.Map;
/**
* descrription:
* <p>
* Create by DbL on 2020/11/5 0005 7:11
*/
@Configuration
public class ShiroConfig {
// 散列算法
private String hashAlgorithmName = "md5";
// 迭代次数
private Integer hashIterations = 1024;
/**
* 获取凭证匹配器
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName(hashAlgorithmName);
matcher.setHashIterations(hashIterations);
return matcher;
}
/**
* 获取自定义的Realm
* @return
*/
@Bean
public AuthcRealm authcRealm(HashedCredentialsMatcher matcher){
AuthcRealm realm = new AuthcRealm();
realm.setCredentialsMatcher(matcher);
return realm;
}
/**
* 获取SecurityManager对象
* @param realm
* @return
*/
@Bean
public SecurityManager securityManager(AuthcRealm realm){
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(realm);
return manager;
}
/**
* 注册ShiroFilterFactoryBean
* @param manager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager manager){
ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
filter.setSecurityManager(manager);
filter.setLoginUrl("/login.do");
filter.setSuccessUrl("/success.html");
filter.setUnauthorizedUrl("/refuse.html");
// 设置过滤器链
Map<String,String> map = new HashMap<>();
map.put("/css/*","anon");
map.put("/js/**","anon");
map.put("/img/**","anon");
map.put("/login","anon");
map.put("/login.do","authc");
map.put("/**","authc");
filter.setFilterChainDefinitionMap(map);
return filter;
}
}
2.4 认证配置
package com.dbl.gp_dbl_springboot_mybatis.realm;
import com.dbl.gp_dbl_springboot_mybatis.pojo.User;
import com.dbl.gp_dbl_springboot_mybatis.service.IUserService;
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.util.SimpleByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.List;
/**
* descrription:
* <p>
* Create by DbL on 2020/11/4 0004 23:22
*/
public class AuthcRealm extends AuthorizingRealm {
@Autowired
private IUserService service;
/**
* 认证的方法
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
String userName = token.getUsername();
System.out.println("开始认证:" + userName);
User user = new User();
user.setUsername(userName);
// 根据账号认证
List<User> list = service.query(user);
if(list == null || list.size() != 1){
// 账号不存在或者异常
return null;
}
user = list.get(0);
return new SimpleAuthenticationInfo(user
,user.getPassword() // 密码
,new SimpleByteSource(user.getSalt()) // salt
,"authcRealm" // 自定义的Realm名称
);
}
/**
* 授权的方法
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
}
2.5. 控制器
package com.dbl.gp_dbl_springboot_mybatis.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpServletRequest;
/**
* descrription:
* <p>
* Create by DbL on 2020/11/5 0005 7:56
*/
@Controller
public class AuthcController {
@RequestMapping("/login.do")
public String login(HttpServletRequest request){
// 认证失败的异常信息
Object obj = request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
System.out.println("认证失败的信息:" + obj);
return "login";
}
@RequestMapping("/logout.do")
public String logout(){
SecurityUtils.getSubject().logout();
return "redirect:/login";
}
}
package com.dbl.gp_dbl_springboot_mybatis.controller;
import com.dbl.gp_dbl_springboot_mybatis.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* descrription:
* <p>
* Create by DbL on 2020/11/4 0004 7:43
*/
@Controller
public class BaseController {
@RequestMapping("/{page}")
public String showPage(@PathVariable String page){
return page;
}
}
2.6 登录界面
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>登录管理</h1>
<form th:action="/login.do" method="post">
<label>账号:</label><input type="text" name="username"><br>
<label>密码:</label><input type="password" name="password"><br>
<input type="submit" value="提交">
</form>
</body>
</html>
3.SpringBoot整合Shiro授权
3.1 注解授权的开启
@Configuration
public class ShiroConfig {
/**
* 开始Shiro 注解授权操作
* @param manager
* @return
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager manager){
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(manager);
return advisor;
}
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
proxyCreator.setProxyTargetClass(true);
return proxyCreator;
}
}
3.2 自定义Realm中完成授权操作
public class AuthcRealm extends AuthorizingRealm {
/**
* 授权的方法
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
User user = (User) principalCollection.getPrimaryPrincipal();
System.out.println("授权的账号是:" + user.getUsername());
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRole("role1");
return info;
}
}
3.3 控制器
package com.dbl.gp_dbl_springboot_mybatis.controller;
import com.dbl.gp_dbl_springboot_mybatis.pojo.User;
import com.dbl.gp_dbl_springboot_mybatis.service.IUserService;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* descrription:
* <p>
* Create by DbL on 2020/11/4 0004 7:43
*/
@Controller
public class UserController {
@Autowired
private IUserService service;
@RequiresRoles(value = {"role1"},logical= Logical.OR)
@RequestMapping("/user/query")
public String query(Model model){
model.addAttribute("list",service.query(null));
return "user";
}
@RequiresRoles(value = {"role2"},logical=Logical.OR)
@RequestMapping("/user/query1")
public String query1(Model model){
model.addAttribute("list",service.query(null));
return "user";
}
}
3.4 自定义没有授权的页面
package com.dbl.gp_dbl_springboot_mybatis;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;
import java.util.Properties;
@SpringBootApplication
@MapperScan("com.dbl.gp_dbl_springboot_mybatis.mapper")
public class GpDblSpringbootMybatisApplication {
public static void main(String[] args) {
SpringApplication.run(GpDblSpringbootMybatisApplication.class, args);
}
@Bean
public SimpleMappingExceptionResolver simpleMappingExceptionResolver() {
SimpleMappingExceptionResolver resolver = new SimpleMappingExceptionResolver();
Properties properties = new Properties();
properties.setProperty("AuthorizationException", "/refuse");
resolver.setExceptionMappings(properties);
return resolver;
}
}
3.5 测试
4. 标签库的使用
4.1 扩展Thymeleaf中Shiro标签库
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
4.2 容器中注册 ShiroDialect对象
@SpringBootApplication
@MapperScan("com.dbl.gp_dbl_springboot_mybatis.mapper")
public class GpDblSpringbootMybatisApplication {
// 添加一个Thymeleaf的模板
@Bean
public ShiroDialect shiroDialect(){
return new ShiroDialect();
}
}
4.3 页面头部引入一下信息
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"
修改后的user.html
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"
xmlns:th="http://www.thymeleaf.org"
>
<head>
<meta charset="UTF-8">
<title>用户信息</title>
</head>
<body>
<h1>用户管理</h1>
<table border="1" style="width: 300px">
<tr>
<th>用户ID</th>
<th>用户姓名</th>
<th>创建时间</th>
<th>操作</th>
</tr>
<tr th:each="user:${list}">
<td th:text="${user.id}"></td>
<td th:text="${user.username}"></td>
<td th:text="${user.create_time}"></td>
</tr>
</table>
<hr>
<shiro:authenticated>
已登录<br>
</shiro:authenticated>
<span shiro:hasRole="role1">权限Role1</span><br>
<span shiro:hasRole="role2">权限Role2</span><br>
<shiro:guest>游客</shiro:guest>
</body>
</body>
</html>