shiro的使用
什么都不用说了,我们直接看代码吧!!
pom.xml
导入依赖
<!-- shiro安全框架 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
Shiro配置类
ShiroConfig
import com.yumbo.shiro.MyRealm;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @Author: GrainFull
* @Date: 2021/4/21 21:48
* @Description: Shiro配置类
*/
@Configuration
public class ShiroConfig {
private Logger logger = LoggerFactory.getLogger(ShiroConfig.class);
@Bean
public MyRealm getMyRealm() {
logger.info("=====准备执行myRealm校验=====");
return new MyRealm();
}
/**
* 安全管理器
* 权限管理,配置主要是Realm的管理认证
*
* @return
*/
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(getMyRealm());
logger.info("=====securityManager注册完成=====");
return securityManager;
}
/**
* 注入 Shiro 过滤器
* Filter工厂,设置对应的过滤条件和跳转条件
*
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean() {
//定义 shiroFactoryBean
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//设置自定义的 securityManager安全管理器
shiroFilterFactoryBean.setSecurityManager(securityManager());
//设置默认登录的 URL,身份认证失败会访问该 URL
shiroFilterFactoryBean.setLoginUrl("/login");
//设置成功之后要跳转的链接
shiroFilterFactoryBean.setSuccessUrl("/index");
// 设置未授权界面,权限认证失败会访问该 URL
shiroFilterFactoryBean.setUnauthorizedUrl("/login");
// LinkedHashMap 是有序的,进行顺序拦截器配置
Map<String, String> map = new LinkedHashMap<>();
//配置可以匿名访问的地址,可以根据实际情况自己添加,放行一些静态资源等,anon 表示放行
//登录 URL 放行
map.put("/login", "anon");//登录页面放行
map.put("/doLogin", "anon");//登录请求接口放行
map.put("/404", "anon");//登录请求接口放行
map.put("/plugins/**", "anon");//静态文件放行
//对所有用户认证
//authc表示需要认证才可以访问
map.put("/**", "authc");
// 配置 logout 过滤器
map.put("/logout", "logout");
//设置 shiroFilterFactoryBean 的 FilterChainDefinitionMap
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
logger.info("=====shiroFilterFactoryBean注册完成=====");
return shiroFilterFactoryBean;
}
}
MyRealm
import com.yumbo.entity.User;
import com.yumbo.service.UserService;
import org.apache.commons.lang3.StringUtils;
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;
/**
* @Author: GrainFull
* @Date: 2021/4/21 21:50
* @Description:
*/
public class MyRealm extends AuthorizingRealm {
@Autowired(required = false)
private UserService userService;
/**
* 为当前登录成功的用户授予权限和分配角色。
*
* @param principalCollection
* @return AuthorizationInfo 为当前登录成功的用户授予权限和分配角色。
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取用户名
String username = (String) principalCollection.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 给该用户设置角色,角色信息存在 t_role 表中获取
authorizationInfo.setRoles(null);//从数据库中获取
// 给该用户设置权限,权限信息存在 t_permission 表中取
authorizationInfo.setStringPermissions(null);//从数据库中获取
return authorizationInfo;
}
/**
* 用来验证当前登录的用户,获取认证信息。
*
* @param authenticationToken
* @return AuthenticationInfo 用来验证当前登录的用户,获取认证信息。
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
// 根据 Token 获取用户名,如果您不知道该 Token 怎么来的,先可以不管,下文会解释
String username = (String) authenticationToken.getPrincipal();
// 根据用户名从数据库中查询该用户
User user = userService.login(username);
if (StringUtils.isBlank(user.getUsername())) {
throw new UnknownAccountException("该账号不存在!");
}
return new SimpleAuthenticationInfo(username, user.getPassword(), getName());
}
}
application.yml
server:
port: 8080
servlet:
context-path: /yumbo
tomcat:
uri-encoding: UTF-8
max-threads: 1000
min-spare-threads: 30
spring:
## freemarker
freemarker:
suffix: .ftl
content-type: text/html
charset: UTF-8
template-loader-path: classpath:/views/
settings:
classic_compatible: true
## 启用热部署
devtools:
restart:
enabled: true
additional-paths: src/main/java
LoginController
import com.yumbo.utils.BaseController;
import com.yumbo.utils.ResultInfo;
import org.apache.shiro.SecurityUtils;
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.util.DigestUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.util.HtmlUtils;
/**
* @Author: GrainFull
* @Date: 2021/4/21 1:08
* @Description:
*/
@Controller
public class LoginController extends BaseController {
/**
* 登录视图
*
* @return
*/
@RequestMapping(value = "login")
public String login() {
return "login";
}
/**
* 主页视图
*
* @return
*/
@RequestMapping(value = "index")
public String index() {
return "index";
}
/**
* 404视图
*
* @return
*/
@RequestMapping(value = "404")
public String error() {
return "404";
}
/**
* 登录
*
* @param username
* @param password
* @return
*/
@RequestMapping(value = "doLogin", method = RequestMethod.POST)
@ResponseBody
public ResultInfo doLogin(String username, String password) {
Subject subject = SecurityUtils.getSubject();
try {
username = HtmlUtils.htmlEscape(username);
username = username.trim();
UsernamePasswordToken token = new UsernamePasswordToken(username, DigestUtils.md5DigestAsHex(password.getBytes()));
subject.login(token);
return new ResultInfo("成功");
} catch (UnknownAccountException e) {
e.printStackTrace();
}
return new ResultInfo(300, "失败");
}
/**
* 注销登录
*
* @return
*/
@RequestMapping(value = "logout", method = RequestMethod.GET)
public String logout() {
return "login";
}
}
BaseController
import org.springframework.web.bind.annotation.ModelAttribute;
import javax.servlet.http.HttpServletRequest;
/**
* @Author: GrainFull
* @Date: 2021/4/21 1:19
* @Description:
*/
public class BaseController {
@ModelAttribute
public void preHandler(HttpServletRequest request) {
request.setAttribute("ctx", request.getContextPath());
}
}
ResultInfo
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
/**
* @Author: GrainFull
* @Date: 2021/4/21 1:08
* @Description: 响应结果工具类
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Accessors(chain = true)
public class ResultInfo {
private Integer code = 200;
private String msg = "success";
private Object data;
public ResultInfo(String msg) {
this.msg = msg;
}
public ResultInfo(Integer code, String msg) {
this.code = code;
this.msg = msg;
}
public ResultInfo(String msg, Object data) {
this.msg = msg;
this.data = data;
}
}
UserService
import com.yumbo.entity.User;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
/**
* @Author: GrainFull
* @Date: 2021/4/21 1:12
* @Description:
*/
@Service
public class UserService {
/**
* 登录
*
* @param username
* @return
*/
public User login(String username) {
return new User(1, username, DigestUtils.md5DigestAsHex("123456".getBytes()), "admin", "15535795261", "admin@163.com", "男", "上海"); //这里是我用来测试的,实际上应该从数据库中获取
}
}
页面
login.ftl
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>云博-登录</title>
<#include "common.ftl"/>
<link rel="stylesheet" href="${ctx}/plugins/css/login.css" media="all">
<script type="text/javascript" src="${ctx}/plugins/js/login.js" charset="UTF-8"></script>
</head>
<body class="poster">
<form class="form-horizontal login-container" id="loginForm" role="form" action="${ctx}/doLogin" method="post">
<h2 class="login_title">云博-登录</h2>
<div class="form-group">
<label for="username" class="control-label"></label>
<div class="col-sm-12">
<input type="text" class="form-control" name="username" id="username" placeholder="请输入账号">
</div>
</div>
<div class="form-group">
<label for="password" class="control-label"></label>
<div class="col-sm-12">
<input type="password" class="form-control" name="password" id="password" placeholder="请输入密码">
</div>
</div>
<div class="form-group">
<div class="col-sm-12">
<button type="submit" class="btn btn-default col-sm-12 loginSubmit">登录</button>
</div>
</div>
</form>
</body>
</html>
login.js
/**
* @Author: GrainFull
* @Date: 2021/4/20 16:14
* @Description:
*/
charset = "UTF-8"
$(function () {
$("#loginForm").on("submit", function () {
var params = $(this).serializeArray();
var requestUrl = $(this).attr("action");
$.ajax({
// url: ctx + "/doLogin",
url: requestUrl,
type: "post",
data: params,
cache: false,//false是不缓存,true为缓存
async: true, //true为异步,false为同步
beforeSend: function () {
//请求前
console.log("准备登录请求了..")
},
success: function (res) {
console.log("登陆成功");
if (res.code == 200) {
console.log("登陆成功");
window.location.href = ctx + "/index";
}
},
complete: function () {
//请求结束时
console.log("登录请求结束了..")
alert("登录请求结束了..")
},
error: function () {
//请求失败时
console.log("登录失败..")
}
});
});
});
login.css
/**
* @Author: GrainFull
* @Date: 2021/4/20 16:07
* @Description:
*/
.login-container {
border-radius: 15px;
background-clip: padding-box;
margin: 170px auto;
width: 350px;
padding: 35px 35px 35px 35px;
background-color: transparent;
border: 1px solid #eaeaea;
/*阴影设置*/
box-shadow: 0 0 25px #cac6c6;
background-color: #FFFFFF;
}
.login_title {
margin: 0px auto 40px auto;
text-align: center;
color: #505458;
}
.loginSubmit {
width: 100%;
background: #505458;
border: none;
color: #FFFFFF;
}
.poster {
height: 100%;
width: 100%;
/*background: #009688;*/
}
body {
margin: 0;
}
common.ftl
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="icon" href="${ctx}/plugins/images/favicon.ico">
<!-- 引入 Bootstrap -->
<link href="${ctx}/plugins/bootstrap-3.3.7/css/bootstrap.min.css" rel="stylesheet">
<link href="${ctx}/plugins/bootstrap-3.3.7/css/bootstrap-theme.min.css" rel="stylesheet">
<!-- HTML5 Shiv 和 Respond.js 用于让 IE8 支持 HTML5元素和媒体查询 -->
<!-- 注意: 如果通过 file:// 引入 Respond.js 文件,则该文件无法起效果 -->
<!--[if lt IE 9]>
<script src="${ctx}/plugins/libs/html5shiv/3.7.0/html5shiv.js"></script>
<script src="${ctx}/plugins/libs/respond/1.4.2/respond.min.js"></script>
<![endif]-->
<!-- jQuery (Bootstrap 的 JavaScript 插件需要引入 jQuery) -->
<script src="${ctx}/plugins/jquery/jquery.js"></script>
<!-- 包括所有已编译的插件 -->
<script src="${ctx}/plugins/bootstrap-3.3.7/js/bootstrap.min.js"></script>
<script type="text/javascript">
var ctx = "${ctx}";
</script>
index.ftl
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>云博-主页</title>
<#include "common.ftl"/>
</head>
<body>
<h3><i>欢迎使用云博管理系统</i></h3>
</body>
</html>
简单shiro使用,欢迎大家参考借鉴
Security安全框架:https://blog.csdn.net/qq_45742386/article/details/115978867