文章目录
参考了https://www.bilibili.com/video/BV1ct411x7CN
初始准备及配置
- 创建springboot项目
- 导入依赖列表
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
<!--MyBatis相关依赖-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.37</version>
</dependency>
<!--springboot-MyBatis启动器-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
shiro核心API
图片来自https://www.bilibili.com/video/BV1ct411x7CN?p=5
创建配置类
config文件
package com.example.shiro.config;
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.LinkedHashMap;
import java.util.Map;
/**
* shiro配置类
*/
@Configuration
public class ShiroConfig {
/**
* 创建ShiroFilterFactoryBean
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getSecurityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加shiro内置过滤器
Map<String, String> filterMap = new LinkedHashMap<String, String>();
// filterMap.put("/add", "authc");
// filterMap.put("/update", "authc");
//授权过滤器,要放在最上面,否则会失效
filterMap.put("/add", "perms[user:add]");
filterMap.put("/", "anon");
//放行login
filterMap.put("/login", "anon");
filterMap.put("/*", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
//设置过滤后跳转的页面
shiroFilterFactoryBean.setLoginUrl("/toLogin");
//设置未授权提示页面,这里因为已经是用户验证过了,所以不必在过滤器中再放行一次
shiroFilterFactoryBean.setUnauthorizedUrl("/unAuth");
return shiroFilterFactoryBean;
}
/**
* 创建DefaultWebSecurityManager
* @param userRealm
* @return
*/
@Bean
public DefaultWebSecurityManager getSecurityManager(@Qualifier("getRealm") UserRealm userRealm){
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
//关联Realm
defaultWebSecurityManager.setRealm(userRealm);
return defaultWebSecurityManager;
}
/**
* 创建realm
* @return
*/
@Bean
public UserRealm getRealm(){
return new UserRealm();
}
}
自定义UserRealm
package com.example.shiro.config;
import com.example.shiro.domain.User;
import com.example.shiro.service.UserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
public class UserRealm extends AuthorizingRealm {
/**
* 执行授权逻辑
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//给资源授权
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//添加资源的授权字符串,认证中perms指定的
info.addStringPermission("user:add");
return info;
}
//注入业务
@Autowired
private UserService userService;
/**
* 执行认证逻辑
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
User user = userService.findByUName(token.getUsername());
if(user == null){
return null; //这里return null,shiro底层就会抛出UnknownAccountException
}
//判断密码
return new SimpleAuthenticationInfo("", user.getPassword(), ""); //第二个是数据库中密码,第三个是realmName
}
}
配置类中常用内置过滤器分析
参考了https://github.com/YUbuntu0109/YUbuntu0109.github.io/blob/HexoBackup/source/_posts/Shiro%E7%9A%84%E6%8B%A6%E6%88%AA%E5%99%A8%E6%9C%BA%E5%88%B6.md
anon
: 匿名拦截器,即不需要登录即可访问。类似于filterMap.put("/", "anon");
将/的请求放行。authc
: 表示需要认证(登录)才能使用,类似于filterMap.put("/*", "authc");
将所有请求进行拦截。user
: 用户拦截器,用户已经身份验证/记住我的登录。perms
: 权限授权拦截器,验证用户是否拥有资源权限。roles
: 角色授权拦截器,验证用户是否拥有资源角色。
用户认证的简单逻辑
- 获取subject
- 封装用户数据
执行登录方法
subject.login会去调用UserRealm
中的doGetAuthenticationInfo
方法进行认证,需要在里面编写认证逻辑。
连接mybatis
配置相关依赖
见初始配置中mybatis相关依赖
部分
配置application.properties
spring.datasource.driverClassName = com.mysql.jdbc.Driver
spring.datasource.url = jdbc:mysql://localhost:3306/student
spring.datasource.username = root
spring.datasource.password = 123456
spring.datasource.type = com.alibaba.druid.pool.DruidDataSource
mybatis.type-aliases-package=com.example.domain
所用到的其他类和页面
- UserController
package com.example.shiro.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.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class UserController {
@GetMapping("add")
public String add(){
return "/user/add.html";
}
@GetMapping("update")
public String update(){
return "/user/update.html";
}
@GetMapping("toLogin")
public String toLogin(){
return "/login.html";
}
/**
* 登录逻辑处理
*/
@PostMapping("/login")
public String login(String name, String pwd, Model model){
//1.获取subject
Subject subject = SecurityUtils.getSubject();
//2.封装用户数据
UsernamePasswordToken token = new UsernamePasswordToken(name, pwd);
//3.执行登陆方法
try {
subject.login(token);
//登陆成功
return "redirect:/";
}
catch (UnknownAccountException e){
//登陆失败: 用户名不存在
model.addAttribute("msg", "用户名不存在");
return "login";
}
catch (IncorrectCredentialsException e){
//登陆失败: 密码错误
model.addAttribute("msg", "密码错误");
return "login";
}
}
}
- 静态页面结构