Shiro是什么?是 Java 的一个安全框架,主要功能是实现认证与授权
步骤:
1.添加依赖
2.自定义Realm类执行授权和认证的逻辑
3.创建Shiro的配置类
4.创建登录的页面,成功的页面,提示无权限的页面
5.编写LoginController
6.运行测试
具体步骤如下:
- 1.依赖
- <!--thymeleaf依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--shiro依赖,实现认证与授权-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
- 2.自定义 Realm 类,
执行授权和认证的逻辑, Realm 充当了 Shiro 与应用安全数据之间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro 会从应用配置的 Realm 中查找用户及其权限信息
package com.xxx.common.shiro;
import org.apache.shiro.authc.*;
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 arg0) {
System.out.println("执行授权逻辑");
return null;
}
/**
* 执行认证逻辑
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken arg0) throws AuthenticationException {
System.out.println("执行认证逻辑");
//假设数据库的用户名和密码
String name = "admin";
String password = "123456";
//编写shiro判断逻辑,判断用户名和密码
//1.判断用户名
UsernamePasswordToken token = (UsernamePasswordToken) arg0;
if (!token.getUsername().equals(name)) {
//用户名不存在
return null;//shiro底层会抛出UnKnowAccountException
}
//2.判断密码
return new SimpleAuthenticationInfo("", password, "");
}
}
3.创建Shiro配置类
SecurityManager 会去 Authenticator(认证器)中查找相应的Realms,Realms 可以根据不同类型的 Realm 去查找用户信息,并进行判断是否认证成功。当配置 Shiro 时,你必须至少指定一个Realm,用于认证和(或)授权。也可以配置多个 Realm,但至少需要一个.
package com.xxx.common.shiro;
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
*/
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager);
/**
* Shiro内置过滤器,可以实现权限相关的拦截器
* 常用的过滤器:
* anon: 无需认证(登录)可以访问
* authc: 必须认证才可以访问
* user: 如果使用rememberMe的功能可以直接访问
* perms: 该资源必须得到资源权限才可以访问
* role: 该资源必须得到角色权限才可以访问
*
* URL 匹配及过滤规则汇总如下:
* 1) ”?”:匹配一个字符,如”/admin?”,将匹配” /admin1”、”/admin2”,但不匹配”/admin”;
* 2) ”*”:匹配零个或多个字符串,如”/admin*”,将匹配” /admin”、”/admin123”,但不匹配”/admin/1”;
* 3) ”**”:匹配路径中的零个或多个路径,如”/admin/**”,将匹配”/admin/a”、”/admin/a/b”;
* 4) anon:匿名过滤器,表示通过了 url 配置的资源都可以访问,如:“/statics/**=anon”表示statics目录下所有资源都能访问;
* 5) authc:基于表单的过滤器,表示通过了 url 配置的资源需要登录验证,否则跳转到登录,如:“/unauthor.jsp=authc”如果用户没有登录访问 unauthor.jsp 则直接跳转到登录。
*/
Map<String,String> filterMap = new LinkedHashMap<String,String>();
filterMap.put("/testThymeleaf", "anon");
filterMap.put("/login", "anon");
filterMap.put("/**", "authc");
//修改调整的登录页面
shiroFilterFactoryBean.setLoginUrl("/toLogin");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
return shiroFilterFactoryBean;
}
/**
* 创建DefaultWebSecurityManager
*/
@Bean(name = "securityManager")
public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//关联realm
securityManager.setRealm(userRealm);
return securityManager;
}
/**
* 创建Realm
*/
@Bean(name = "userRealm")
public UserRealm getRealm() {
return new UserRealm();
}
}
- 4.创建登录页面、成功页面和无权限提示页面
在 templates 目录下新建页面 login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面:测试shiro</title>
</head>
<body>
<h3>登录</h3>
<form method="post" action="login">
用户名:<input type="text" name="name"/><br/>
密码:<input type="password" name="password"/><br/>
<input type="submit" value="登录"/>
</form>
</body>
</html>
在templates目录下创建test.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<title>测试Thymeleaf的使用</title>
</head>
<body>
<h3 th:text="${name}"></h3>
</body>
</html>
在templates目录下创建noAuth.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>没有权限</h1>
</body>
</html>
- 编写LoginController
package com.xxx.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.RequestMapping;
@Controller
public class LoginController {
/**
* 登录逻辑处理
*/
@RequestMapping("/login")
public String login(String name, String password, Model model) {
/**
* 使用Shiro编写认证操作
*/
// 1.获取Subject
Subject subject = SecurityUtils.getSubject();
// 2.封装用户数据
UsernamePasswordToken token = new UsernamePasswordToken(name, password);
// 3.执行登录方法
try {
subject.login(token);
// 登录成功
// 跳转到test.html
return "redirect:/testThymeleaf";
} catch (UnknownAccountException e) {
// 登录失败:用户名不存在
model.addAttribute("msg", "用户名不存在");
return "login";
} catch (IncorrectCredentialsException e) {
// 登录失败:密码错误
model.addAttribute("msg", "密码错误");
return "login";
}
}
@RequestMapping("/toLogin")
public String toLogin(Model model) {
return "login";
}
@RequestMapping("/toNoAuth")
public String toNoAuth(Model model) {
return "noAuth";
}
/**
* 测试Thymeleaf:
* 将带着数据跳转到模板文件夹下的test.html文件中显示
*
* @param model
* @return
*/
@RequestMapping("/testThymeleaf")
public String testThymeleaf(Model model) {
//把数据存入model
model.addAttribute("name", "Hello");
//返回test.html
return "test";
}
}
- 运行测试
在shiro配置类中已经设置了需认证的请求及拦截跳转登录页,所以启动项目后,地址随便拼写都是自动跳转到登录页,(包括静态),登录成功后,即可访问其他资源,关闭浏览器即失效
[{"src":"xap:resources/18e040240c3f0df0cfd2cf05c8bfdf294d1849e98d29681d2ac5358671749429.png","width":495,"height":324}]
请求地址为index.html,程序会自动跳转到登录
- shiro实现授权:
- 有些资源没有权限就访问不到
- 修改配置类:
- 设置哪些资源需要什么权限
filterMap.put("/getUserList", "perms[user:get]");
- 如果没有权限怎么办? 跳转到无权限的页面
shiroFilterFactoryBean.setUnauthorizedUrl("/toNoAuth");
- 在controller中有处理toNoAuth请求的代码,跳转到对应的页面
@RequestMapping("/toNoAuth")
public String toNoAuth(Model model) {
return "noAuth";
}
- 运行测试,登录成功后,getUserList资源还是访问不了,会验证是否拥有user:get的权限(字符串),会跳转到对应的提示页面
- 修改自定义Realm类,设置对应的权限
- /**
* 执行授权逻辑
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {
System.out.println("执行授权逻辑");
// return null;
// 给资源进行授权
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
// 添加资源的授权字符串
info.addStringPermission("user:get");
return info;
}
- 运行测试,再次登录成功后,getUserList资源可以访问了