在現代Web開發中,快速搭建一個高效、安全的后端服務是每個開發者的追求。Spring Boot作為Java生態中最流行的框架之一,以其簡潔的配置和強大的功能贏得了廣泛的青睞。結合JWT(JSON Web Token)、Shiro(Apache Shiro)和MybatisPlus,我們可以快速構建一個功能完善的后端腳手架。本文將詳細介紹如何使用這些技術棧實現一個Restful風格的后端服務。
首先,我們需要創建一個Spring Boot項目??梢允褂肧pring Initializr來快速生成項目骨架。選擇以下依賴:
生成項目后,導入到IDE中,確保項目結構如下:
src
├── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ └── demo
│ │ ├── config
│ │ ├── controller
│ │ ├── entity
│ │ ├── mapper
│ │ ├── service
│ │ └── DemoApplication.java
│ └── resources
│ ├── application.yml
│ └── mapper
└── test
└── java
└── com
└── example
└── demo
MybatisPlus是Mybatis的增強工具,提供了許多便捷的功能。首先,我們需要在application.yml
中配置數據庫連接和MybatisPlus的相關設置:
spring:
datasource:
url: jdbc:mysql://localhost:3306/demo?useSSL=false&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.example.demo.entity
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
接下來,創建一個實體類User
:
@Data
@TableName("user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private String password;
private String role;
}
然后,創建Mapper接口UserMapper
:
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
Shiro是一個強大的安全框架,而JWT是一種輕量級的身份驗證機制。我們將結合兩者來實現用戶認證和授權。
首先,添加Shiro和JWT的依賴:
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
接下來,創建一個JWT工具類JwtUtil
:
public class JwtUtil {
private static final String SECRET_KEY = "your-secret-key";
public static String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setExpiration(new Date(System.currentTimeMillis() + 86400000)) // 1天
.signWith(SignatureAlgorithm.HS512, SECRET_KEY)
.compact();
}
public static String getUsernameFromToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
}
然后,配置Shiro的Realm
和Filter
:
public class JwtRealm extends AuthorizingRealm {
@Autowired
private UserMapper userMapper;
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof JwtToken;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String) principals.getPrimaryPrincipal();
User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRole(user.getRole());
return info;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String jwtToken = (String) token.getPrincipal();
String username = JwtUtil.getUsernameFromToken(jwtToken);
if (username == null) {
throw new AuthenticationException("Invalid token");
}
User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
if (user == null) {
throw new AuthenticationException("User not found");
}
return new SimpleAuthenticationInfo(username, jwtToken, getName());
}
}
public class JwtFilter extends AuthenticatingFilter {
@Override
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String token = httpRequest.getHeader("Authorization");
if (token == null || !token.startsWith("Bearer ")) {
return null;
}
return new JwtToken(token.substring(7));
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
AuthenticationToken token = createToken(request, response);
if (token == null) {
return true;
}
try {
getSubject(request, response).login(token);
return true;
} catch (Exception e) {
return false;
}
}
}
最后,配置Shiro的SecurityManager
和Filter
:
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(securityManager);
Map<String, Filter> filters = new HashMap<>();
filters.put("jwt", new JwtFilter());
factoryBean.setFilters(filters);
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/**", "jwt");
factoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return factoryBean;
}
@Bean
public SecurityManager securityManager(JwtRealm jwtRealm) {
DefaultSecurityManager securityManager = new DefaultSecurityManager();
securityManager.setRealm(jwtRealm);
return securityManager;
}
@Bean
public JwtRealm jwtRealm() {
return new JwtRealm();
}
}
現在,我們可以實現一些Restful API來測試我們的腳手架。首先,創建一個UserController
:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserMapper userMapper;
@PostMapping("/login")
public String login(@RequestParam String username, @RequestParam String password) {
User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
if (user != null && user.getPassword().equals(password)) {
return JwtUtil.generateToken(username);
}
throw new RuntimeException("Invalid username or password");
}
@GetMapping("/info")
public User info(@RequestHeader("Authorization") String token) {
String username = JwtUtil.getUsernameFromToken(token.substring(7));
return userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
}
}
啟動項目后,可以使用Postman或其他工具測試API。首先,調用/user/login
接口獲取JWT令牌,然后在請求其他接口時在Header中添加Authorization: Bearer <token>
。
通過Spring Boot、JWT、Shiro和MybatisPlus的結合,我們快速搭建了一個功能完善的后端腳手架。這個腳手架不僅支持用戶認證和授權,還提供了Restful風格的API接口。希望本文能幫助你快速上手這些技術,并在實際項目中應用它們。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。