文章目录
参考文章(先看这个): https://blog.youkuaiyun.com/qq_35642036/article/details/82788588
官方文章(强烈看这个-写的非常全): https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Authentication#%E5%9F%BA%E6%9C%AC%E9%AA%8C%E8%AF%81%E6%96%B9%E6%A1%88
Base64编码: 只是一种字符编码转换而已,并非密文,依然可以解码解出明文内容是什么
特点: 简单,无需复杂的认证操作,仅仅只是在请求中添加用户账号、密码信息。前提是客户机、服务器是非常安全,没有人进行拦截截取用户认证信息
典型案例: Nexus的jar包上传接口,可查看此文章的脚本代码 【https://blog.youkuaiyun.com/weixin_39651356/article/details/126007459】
//每次请求时请求头都携带认证信息:即用户账号、密码
//格式:Authorization: 认证方式 用户:密码的base64编码
Authorization: Basic【用户账号:用户密码】的Base64编码
//如果认证失败:响应头中则会有一个类似这个信息
//WWW-Authenticate: 认证方式 realm="需要的认证资源角色描述或者仅仅只是资源描述"
WWW-Authenticate: Basic realm="Sonatype Nexus Repository Manager"
讲解(Base认证)
请求添加认证方式
方式1-API工具自动帮你添加认证请求头,你只要事先填好账户密码即可
方式2-自己添加请求头信息
public class OtherTest {
@Test
public void test2() {
String formatInfo = StrUtil.format("{}:{}", "admin", "admin123");
Console.log(formatInfo);
String encodeContent = Base64.encode(formatInfo);
Console.log(encodeContent);
String requestHeaderInfo = StrUtil.format("Authorization: Basic {}", encodeContent);
Console.log(requestHeaderInfo);
}
}
方式3-curl
# 格式1,下面两句效果是一样的,只要添加 -u 默认就是basic认证
curl --basic -u '账号:密码' url地址
curl -u '账号:密码' url地址
# 格式2:注意 -n必须加因为不加-n,echo就会在字符串末尾加上换行符多了个字符
curl -H ''Authorization:$(echo -n '账号:密码' | base64)" url地址
认证结果
认证成功-响应请求头
认证失败-响应请求头
实现(Base认证)
代码(Base认证)
application.yml
server:
port: 8080
# mybatisplus\u8BBE\u7F6E
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
cache-enabled: true
mapper-locations: classpath:mapper/*Mapper.xml
global-config:
db-config:
id-type: assign_uuid
logic-delete-value: 1
logic-not-delete-value: 0
logic-delete-field: is_del
where-strategy: not_empty #\u4E0Dwhere\u975Eempty\u7684\u5B57\u6BB5\u3010\u7A7A\u5B57\u7B26\u3001null\u503C\u3011
update-strategy: not_empty
insertStrategy: not_empty
spring:
datasource:
driver-class-name: com.p6spy.engine.spy.P6SpyDriver
username: root
password: root
url: jdbc:p6spy:mysql://localhost:3306/lrc_blog?useSSL=false&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
freemarker:
suffix: .html
BasicAuthInterceptor.java
package work.linruchang.qq.mybaitsplusjoin.config.interceptor;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
* 作用:Basic认证
*
* @author LinRuChang
* @version 1.0
* @date 2022/08/04
* @since 1.8
**/
@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class BasicAuthInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
boolean authStatusFlag = false;
String authorization = request.getHeader("Authorization");
String authType = null;
String authInfoCredentials = null;
String userName = null;
List<String> authorizationInfos = StrUtil.splitTrim(authorization, StrUtil.SPACE);
if(CollUtil.size(authorizationInfos) == 2) {
authType = authorizationInfos.get(0);
authInfoCredentials = authorizationInfos.get(1);
if (StrUtil.isNotBlank(authInfoCredentials)) {
if (StrUtil.equalsAnyIgnoreCase(authType, "BASIC")) {
String authInfo = Base64.decodeStr(authInfoCredentials);
userName = StrUtil.splitTrim(authInfo, StrUtil.COLON).get(0);
String password = StrUtil.splitTrim(authInfo, StrUtil.COLON).get(1);
//这里自行获取数据库中的用户、密码信息进行校验是否正确
Dict dbUserInfo = getUserInfo(userName);
if(dbUserInfo != null && StrUtil.equals(password,dbUserInfo.getStr("password"))) {
authStatusFlag = true;
}
}
}
}
//认证失败
if (!authStatusFlag) {
response.setHeader("WWW-Authenticate",StrUtil.format("{} realm=\"rights of administrators\"", StrUtil.blankToDefault(authType,"BASIC")));
response.setStatus(401);
return false;
}
//添加cookie信息给用户 == 当前用户名
if(!StrUtil.containsIgnoreCase(request.getRequestURI(),"logout")) {
Cookie userNameCookie = new Cookie("userName", userName);
userNameCookie.setPath("/");
response.addCookie(userNameCookie);
Cookie userNameDescCookie = new Cookie("userNameDesc", "管理员");
userNameDescCookie.setPath("/");
response.addCookie(userNameDescCookie);
}
return authStatusFlag;
}
public Dict getUserInfo(String userName) {
if(StrUtil.equals(userName,"admin")) {
return Dict.create()
.set("userName","admin")
.set("password", "admin123");
}
return null;
}
}
MyConfig.java
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Autowired
BasicAuthInterceptor basicAuthInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(basicAuthInterceptor)
.addPathPatterns("/**")
.excludePathPatterns("/js/**");
}
}
ArticleCategoryController.java
@RestController
@RequestMapping("article-category")
public class ArticleCategoryController {
@Autowired
ArticleCategoryService articleCategoryService;
/**
* 根据ID进行查询
* @param id
* @return
*/
@GetMapping("/one/{id}")
public CommonHttpResult<ArticleCategory> findById(@PathVariable("id") String id) {
return CommonHttpResult.success(articleCategoryService.getById(id));
}
}
UserController0.java
@Controller
@RequestMapping("user0")
public class UserController0 {
/**
* 用户页面
*
* @return
*/
@GetMapping
public String userPage() {
return "user";
}
/**
* 退出登录
* 命令浏览器清除当前站点的所有缓存以及cookie信息
* @param httpServletResponse
*/
@GetMapping("logout")
@SneakyThrows
public void logout(HttpServletResponse httpServletResponse) {
httpServletResponse.setStatus(401);
httpServletResponse.setHeader("Clear-Site-Data", "\"cache\", \"cookies\"");
}
}
user.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="/js/jquery.min.js"></script>
</head>
<body>
<button id="logout">退出登录</button>
<p>
用户名:<span id="userName"></span>
</p>
<p>
用户描述:<span id="userNameDesc"></span>
</p>
</body>
<script>
$(function () {
$("#userName").text(getCookie("userName"))
$("#userNameDesc").text(getCookie("userNameDesc"))
//退出登录
$("#logout").click(function () {
jQuery.get({
url: "/user0/logout",
error: function() {
window.location.reload();
}
});
})
function getCookie(cookie_name) {
var allcookies = document.cookie;
//索引长度,开始索引的位置
var cookie_pos = allcookies.indexOf(cookie_name);
// 如果找到了索引,就代表cookie存在,否则不存在
if (cookie_pos != -1) {
// 把cookie_pos放在值的开始,只要给值加1即可
//计算取cookie值得开始索引,加的1为“=”
cookie_pos = cookie_pos + cookie_name.length + 1;
//计算取cookie值得结束索引
var cookie_end = allcookies.indexOf(";", cookie_pos);
if (cookie_end == -1) {
cookie_end = allcookies.length;
}
//得到想要的cookie的值
var value = unescape(allcookies.substring(cookie_pos, cookie_end));
}
return value;
}
})
</script>
</html>
演示(Base认证)
普通API接口
服务器质询浏览器需要权限才能访问此链接
客户端填写错误的用户名、密码
客户端填写正确的用户名、密码 == 链接数据访问成功