SpringBoot整合Shiro
1.SpringBoot和Shiro的介绍
- SpringBoot:
Spring的三大核心思想:IOC(控制反转),DI(依赖注入),AOP(面向切面编程)。
SpringBoot简化了基于Spring的应用开发,Spring需要大量的xml配置文件。
- 关于Shiro:
这图比较经典吧,官方拿来的图,介绍了主要功能和辅助功能
Shiro主要面向Shiro开发团队所谓的“应用安全的四大基础” ——认证,授权,会话管理与密码加密:
- 认证: 或“登录”,用以验证用户身份。
- 授权: 访问控制, 比如决定谁可以访问某些资源。
- 会话管理: 管理用户相关的session,即使是在非web或EJB应用中。
- **加密:**可以非常方便地使用(各种)加密算法保证数据的安全。
Shiro还包含了一些其他功能以支持不同的应用环境,其中:
- 对Web的支持: Shiro自带的支持Web的API可以很容易地保证web应用的安全。
- 缓存:缓存在Apache Shiro的API中是“一等公民”,可以保证操作的快速高效。
- 并发: Apache Shiro的并发功能支持开发多线程的应用。
- 测试:对测试的支持可以帮助你编写单元测试与集成测试。
- “以…(身份)运行”(Run As):允许一个用户使用另外某个用户的身份(执行操作),这个功能常用于管理场景中(比如“以管理员身份运行”)。
- “自动登陆”(Remember Me):可以跨会话记住用户身份,只在某些特殊情况下才需要强制登录。
2.搭建SpringBoot环境
这个还用写吗…IDEA创建就完事儿了。
3.用thymeleaf作为模板
pom引入jar包
<!-- thymeleaf -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<properties>
<java.version>1.8</java.version>
<!-- 修改thymeleaf版本,为3.0以上,使得html语法宽松-->
<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
<!--这个版本也要加上,否则报错视图解析器问题-->
<thymeleaf-layout-dialect.version>2.0.4</thymeleaf-layout-dialect.version>
</properties>
4.整合SpringBoot+Shiro
4.1过滤器设置url访问权限
导入jar
pom.xml
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
创建配置类:
package com.shiro.demo.shiro;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
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;
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
//添加Shiro内置过滤器
/**
* Shiro内置过滤器,可以实现权限相关的拦截器
* 常用的过滤器:
* anon: 无需认证(登录)可以访问
* authc: 必须认证才可以访问
* user: 如果使用rememberMe的功能可以直接访问
* perms: 该资源必须得到资源权限才可以访问
* role: 该资源必须得到角色权限才可以访问
*/
Map <String,String> map = new LinkedHashMap();
//登录页无需认证
map.put("/login","anon");
map.put("/testThymleaf","anon");
//其他所有页面,都需要认真
map.put("/*/**","authc");
shiroFilterFactoryBean.setLoginUrl("/login");
//设置规则
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
return shiroFilterFactoryBean;
}
@Bean(name="securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
DefaultWebSecurityManager dwsm = new DefaultWebSecurityManager();
dwsm.setRealm(userRealm);
return dwsm;
}
@Bean(name="userRealm")
public UserRealm userRealm(){
return new UserRealm();
}
}
创建自定义Reaml
package com.shiro.demo.shiro;
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("执行认证逻辑");
return null;
}
}
controller类:
package com.shiro.demo.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class UserController {
@RequestMapping("/testThymleaf")
public String TestThymleaf (Model model){
model.addAttribute("name","陈亮");
return "test";
}
@RequestMapping("/user/add")
public String toAddUser(){
return "user/add";
}
@RequestMapping ("/user/update")
public String toUpdate(){
return "user/update";
}
@RequestMapping ("login")
public String toLogin(){
return "login";
}
}
4.2编写认证逻辑
在自定义realm中编写逻辑
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("执行认证逻辑");
String username = "chen";
String password = "123";
UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
//用户名不存在
if( !token.getUsername().equals(username)){
return null;
}
//用户名存在
//校验密码
return new SimpleAuthenticationInfo("",password,"");
}
controller中调用login方法,并捕获相关异常
@RequestMapping("/login")
public String login(String userName,String password,Model model){
//1.获取subject
Subject subject = SecurityUtils.getSubject();
//2.获取token
UsernamePasswordToken token = new UsernamePasswordToken(userName,password);
try {
//3.执行登录方法,获取自定义Realm做认证
subject.login(token);
//没有异常,登录成功,重定向 跳到到指定页面
return "redirect:/testThymleaf";
}catch (UnknownAccountException e){//用户名不存在
//捕获相对应的异常,给出不同信息
model.addAttribute("msg","用户名不存在");
return "login";
}catch (IncorrectCredentialsException e){//密码错误
model.addAttribute("msg","密码错误");
return "login";
}
}
4.3认证逻辑加入mybatis
导入相关依赖
<!-- SpringBoot的Mybatis启动器 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<!-- druid连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.9</version>
</dependency>
<!-- mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
配置application.properties
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.password=root
spring.datasource.username=root
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
mybatis.type-aliases-package=com.shiro.demo
创建mapper接口,和mapper.xml,service,service实现类~~~巴拉巴拉
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">
<!-- 该文件存放CRUD的sql语句 -->
<mapper namespace="com.shiro.demo.mapper.UserMapper">
<select id="findByName" parameterType="string" resultType="user">
SELECT id,
NAME,
PASSWORD
FROM
user where name = #{name}
</select>
<!-- <select id="findById" parameterType="int" resultType="user">
SELECT id,
NAME,
PASSWORD,
perms
FROM
user where id = #{value}
</select>-->
</mapper>
UserMapper
package com.shiro.demo.mapper;
import com.shiro.demo.entity.User;
public interface UserMapper {
public User findByName(String name);
}
注意:启动类加注解,扫描mapper接口,mapper接口上不需要家注解。
@SpringBootApplication
@MapperScan("com.shiro.demo.mapper")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
注意:用新版本IDEA开发时,如果你的mapper.xml放在java目录下,而不是在resources下,需要往pom.xml加入以下配置
<build>
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build>
4.3过滤器加入权限过滤
在ShiroFilterFactoryBean过滤器中,设置url访问权限
//设置权限
map.put("/user/add","perms[user:add]");
//设置无权限提示页面
shiroFilterFactoryBean.setUnauthorizedUrl("/toUnauth");
controller:
@RequestMapping("/toUnauth")
public String toUnauth (){
return "Unauth";
}
再加一个Unauth.html页面
4.4自定义Realm中加入授权
UserRealm:
public class UserRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection)
{
System.out.println("执行授权逻辑");
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermission("user:add");
return info;
}
}
和数据库关联进行授权:
UserReaml:
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行授权逻辑");
//获取Subject
Subject subject = SecurityUtils.getSubject();
//获取Principal,认证的时候设置了Principal为User对象
User user =(User) subject.getPrincipal();
//创建授权类
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//查数据库,查权限,并授权
info.addStringPermission(userService.findById(user.getId()).getPerms());
return info;
}
就是加了一个数据库查询而已,其他没啥不同的。写上Service、mapper接口、mapper.xml即可
4.5shiro权限标签
pom.xml导入依赖坐标:
<!-- thymeleaf整合shiro标签 -->
<dependency>
<groupId>com.github.theborakompanioni</groupId>
<artifactId>thymeleaf-extras-shiro</artifactId>
<version>2.0.0</version>
</dependency>
在ShiroCongfig配置类注入一个bean
@Bean
public ShiroDialect getShiroDialect(){
return new ShiroDialect();
}
修改HTML,加入shiro标签,
<div shiro:hasPermission="user:add">
增加用户:<a href="/user/add">增加</a><br>
</div>
<div shiro:hasPermission="user:update">
修改用户:<a href="/user/update">修改</a>
</div>