springboot+shiro+mybatis安全框架整合
springboot+shiro+mybatis maven项目整合
1.引入依赖
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
<!--数据库连接依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--durid的数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!--mybits依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--thymeleaf依赖-->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>
<!--thymeleaf整合shiro依赖-->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
2、创建实体类
public class User implements Serializable{
private int id;
private String username;
private String password;
private String role;
public User() {
}
public User(int id, String username, String password, String role) {
this.id = id;
this.username = username;
this.password = password;
this.role = role;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
}
3、创建realm类
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了=>授权doGetAuthorizationInfo");
Subject subject = SecurityUtils.getSubject();
User currentUser = (User) subject.getPrincipal();
System.out.println(currentUser.getUsername());
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//多角色我在数据的是用逗号隔开的字符串,认证操作跟你配置的数据库做处理,但是 都是用info.addStringPermission(‘角色’)来认证
String[] split = currentUser.getRole().split(",");
for (String s : split) {
info.addStringPermission(s);
}
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了=>认证doGetAuthenticationInfo");
/*
此代码是不链接数据库的测试代码
String username = "root";
String password = "root";
UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
System.out.println(userToken.getUsername());
if (!username.equals(userToken.getUsername())){
return null;
}*/
UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
//System.out.println(userToken.getUsername());
//链接真是数据库
User user = userService.findByName(userToken.getUsername());
if (user == null){
return null;
}
//将实体类存到shiro的回话当中,用于页面展示登录用户
Subject subject = SecurityUtils.getSubject();
Session session = subject.getSession();
session.setAttribute("loginUser",user);
return new SimpleAuthenticationInfo(user,user.getPassword(),"");
}
}
4、创建shiro控制类
@Configuration
public class ShiroConfig {
//ShiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
filterFactoryBean.setSecurityManager(securityManager);
/*
anon: 无需认证就可以访问
authc: 必须认证才能访问
user: 必须拥有记住我功能才能用
perms: 拥有对某个资源的权限才能访问
role: 拥有某个角色权限才能访问
filterMap.put("/user/add","authc");//设置认证链接
filterMap.put("/user/update","authc");//设置认证链接
*/
Map<String,String> filterMap = new LinkedHashMap<>();
filterMap.put("/user/add","perms[root]");
filterMap.put("/user/update","perms[update]");
filterMap.put("/user/*","authc");//设置认证链接
filterFactoryBean.setFilterChainDefinitionMap(filterMap);
filterFactoryBean.setLoginUrl("/toLogin");
//设置未授权跳转
// filterFactoryBean.setUnauthorizedUrl("未授权跳转的url");
return filterFactoryBean;
}
//DefaultWebSecurityManager
@Bean(name = "securityManager")
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("myrealm") MyRealm myRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(myRealm);
securityManager.setRememberMeManager(rememberMeManager());
return securityManager;
}
//创建realm对象
@Bean(name = "myrealm")
public MyRealm myRealm(){
return new MyRealm();
}
//配置thymeleaf和shiro的整合
@Bean()
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
/**
* cookie对象;
* rememberMeCookie()方法是设置Cookie的生成模版,比如cookie的name,cookie的有效时间等等。
* @return
*/
@Bean
public SimpleCookie rememberMeCookie(){
/* //System.out.println("ShiroConfiguration.rememberMeCookie()");
//这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
//<!-- 记住我cookie生效时间30天 ,单位秒;-->
simpleCookie.setMaxAge(259200);
return simpleCookie;*/
//这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
//setcookie的httponly属性如果设为true的话,会增加对xss防护的安全系数。它有以下特点:
//setcookie()的第七个参数
//设为true后,只能通过http访问,javascript无法访问
//防止xss读取cookie
simpleCookie.setHttpOnly(true);
simpleCookie.setPath("/");
//<!-- 记住我cookie生效时间30天 ,单位秒;-->
simpleCookie.setMaxAge(2592000);
return simpleCookie;
}
/**
* cookie管理对象;
* rememberMeManager()方法是生成rememberMe管理器,而且要将这个rememberMe管理器设置到securityManager中
* @return
*/
@Bean
public CookieRememberMeManager rememberMeManager(){
//System.out.println("ShiroConfiguration.rememberMeManager()");
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
//rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位)
cookieRememberMeManager.setCipherKey(Base64.decode("2AvVhdsgUs0FSA3SDFAdag=="));
return cookieRememberMeManager;
}
/**
* FormAuthenticationFilter 过滤器 过滤记住我
* @return
*/
@Bean
public FormAuthenticationFilter formAuthenticationFilter(){
FormAuthenticationFilter formAuthenticationFilter = new FormAuthenticationFilter();
//对应前端的checkbox的name = rememberMe
formAuthenticationFilter.setRememberMeParam("rememberMe");
return formAuthenticationFilter;
}
}
5、编写controller 登陆退出方法
@Controller
public class MyController {
@RequestMapping("login")
public String login(Model model,String username,String password,boolean rememberMe){
Subject subject = SecurityUtils.getSubject();
AuthenticationToken token = new UsernamePasswordToken(username,password,rememberMe);
try {
subject.login(token);
return "index";
} catch (UnknownAccountException uae) {
model.addAttribute("msg","用户名错误");
return "loginView";
}catch (IncorrectCredentialsException ice){
model.addAttribute("msg","密码错误");
return "loginView";
}
}
@RequestMapping("quite")
public String quite(){
Subject subject = SecurityUtils.getSubject();
Session session = subject.getSession();
session.removeAttribute("loginame");
subject.logout();
return "index";
}
}
在这里,基础的页面跳转我是做了一个前端控制器的控制类,大家也可以在controller里面添加跳转的url
@Configuration
public class WebConfig implements WebMvcConfigurer{
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/user/add.html").setViewName("/user/add");
registry.addViewController("/user/update.html").setViewName("user/update");
registry.addViewController("/user/add").setViewName("/user/add");
registry.addViewController("/user/update").setViewName("user/update");
registry.addViewController("/toLogin").setViewName("loginView");
}
}
6、编写业务层(ps:这是两个类)
public interface UserService {
User findByName(String username);
}
@Service
public class UserServiceImlp implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User findByName(String username) {
return userMapper.findByName(username);
}
}
7、编写持久层接口
@Repository
@Mapper
public interface UserMapper {
User findByName(String username);
}
8、编写sql
<?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.shiro.mapper.UserMapper">
<select id="findByName" resultType="user">
select * FROM `user` WHERE username = #{username}
</select>
</mapper>
数据库字段配置
9、yml文件配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
username: root
password: 123456
#serverTimezone=UTC时区错误
url: jdbc:mysql://localhost:3306/test?serverTimezone=UTC
driver-class-name: com.mysql.jdbc.Driver
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
#热部署配置
devtools:
restart:
enabled: true
additional-paths: src/main/java
exclude: WEB-INF/**
freemarker:
cache: false #关闭thymeleaf缓存
mybatis:
type-aliases-package: com.yipengzhan.pojo #实体类包扫描
mapper-locations: classpath:com/shiro/mapper/*.xml #如果mybatis的xml文件必须与持久层接口文件路径一致
文件存放路径
index.html文件内容
<!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>
</head>
<body>
<!--验证当前用户是否为“访客”,即未认证(包含未记住)的用户。-->
<shiro:guest>
<a th:href="@{/toLogin}">登录</a>
</shiro:guest>
<!--认证通过或已记住的用户-->
<shiro:user>
欢迎<shiro:principal property="username"/>
<a th:href="@{/quite}">退出</a>
</shiro:user>
<!--验证当前用户是否拥有指定权限。 -->
<div shiro:hasPermission="root">
<a th:href="@{/user/add}">add</a>
</div>||
<div shiro:hasPermission="update">
<a th:href="@{/user/update}">update</a>
</div>
</body>
</html>
loginview.html页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<p th:text="${msg}" style="color: red"></p>
<form th:action="@{/login}" method="post">
用户名:<input name="username"><br>
密码:<input name="password"><br>
<input type="checkbox" name="rememberMe" value="true"/>记住我<br>
<input type="submit">
</form>
</body>
</html>
我用的springboot的版本的是2.3.3,如果通过以上的没有实现整合,建议更换一下springbot版本
版权声明:本文为weixin_45815347原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。