一、创建maven项目,引入依赖
<dependencies>
<dependency>
<groupId>org.apache.directory.studio</groupId>
<artifactId>org.apache.commons.codec</artifactId>
<version>1.8</version>
</dependency>
<!-- 自动依赖导入 shiro-core 和 shiro-web -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.5.3</version>
</dependency>
<!-- configure logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.11.0</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!--配置mybatis依赖-->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.2</version>
</dependency>
<!--缺少此jar包,导致@Mapper注解无效-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<!--版本1.2.0否则无效-->
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
<version>5.1.46</version>
</dependency>
</dependencies>
<!--还需要加点东西,便于springBoot识别后续用到的mapper文件和html资源-->
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
这些依赖包括MySQL、mybatis和logf4j依赖,之后都会用到
这是最基础的 application.properties 配置
spring.main.allow-bean-definition-overriding= true
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/syslog?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false
spring.datasource.username=root
spring.datasource.password=root
mybatis.configuration.mapUnderscoreToCamelCase=true
二、前期准备
shrio登录的时候会用到用户的账号密码做登录判断需要创建数据库和实体映射文件,之所以不用shiro.ini是因为更好的理解shrio框架的使用,而不是为了糊弄。
1、创建数据库用户表
create table sys_user(id varchar(255),user_name varchar(255),password varchar(255),phone varchar(255),avatar varchar(255));
2、创建实体类
package com.example.shiro_sys.entity;
import com.example.shiro_sys.util.BaseEntity;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class UserInfo{
private String userName;
private String password;
private String phone;
}
3、创建mapper和对应mybatis.xml文件
package com.example.shiro_sys.mapper;
import com.example.shiro_sys.entity.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Mapper
@Repository
public interface UserMapper {
public void insert ();
public UserInfo selectUserName (UserInfo userInfo);
}
<?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.example.shiro_sys.mapper.UserMapper">
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
insert into sys_user(user_name)
values (#{username})
</insert>
<select id="selectUserName" resultType="com.example.shiro_sys.entity.UserInfo">
select * from sys_user where user_name=#{userName}
</select>
</mapper>
在spring启动类中添加注解扫描mapper.xml文件
@MapperScan("com.example.shiro_sys.mapper")
package com.example.shiro_sys;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.mybatis.spring.annotation.MapperScan;
@SpringBootApplication
@MapperScan("com.example.shiro_sys.mapper")
public class ShiroSysApplication {
public static void main(String[] args) {
SpringApplication.run(ShiroSysApplication.class, args);
}
}
三、创建Shiro配置文件
这是我的文件目录有config配置类,controller控制层,mapper和service层,最后还有些页面静态资源。
1、创建配置类SpringShiroConfig,此类主要将访问请求拦截和放行请求。
package com.example.shiro_sys.config;
import org.apache.shiro.realm.Realm;
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.HashMap;
import java.util.Map;
@Configuration
public class SpringShiroConfig {
//1.创建自定义realm
@Bean
public Realm getRealm() {
CustomRealm customerRealm = new CustomRealm();
return customerRealm;
}
//2.创建shiroFilter //负责拦截所有请求
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//给filter设置安全管理器
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
//配置系统受限资源
//配置系统公共资源
Map<String, String> map = new HashMap<String, String>();
map.put("/user/login", "anon"); // anon 设置为公共资源,放行要注意anon和authc的顺序
map.put("/**", "authc"); //authc 请求这个资源需要认证和授权
//默认认证界面路径
shiroFilterFactoryBean.setLoginUrl("/login.html");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
//3.创建安全管理器
@Bean
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("getRealm") Realm realm) {
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
//给安全管理器设置
defaultWebSecurityManager.setRealm(realm);
return defaultWebSecurityManager;
}
}
2、创建自定义Realm类,此类主要是创建凭证用于登录判断。
package com.example.shiro_sys.config;
import com.example.shiro_sys.entity.UserInfo;
import com.example.shiro_sys.mapper.UserMapper;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class CustomRealm extends AuthorizingRealm {
@Autowired
private UserMapper userMapper;
// 授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
return null;
}
// 认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 获取当前登录的主体
String principal = (String) token.getPrincipal();
UserInfo userInfo = new UserInfo();
userInfo.setUserName(principal);
UserInfo user = userMapper.selectUserName(userInfo);
// 模拟数据库返回的数据
// 目前用户名为唯一标识
if (user.getUserName().equals(principal)) {
//用户名匹配成功后,将数据库查询到的用户密码存入上下文中,在调用subject.login(new UsernamePasswordToken(username,password));
//时会将存入上下文中的密码作比对,这里用的密码凭证是密码,也可以存放动态验证码
return new SimpleAuthenticationInfo(principal, user.getPassword(), this.getName());
}
return null;
}
}
四、测试
1、创建controller和静态访问页面
package com.example.shiro_sys.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("user")
public class UserController {
/**
* 用户登录
* @param username
* @param password
* @return
*/
@RequestMapping("login")
public String login(String username,String password){
System.out.println("~~~~~~login~~~~~");
// 获取当前登录用户
Subject subject = SecurityUtils.getSubject();
try {
// 执行登录操作
subject.login(new UsernamePasswordToken(username,password));
// 认证通过后直接跳转到index.jsp
return "redirect:/index.html";
} catch (UnknownAccountException e) {
e.printStackTrace();
System.out.println("用户名错误");
} catch (IncorrectCredentialsException e) {
e.printStackTrace();
System.out.println("密码错误");
} catch (Exception e) {
e.printStackTrace();
}
// 如果认证失败仍然回到登录页面
return "redirect:/login.html";
}
@RequestMapping("logout")
public String logout(){
Subject subject = SecurityUtils.getSubject();
subject.logout();
// 退出后仍然会到登录页面
return "redirect:/login.html";
}
public static void main(String[] args) {
Md5Hash md5Hash03 = new Md5Hash("1234567","1q2w3e",1024);
System.out.println(md5Hash03.toHex());
}
}
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org"
xmlns:shiro="https://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>登录</p>
<form action="/user/login" method="post">
用户名:<input type="text" name="username" > <br/>
密码 : <input type="text" name="password"> <br>
<input type="submit" value="登录">
</form>
</body>
</html>
<!DOCTYPE html>
<html lang="en" xmlns:th="https://www.thymeleaf.org"
xmlns:shiro="https://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>首页</h1>
<a href="/user/logout">退出用户</a>
</body>
</html>