Springboot集成shiro
程序员文章站
2022-05-26 08:50:42
...
Springboot集成shiro
项目目录
1,shiro简介:
subject:用户主体
security:安全管理器
Realm:shiro连接数据的桥梁
2,springboot集shiro
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
3,自定义realm类
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
public class UserRealm extends AuthorizingRealm {
/*
* 执行授权逻辑
* */
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行授权逻辑");
return null;
}
/*
* 执行认证逻辑
* */
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行认证逻辑");
String name = "wangxin";
String password = "123456";
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
//1.判断用户名
if(!token.getUsername().equals(name)){
return null;//shiro低层会抛出UnknownAccountException异常
}
//2.判断密码
return new SimpleAuthenticationInfo("",password,"");
}
}
4,编写shiro配置类
import org.apache.shiro.mgt.DefaultSecurityManager;
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;
@Configuration
public class shiroConfig {
/*
* 创建ShiroFilterFactoryBean
*
*/
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
factoryBean.setSecurityManager(securityManager);
/*
* shiro内置过滤器,
* 常用过滤器
* anon:无需认证(登录),可以访问
* authc:必须认证才可以访问
* user:如果使用rememeber me就可以直接访问
* perms:有资源权限才可以访问
* role:必须得到角色权限才可以访问
* */
Map<String,String> filter = new LinkedHashMap<>();
filter.put("/user/add","authc");
filter.put("/user/update","authc");
//默认跳转login.jsp
//修改跳转的页面
shiroFilterFactoryBean.setLoginUrl("/user/tologin");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filter);
return factoryBean;
}
/*
* 创建DefaultWebSecurityManager
* */
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm")UserRealm userRealm){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
return securityManager;
}
/*
*
* 创建realm
* */
@Bean(name ="userRealm")
public UserRealm getrealm(){
return new UserRealm();
}
}
5,整合Mybatis实现登录认证
(1)导入依赖
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.19</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
(2)配置application.yml
datasource:
driver-class-name: com.mysql.jdbc.Driver
username: root
password: root
url: jdbc:mysql://localhost:3306/db_cqb?serverTimezone=UTC
type: com.alibaba.druid.pool.DruidDataSource
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
maxPoolPreparedStatementPerConnectionSize: 20
filters: stat,wall
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
mybatis:
type-aliases-package: com.godx.entity
(3) 编写user实体类
public class User {
private Integer id;
private String username;
private String password;
private String role;
public User(){}
public User(Integer id, String username, String password, String role) {
this.id = id;
this.username = username;
this.password = password;
this.role = role;
}
public Integer getId() {
return id;
}
public void setId(Integer 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;
}
}
(4) 编写UserMapper接口
public interface UserMapper {
public User findByName(String username);
public User findById(Integer id);
}
(5)编写UserMapper.xml
<?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.godx.mapper.UserMapper">
<select id="findByName" resultType="user">
select * from user where username = #{username};
</select>
<select id="findById" resultType="user">
select * from user where id = #{id};
</select>
</mapper>
(6)编写UserService接口和UserServiceImpl实现类
import com.godx.entity.User;
public interface UserService {
public User findByName(String username);
public User findById(Integer id);
}
import com.godx.entity.User;
import com.godx.mapper.UserMapper;
import com.godx.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User findByName(String username) {
User user = userMapper.findByName(username);
return user;
}
}
(7)编写UserController类
import com.godx.service.UserService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.sql.SQLOutput;
@Controller
@RequestMapping("/user")
@Api(tags = "user")
public class UserController {
@Autowired
private UserService userService;
@RequestMapping("/hello")
public String hello(){
return "test";
}
@RequestMapping("/add")
public String add(){
return "addUser";
}
@RequestMapping("/tologin")
public String tologin(){
return "login";
}
@RequestMapping("/update")
public String upate(){
return "updateUser";
}
@RequestMapping("/login")
public String login(String username, String password, Model model){
/*
* 使用shiro编写用户登录*/
//1.获取Subject对象
Subject subject = SecurityUtils.getSubject();
//2,封装用户数据
UsernamePasswordToken token = new UsernamePasswordToken(username,password);
//3,执行登录
try {
subject.login(token);
return "test";
}catch (UnknownAccountException e){
model.addAttribute("msg","用户名不存在");
return "login";
}catch (IncorrectCredentialsException e){
model.addAttribute("msg","密码错误");
return "login";
}
}
/*@ApiOperation(value = "好人",notes = "hr")
@RequestMapping("/good")
public String good(){
return "You are a good man!";
}*/
}
6,修改UserRealm
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行认证逻辑");
/* String name = "wangxin";
String password = "123456";*/
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
User user = userService.findByName(token.getUsername());
System.out.println(user.getUsername()+"/"+user.getPassword());
//1.判断用户名
if(user==null){
return null;//shiro低层会抛出UnknownAccountException异常
}
//2.判断密码
return new SimpleAuthenticationInfo(user,user.getPassword(),"");
}
7,Html页面
(1)login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h3 style="color: red" th:text="${msg}"></h3>
<form method="post" action="/user/login">
<div>
用户名:<input type="text" name="username">
</div>
<div>
密码:<input type="password" name="password">
</div>
<div>
<input type="submit" value="登录">
</div>
</form>
</body>
</html>
其他页面简单不放出来了
8,SpringBoot整合Shiro实现用户授权
(1) 使用shiro内置过滤器进行拦截
将原来的ShiroConfig修改成以下
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager")DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
/*
* shiro内置过滤器,
* 常用过滤器
* anon:无需认证(登录),可以访问
* authc:必须认证才可以访问
* user:如果使用rememeber me就可以直接访问
* perms:有资源权限才可以访问
* role:必须得到角色权限才可以访问
* */
Map<String,String> filter = new LinkedHashMap<>();
filter.put("/user/add","authc");
filter.put("/user/update","authc");
filter.put("/user/hello","authc");
//授权过滤器
//注意:当前授权拦截后,shiro会自动跳转到未授权的页面
//filter.put("/user/add","perms[user:add]");
//连接数据库动态查询
filter.put("/user/add","perms[admin]");
filter.put("/user/update","perms[test]");
//设置权限不够跳转的页面
shiroFilterFactoryBean.setUnauthorizedUrl("/user/noAuth");
//默认跳转login.jsp
//修改跳转的页面
shiroFilterFactoryBean.setLoginUrl("/user/tologin");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filter);
return shiroFilterFactoryBean;
}
(2)关联数据库动态授权
修改UserRealm
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行授权逻辑");
//给资源进行授权:
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
//获取当前的用户
Subject subject = SecurityUtils.getSubject();
User user = (User) subject.getPrincipal();
User dbuser = userService.findById(user.getId());
simpleAuthorizationInfo.addStringPermission(dbuser.getRole());
return simpleAuthorizationInfo;
}
9,thymeleaf整合shiro标签
(1)导入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/com.github.theborakompanioni/thymeleaf-extras-shiro -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
(2)配置ShiroDialect
在ShiroConfig配置类中加入以下代码
/*
*
* 配置ShiroDialect用于thymeleaf和shiro的标签*/
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
(3)test.html页面修改
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div shiro:hasPermission="admin">
<a href="/user/add">用户添加</a>
</div>
<div shiro:hasPermission="test">
<a href="/user/update">用户修改</a>
</div>
</body>
</html>
10,安全退出
(1)UserController添加logout方法
@RequestMapping("/logout")
public String logout(){
Subject subject = SecurityUtils.getSubject();
subject.logout();
return "login";
}