① 后端:创建一个 springboot 项目
写入pom 配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.chen</groupId>
<artifactId>springboot-shiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-shiro</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--苞米豆-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<!--shiro 依赖-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.7.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
配置 application 文件:
server.port=8005
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/shiro?serverTimezone=Asia/Shanghai
spring.datasource.password=root
spring.datasource.username=root
编写主启动类:
@SpringBootApplication
@MapperScan(basePackages = "com.chen.springbootshiro.mapper")
public class SpringbootShiroApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootShiroApplication.class, args);
}
}
写入 entity 实体:
/**
* @program: springboot-shiro
* @description: 账号类的实体类
* @author: 陈
* @create: 2021-07-05 18:37
**/
@Data
@TableName("tab_account")
public class Account {
private Long accountId;
private Long empId;
private String username;
private String password;
private Long accountState;
private String salt;
private Long operatorId;
private Date operatorTime;
}
mapper层:
public interface UserMapper extends BaseMapper<Account> {
}
自定义Realm类:
/**
* @program: springboot-shiro
* @description: 自定义Realm类
* @author: 陈
* @create: 2021-07-05 15:56
**/
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserMapper userMapper;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
/**
* 认证方法
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 1.得到账号
String username = authenticationToken.getPrincipal().toString();
//根据账号查询用户信息
QueryWrapper<Account> wrapper = new QueryWrapper<>();
wrapper.eq("username",username);
Account account= userMapper.selectOne(wrapper);
if (account!=null){
/**
* 账号
* 表示从数据库获取密码
* 盐
*/
ByteSource byteSource=ByteSource.Util.bytes(account.getSalt());
//密码的比对由shiro自动比对
SimpleAuthenticationInfo info=new SimpleAuthenticationInfo(username,account.getPassword(),byteSource,this.getName());
return info;
}
return null;
}
}
cofig 配置类:
@Configuration
public class ShiroConfig {
//1.spring容器创建 securityManager对象
@Bean
public DefaultWebSecurityManager securityManager(Realm realm){
DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();
securityManager.setRealm(realm); //自定义realm对象
return securityManager;
}
//自定义Realm
@Bean
public Realm realm(CredentialsMatcher credentialsMatcher){
MyRealm myRealm=new MyRealm();
myRealm.setCredentialsMatcher(credentialsMatcher);//设置密码匹配器
return myRealm;
}
//创建一个密码匹配器
@Bean
public CredentialsMatcher credentialsMatcher(){
HashedCredentialsMatcher credentialsMatcher=new HashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName("MD5"); //指定加密方式 MD5
credentialsMatcher.setHashIterations(1024);
return credentialsMatcher;
}
//shiro 的过滤工厂
@Bean("shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean=new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/toLogin");
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
Map<String,String> map=new HashMap<>();
map.put("/login","anon");
map.put("/**","authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
//注入过滤器组件
@Bean
public FilterRegistrationBean<Filter> filter(){
FilterRegistrationBean registrationBean=new FilterRegistrationBean();
registrationBean.setName("shiroFilter");
registrationBean.addUrlPatterns("/*");
registrationBean.setFilter(new DelegatingFilterProxy());
return registrationBean;
}
控制层:
/**
* @program: springboot_shiro
* @description: 控制层
* @author: 陈
* @create: 2021-07-05 15:09
**/
@RestController
@CrossOrigin
public class LoginController {
@PostMapping("login")
public String login(String username,String password){
Subject subject= SecurityUtils.getSubject();
UsernamePasswordToken token=new UsernamePasswordToken(username,password);
try{
subject.login(token);
return "登录成功";
}catch (Exception e){
e.printStackTrace();
return "登录失败";
}
}
@GetMapping("toLogin")
public String toLogin(){
return "请先登录";
}
}
测试:
若 跳过 登录会出现错误:
前端测试成功
② 前端:
创建一个 login.vue 配置路径
主要代码:
<template>
<div>
<!--添加的对话框-->
<el-dialog
title="提示"
:visible.sync="loginDialogVisible"
width="30%"
>
<!--model:表单数据-->
<el-form label-width="80px" :model="loginForm" >
<el-form-item label="账号" >
<el-input v-model="loginForm.username"></el-input>
</el-form-item>
<el-form-item label="密码" >
<el-input v-model="loginForm.password"></el-input>
</el-form-item>
</el-form>
<span slot="footer" class="dialog-footer">
<el-button>取 消</el-button>
<el-button type="primary" @click="confirmInsertStu">确 定</el-button>
</span>
</el-dialog>
</div>
</template>
<script>
export default {
name: "login",
data(){
return {
//控制添加对话框的显示
loginDialogVisible:true,
//添加表单
loginForm:{},
}
},
methods:{
confirmInsertStu(){
var that=this;
this.$http.post(`http://localhost:8005/login?username=${this.loginForm.username}&password=${this.loginForm.password}`).then(function (result) {
console.log(result)
if (result.data=="登录成功"){
that.$message("登录成功");
}else{
that.$message("登录失败");
}
})
},
}
}
</script>
<style scoped>
</style>
测试:
密码正确 显示成功;
密码错误 显示失败;