Apache Shiro is a powerful and flexible Java security framework focused on providing authentication, authorization, session management and encryption. It is often used to protect the access control of Java applications, especially in Web applications. Compared to Spring Security, Shiro's design is more concise, suitable for lightweight applications, and in many ways has a better ease of use and scalability, today V to talk about Shiro security framework.
Core Concepts of Shiro
As usual, let's take a look at the core concepts of Shiro with V:
-
Subject
Subject is a core interface in the Shiro framework that represents a "user" or "entity" in an application and is used to interact and store authentication state. It is usually accessed through the()
Gets the current Subject, which represents the user's identity and permission data. -
SecurityManager
SecurityManager is the core controller of Shiro and is responsible for managing all security operations and authentication. By configuring the SecurityManager, you can control the management of user authentication, authorization, sessions, and so on. -
Realm
The Realm is the means by which Shiro obtains user, role, and permission information from data sources. By implementing a custom Realm, you can integrate Shiro with data sources such as databases, LDAP, files, etc. Shiro will fetch user authentication and authorization data from the Realm. -
Session
Shiro comes with session management and does not depend on the session provided by the Servlet container. Shiro's session management can be used even in non-web environments. shiro's session management provides more granular controls such as session timeout, storage and sharing. -
Authentication
Authentication is the process of verifying a user's identity. shiro provides simple APIs to implement the authentication process, such as(token)
In practice, authentication is usually done through a combination of username and password. In practice, authentication is usually done through a combination of username and password, but Shiro also supports other methods (e.g. OAuth2, JWT, etc.). -
Authorization
Authorization is the process of verifying that a user has certain permissions or roles. shiro supports both role-based and permission-based authorization, allowing for finer-grained control of permissions. Authorization is accomplished through themaybe
method, developers can check the roles and permissions of users.
-
Cryptography
Shiro has built-in encryption features that provide support for encrypting and decrypting passwords and sensitive information. It supports a wide range of encryption algorithms and supports hashing and salting when storing passwords.
Key features and benefits of Shiro
V summarizes some of the main features and advantages of Shiro, which is used for bragging rights in interviews.
-
Easy to integrate
Shiro's API is designed to be simple and easy to integrate into a variety of Java applications. Developers can quickly build a basic security architecture based on the default implementation provided by Shiro, or customize various features as needed. -
Independent session management
Unlike Web container-based session management, Shiro provides cross-environment session management that can be applied to both Web and non-Web environments, increasing application flexibility. -
Permission control is simple and flexible
Shiro's permission management can be implemented through configuration files, annotations, or code, providing fine-grained access control. Through a combination of permissions and roles, developers can control access rights very flexibly. -
Supports multiple data sources
Shiro can obtain user and permission information from a variety of data sources (e.g., databases, LDAP, files, etc.), facilitating integration with a variety of existing systems. -
Support for Web and non-Web environments
Shiro can be used not only in web applications, but also in environments such as desktop applications or microservices.
Basic Shiro Usage Examples
It's not VG style to just talk about concepts, so let's walk through a typical Shiro application to see how to use it, including steps to configure SecurityManager, configure Realm, and perform authentication and authorization.
-
Configuring the Shiro Environment
This can be done byfile to configure Shiro, or you can configure it through code.
[main]
# configure SecurityManager
securityManager =
# configure Realm
myRealm =
= $myRealm
-
Creating a Custom Realm
Customizing Realm by Inheritance
AuthorizingRealm
realizationdoGetAuthenticationInfo
cap (a poem)doGetAuthorizationInfo
method to provide user and permission data.
public class MyCustomRealm extends AuthorizingRealm {
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// Getting information such as username and password,Querying the database for authentication
return new SimpleAuthenticationInfo(username, password, getName());
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// Getting information about user roles and permissions
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
("admin");
("user:read");
return info;
}
}
- Authentication and Authorization with Shiro
Subject currentUser = (); if (!
currentUser = (); if (! ()) {
UsernamePasswordToken token = new UsernamePasswordToken("username", "password"); try {
try {
(token); ("Authentication successful.
("Authentication Successful"); } catch (AuthenticationException a); ("Authentication Successful"); ("Authentication Successful")
} catch (AuthenticationException ae) {
("Authentication failed"); } catch (AuthenticationException ae) { ("Authentication failed"); }
}
}
// Checking permissions
if (("admin")) {
// Simulate this with the output haha
("The user has the admin role");
}
if (("user:read")) {
// Simulate this with the output
("The user has the user:read permission"); }
}
Through this simple case study, we can understand the basic use of Shiro, but that's not all, listen to V continue slowly.
Scenario Case
This is important to emphasize haha.Shiro is suitable for Java applications that require simplicity and ease of use, and flexibility in security control requirements, such as small and medium-sized Web applications, desktop applications, distributed microservices, etc. For large enterprise applications or projects that need to integrate multiple authentication methods (e.g. OAuth2, JWT, etc.), Spring Security may be more appropriate.
To implement Apache Shiro-based secure authentication and authorization in a microservices architecture, such as an order management system for example. This system contains two main services:
- customer service: Responsible for user registration, login, authentication and other operations.
- Order Service: Allow users to create, view, and delete orders and restrict access.
Let's see, how should this be designed?
Microservices Case Design
In this scenario, we need the following core functions:
- user authentication: The user logs in with a username and password.
- privilege control: Only administrators can delete orders, regular users can only view and create orders.
- Token Mechanism: Uses JWT Token (JSON Web Token) to manage the user's login state, realizing stateless authentication and making it independent of a single session in a distributed environment.
- Cross-service authentication: The Order Service checks and verifies the user's identity and permissions when it receives a request.
Architecture and technology selection
- Spring Boot: For rapid building of microservices.
- Shiro: Achieve authentication, authorization.
- JWT: Generate and validate Token to maintain stateless authentication.
- Spring Data JPA: Access to a database to store user and order data.
system structure
+------------------+ +---------------------+
| User Services | | Order Services | | Order Services
| | | | | | | |
| | User Registration, Login | | View, Create, Delete Orders | | | Order Service
+------------------+ +---------------------+
|---- User Token ------|
Step: Implementing Authentication and Authorization in Microservices
1. Introduction of necessary dependencies
exist file, add dependencies such as Shiro, JWT, and Spring Data JPA:
<dependency>
<groupId></groupId>
<artifactId>shiro-spring</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId></groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId></groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId></groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
2. Configuring Shiro and JWT Filters
Use Shiro's custom JWT filters to implement stateless authentication, authenticating users with a Token.
public class JwtFilter extends BasicHttpAuthenticationFilter {
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String token = ("Authorization");
if ((token)) {
return false;
}
try {
// analyze JWT token
JwtToken jwtToken = new JwtToken(token);
getSubject(request, response).login(jwtToken);
return true;
} catch (Exception e) {
return false;
}
}
}
3. Implementation of customized Realm
customizableRealm
The JWT Token is used to obtain user and role information from the database and to perform stateless authentication using the JWT Token.
public class JwtRealm extends AuthorizingRealm {
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof JwtToken;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String jwtToken = (String) ();
// validate (a theory) Token
String username = (jwtToken);
if (username == null) {
throw new AuthenticationException("Token null");
}
// user search
User user = (username);
if (user == null) {
throw new AuthenticationException("The user does not exist");
}
return new SimpleAuthenticationInfo(jwtToken, jwtToken, getName());
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (());
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
User user = (username);
// Adding roles and permissions
(());
(());
return authorizationInfo;
}
}
4. Create the JWT tool class
Write a tool class for generating and parsing JWT Token.
public class JwtUtil {
//Replace your own heresecret_key
private static final String SECRET_KEY = "It's coded here.";
public static String generateToken(String username) {
return ()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(new Date(() + 3600000)) // 1 hour
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
public static String getUsernameFromToken(String token) {
Claims claims = ()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
return ();
}
public static boolean isTokenExpired(String token) {
Claims claims = ()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
return ().before(new Date());
}
}
5. Write user service and order service interfaces
User Service Interface
The user service provides registration and login APIs.
@RestController
@RequestMapping("/user")
public class UserController {
@PostMapping("/register")
public ResponseEntity<?> register(@RequestBody User user) {
(user);
return ("User Registration Successful");
}
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody User user) {
User dbUser = (());
if (dbUser != null && ().equals(())) {
String token = (());
return (token);
}
return ().body("Login Failure");
}
}
Order Service Interface
The Order Service validates user roles and permissions when operating an order.
@RestController
@RequestMapping("/order")
public class OrderController {
@GetMapping("/{orderId}")
public ResponseEntity<?> getOrder(@PathVariable Long orderId) {
Subject currentUser = ();
if (("order:read")) {
// Check Orders
return ("Order Details");
}
return ().body("No permission to view orders");
}
@DeleteMapping("/{orderId}")
public ResponseEntity<?> deleteOrder(@PathVariable Long orderId) {
Subject currentUser = ();
if (("admin")) {
// Delete Order
return ("Order Deleted");
}
return ().body("无权限Delete Order");
}
}
ultimate
In this case we go through how to use Shiro, JWT and Spring Boot to build a stateless microservice authentication and authorization mechanism. We use Shiro for user authentication and privilege control and JWT for stateless token validation. In the lightweight distributed microservice applications, is not the use of Shiro feel more refreshing it, welcome to discuss the comments section, pay attention to Wei brother love programming, love Java, life.