Apache Shiro 是一个强大且灵活的 Java 安全框架,它提供了身份验证、授权、加密和会话管理等一系列功能,帮助开发者构建安全的应用程序。
以下是 Apache Shiro 的一些主要特点:
身份验证:Shiro 提供了强大的身份验证功能,支持多种认证机制,如用户名/密码、LDAP、OAuth、OpenID 等。它还支持自定义身份验证逻辑,以满足特定应用的需求。
授权:Shiro 提供了基于角色的访问控制(RBAC)和基于资源的访问控制(ABAC)等授权机制。它允许你定义角色、权限和资源的层次结构,并配置它们之间的关系。Shiro 还支持跨多个应用程序的授权策略共享。
加密:Shiro 提供了加密算法和工具,用于保护敏感数据。你可以使用 Shiro 提供的加密工具对数据进行加密和解密,以确保数据的机密性和完整性。
会话管理:Shiro 提供了一个强大会话管理组件,用于跟踪和管理用户的会话。它支持单点登录(SSO)和会话集群等功能,以便在分布式环境中管理用户的会话。
与 Spring Boot 集成:Shiro 提供了与 Spring Boot 的集成支持,使得在 Spring Boot 应用程序中集成 Shiro 变得非常简单。你可以通过添加 Shiro 的 Spring Boot Starter 依赖项,并在配置文件中进行简单的配置来启用 Shiro 的功能。
易扩展和定制:Shiro 提供了灵活的扩展机制,允许你根据自己的需求定制和扩展其功能。你可以实现自定义的 Realm、过滤器、认证器等组件,以满足特定应用的安全需求。
支持多种数据源:Shiro 支持从多种数据源中获取用户信息,如关系数据库、LDAP、JDBC、JPA 等。你可以根据自己的数据存储方式选择适合的数据源,并将用户信息映射到 Shiro 的用户模型上。
详细的日志和审计:Shiro 提供了详细的日志和审计功能,可以帮助你跟踪和记录用户的操作和行为。你可以配置 Shiro 的日志记录器,以便在出现问题时进行调试和排查。
总的来说,Apache Shiro 是一个功能强大且易用的 Java 安全框架,它提供了全面的身份验证、授权、加密和会话管理功能,帮助开发者构建安全的应用程序。通过简单的配置和定制,你可以轻松地将 Shiro 集成到你的项目中,并保护你的应用程序免受各种安全威胁。
Apache Shiro 是一个功能强大且易用的 Java 安全框架,用于身份验证、授权、加密和会话管理。在 Spring Boot 应用程序中集成 Apache Shiro 可以很容易地为你的应用提供安全功能。
以下是如何在 Spring Boot 项目中导入和使用 Apache Shiro 的基本步骤:
添加依赖
在你的 pom.xml(Maven)或 build.gradle(Gradle)文件中添加 Shiro 的依赖。如果你使用 Maven,添加如下依赖:
xml
org.apache.shiro
shiro-spring-boot-web-starter
YOUR_DESIRED_VERSION
注意替换 YOUR_DESIRED_VERSION 为你想要的 Shiro Spring Boot Starter 的版本。
配置 Shiro
在 Spring Boot 中,你可以通过配置文件(如 application.yml 或 application.properties)或 Java 配置类来配置 Shiro。例如,你可以配置 Realm、安全管理器(SecurityManager)等。
如果你使用 Java 配置,可以创建一个配置类,并使用 @Configuration 和相关的 Shiro 注解来定义你的配置。
创建 Realm
Realm 是 Shiro 与你的应用安全数据之间的桥梁。你需要实现一个或多个 Realm 来处理身份验证和授权。Realm 可能会访问数据库、LDAP 或其他数据源来获取用户的安全数据。
配置安全管理器
安全管理器(SecurityManager)是 Shiro 的核心组件,它负责协调 Shiro 的所有安全操作。你需要在配置中定义安全管理器,并指定要使用的 Realm。
使用 Shiro 的 API
在你的应用代码中,你可以使用 Shiro 的 API 来进行身份验证、授权等。例如,你可以使用 Subject 类来获取当前用户,并使用其方法来检查用户的角色和权限。
6. 整合 Spring Security(可选)
虽然 Shiro 和 Spring Security 是两个独立的安全框架,但 Shiro 提供了一个与 Spring Security 兼容的模块,允许你在 Shiro 中使用 Spring Security 的某些功能。然而,这通常不是必需的,因为 Shiro 本身已经提供了丰富的安全功能。
7. 测试
确保你的安全配置按预期工作。你可以编写集成测试和/或单元测试来验证你的 Shiro 配置和代码。
8. 部署和监控
将你的应用部署到生产环境,并使用日志和监控工具来跟踪和解决任何安全问题。
请注意,这些步骤是一个概述,并可能需要根据你的具体需求进行调整。你可以查阅 Apache Shiro 的官方文档和示例代码以获取更详细的信息和最佳实践。
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。
package com.programb.jwt;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
package com.programb.jwt.api;
import org.apache.shiro.ShiroException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import com.programb.jwt.api.model.BaseResponse;
import javax.servlet.http.HttpServletRequest;
@RestControllerAdvice
public class ExceptionController {
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler(ShiroException.class)
public BaseResponse handle401(ShiroException e) {
return new BaseResponse<>(false, "异常", null);
}
@ResponseStatus(HttpStatus.UNAUTHORIZED)
@ExceptionHandler(UnauthorizedException.class)
public BaseResponse handle401() {
return new BaseResponse<>(false, "UnauthorizedException", null);
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public BaseResponse globalException(HttpServletRequest request, Throwable ex) {
return new BaseResponse<>(false, "异常", null);
}
private HttpStatus getStatus(HttpServletRequest request) {
Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
if (statusCode == null) {
return HttpStatus.INTERNAL_SERVER_ERROR;
}
return HttpStatus.valueOf(statusCode);
}
}
package com.programb.jwt.api;
import org.apache.shiro.authz.UnauthorizedException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import com.programb.jwt.api.model.BaseResponse;
import com.programb.jwt.api.model.LoginParam;
import com.programb.jwt.common.util.JWTUtil;
import com.programb.jwt.model.ManagerInfo;
import com.programb.jwt.service.ManagerInfoService;
import com.programb.jwt.shiro.ShiroKit;
import javax.annotation.Resource;
@RestController
public class LoginController {
@Resource
private ManagerInfoService managerInfoService;
private static final Logger _logger = LoggerFactory.getLogger(LoginController.class);
@PostMapping("/login")
public BaseResponse<String> login(@RequestHeader(name="Content-Type", defaultValue = "application/json") String contentType,
@RequestBody LoginParam loginParam) {
_logger.info("用户请求登录获取Token");
String username = loginParam.getUsername();
String password = loginParam.getPassword();
ManagerInfo user = managerInfoService.findByUsername(username);
String salt = user.getSalt();
String encodedPassword = ShiroKit.md5(password, username + salt);
if (user.getPassword().equals(encodedPassword)) {
return new BaseResponse<>(true, "Login success", JWTUtil.sign(username, encodedPassword));
} else {
throw new UnauthorizedException();
}
}
}
package com.programb.jwt.api;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*;
import com.programb.jwt.api.model.BaseResponse;
@RestController
@RequestMapping(value = "/api/v1")
public class PublicController {
private static final Logger _logger = LoggerFactory.getLogger(PublicController.class);
@RequestMapping(value = "/join", method = RequestMethod.GET)
@RequiresAuthentication
public BaseResponse join(@RequestParam("programb") String imei) {
_logger.info("programb start... programb=" + imei);
BaseResponse result = new BaseResponse();
result.setSuccess(true);
result.setMsg("programb");
return result;
}
}
package com.programb.jwt.api.model;
public class BaseResponse<T> {
boolean success;
private String msg;
private T data;
public BaseResponse() {
}
public BaseResponse(boolean success, String msg, T data) {
this.success = success;
this.msg = msg;
this.data = data;
}
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
package com.programb.jwt.api.model;
public class LoginParam {
private String username;
private String password;
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;
}
}
package com.programb.jwt.common.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
public class JWTUtil {
private static final Logger log = LoggerFactory.getLogger(JWTUtil.class);
// 过期时间5分钟
private static final long EXPIRE_TIME = 5 * 60 * 1000;
public static String sign(String username, String secret) {
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
Algorithm algorithm = Algorithm.HMAC256(secret);
// 附带username信息
return JWT.create()
.withClaim("username", username)
.withExpiresAt(date)
.