1.导入依赖
org.apache.shiro
shiro-core
1.8.0
org.slf4j
jcl-over-slf4j
1.7.21
org.slf4j
slf4j-log4j12
1.7.21
log4j
log4j
1.2.17
org.apache.shiro
shiro-core
1.8.0
2.配置文件
shiro.ini
[users]
# user 'root' with password 'secret' and the 'admin' role
root = secret, admin
# user 'guest' with the password 'guest' and the 'guest' role
guest = guest, guest
# user 'presidentskroob' with password '12345' ("That's the same combination on
# my luggage!!!" ;)), and role 'president'
presidentskroob = 12345, president
# user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz'
darkhelmet = ludicrousspeed, darklord, schwartz
# user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz'
lonestarr = vespa, goodguy, schwartz
# -----------------------------------------------------------------------------
# Roles with assigned permissions
#
# Each line conforms to the format defined in the
# org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc
# -----------------------------------------------------------------------------
[roles]
# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *
# The 'schwartz' role can do anything (*) with any lightsaber:
schwartz = lightsaber:*
# The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with
# license plate 'eagle5' (instance specific id)
goodguy = winnebago:drive:eagle5
log4j.properties
log4j.rootLogger=INFO, stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n
# General Apache libraries
log4j.logger.org.apache=WARN
# Spring
log4j.logger.org.springframework=WARN
# Default Shiro logging
log4j.logger.org.apache.shiro=INFO
# Disable verbose logging
log4j.logger.org.apache.shiro.util.ThreadContext=WARN
log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN
3.快速开始测试
Subject currentUser = SecurityUtils.getSubject();
Session session = currentUser.getSession();
currentUser.isAuthenticated()
currentUser.getPrincipal()
currentUser.hasRole()
currentUser.isPermitted()
currentUser.logout();
thymeleaf
org.thymeleaf
thymeleaf-spring5
3.0.11.RELEASE
org.thymeleaf.extras
thymeleaf-extras-java8time
3.0.4.RELEASE
thymeleaf
语法提示
设置自定义Realm,重写授权认证方法
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7diBD6y4-1641475033014)(/Users/heroma/Library/Application Support/typora-user-images/image-20220104191443906.png)]
package com.hero.config;
import com.hero.pojo.User;
import com.hero.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import sun.tools.jstat.Token;
//自定义UserRealm,继承AuthorizingRealm
public class UserRealm extends AuthorizingRealm {
@Autowired
UserService userService;
//授权
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行了授权:doGetAuthorizationInfo");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// info.addStringPermission("user:add");
Subject subject = SecurityUtils.getSubject();
User currentUser = (User)subject.getPrincipal();
//设置当前用户的权限
info.addStringPermission(currentUser.getPerms());
return info ;
}
//认证
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行了认证:doGetAuthorizationInfo");
//用户名 密码 数据中获取
//连接数据库
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
User user = userService.queryUserByName(token.getUsername());
if (user == null){
return null; //抛出异常
}
Subject subject = SecurityUtils.getSubject();
Session session = subject.getSession();
session.setAttribute("loginUser", user);
//密码认证,shiro做
return new SimpleAuthenticationInfo(user,user.getPwd(),"");
}
}
shiro配置类,springboot需要管理三个类
UserRealm
类 //创建Realm对象,需要自定义
@Bean
public UserRealm userRealm(){
return new UserRealm();
}
2. `DefaultWebSecurityManager`
//DefaultWebSecurityManager
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
return securityManager;
}
3. `ShiroFilterFactoryBean`
//ShiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
//设置安全管理器
bean.setSecurityManager(securityManager);
//添加shiro过滤器
/**
* anon:无需认证就可访问
* authc:必须认证了才可访问
* user:必须y拥有 记住我 功能才能使用
* perms:拥有某个资源的权限才能访问
* role:拥有某个角色的权限才能访问
*/
Map filterChainDefinitionMap = new LinkedHashMap<>();
// filterChainDefinitionMap.put("/user/add","authc");
// filterChainDefinitionMap.put("/user/update","authc");
//授权 正常情况下未授权会转换到未授权页面
filterChainDefinitionMap.put("/user/add","perms[user:add]");
filterChainDefinitionMap.put("/user/update","perms[user:update]");
// filterChainDefinitionMap.put("/user/*","perms[user:all]");
filterChainDefinitionMap.put("/user/*","authc");
bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
bean.setLoginUrl("/toLogin");
bean.setUnauthorizedUrl("/noauth");
return bean;
}
导入相关依赖
com.github.theborakompanioni
thymeleaf-extras-shiro
2.0.0
mysql
mysql-connector-java
log4j
log4j
1.2.17
com.alibaba
druid
1.1.17
org.projectlombok
lombok
1.18.20
org.mybatis.spring.boot
mybatis-spring-boot-starter
2.1.4
org.springframework.boot
spring-boot-starter-web
org.springframework.boot
spring-boot-starter-test
test
org.apache.shiro
shiro-spring
1.4.1
org.thymeleaf
thymeleaf-spring5
3.0.11.RELEASE
org.thymeleaf.extras
thymeleaf-extras-java8time
3.0.4.RELEASE
配置application.yml
文件
spring:
datasource:
username: "root"
password: "031516"
#?serverTimezone=UTC解决时区的报错
url: jdbc:mysql://localhost:3306/mybatis?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
#Spring Boot 默认是不注入这些属性值的,需要自己绑定
#druid 数据源专有配置
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:监控统计、log4j:日志记录、wall:防御sql注入
#如果允许时报错 java.lang.ClassNotFoundException: org.apache.log4j.Priority
#则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
mybatis
mybatis:
type-aliases-package: com.hero.pojo
mapper-locations: mapper/*.xml
创建用户表
create table mybatis.user
(
id int not null,
name varchar(255) not null,
pwd varchar(255) not null,
perms varchar(255) null
);
创建pojo类,跟数据库字段相同
package com.hero.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private int id;
private String name;
private String pwd;
private String perms;
}
创建mapper接口
package com.hero.mapper;
import com.hero.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
@Repository
@Mapper
public interface UserMapper {
public User queryUserByName(String name);
}
绑定UserMapper.xml
文件
创建UserService
接口
package com.hero.service;
import com.hero.pojo.User;
public interface UserService {
public User queryUserByName(String name);
}
UserService
的接口实现类UserServiceImpl
package com.hero.service;
import com.hero.mapper.UserMapper;
import com.hero.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserMapper userMapper;
@Override
public User queryUserByName(String name) {
return userMapper.queryUserByName(name);
}
}
编写Mycontroller
package com.hero.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.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class Mycontroller {
@RequestMapping({"/","/index"})
public String toIndex(Model model){
model.addAttribute("msg", "hello,shiro");
return "index";
}
@RequestMapping("/user/add")
public String toAdd(){
return "user/add";
}
@RequestMapping("/user/update")
public String toUpdate(){
return "user/update";
}
@RequestMapping("/toLogin")
public String toLogin(){
return "login";
}
@RequestMapping("/login")
public String login(String userName, String passWord, Model model){
//读取当前用户
Subject securityManager = SecurityUtils.getSubject();
//封装用户登录数据
UsernamePasswordToken token = new UsernamePasswordToken(userName, passWord);
try {
securityManager.login(token);//执行登录的方法
return "index";
}catch (UnknownAccountException e){
model.addAttribute("msg", "用户错误");
return "login";
}catch (IncorrectCredentialsException e){
model.addAttribute("msg", "密码错误");
return "login";
}
}
@RequestMapping("/noauth")
@ResponseBody
public String noAuth(){
return "未经授权";
}
@RequestMapping("/logout")
public String logOut(){
//读取当前用户
Subject subject = SecurityUtils.getSubject();
subject.logout();
return "index";
}
}
主页
首页
首页
登录
Title
登录
添加
Title
add
更新
Title
update