步骤1:创建Spring Boot项目 首先,使用Spring Initializr创建一个新的Spring Boot项目。您可以选择适合您的构建工具(如Maven或Gradle)和Java版本。确保在项目依赖中包含Shiro和JWT相关的库。
步骤2:配置Shiro 在项目中创建一个Shiro配置类,用于配置Shiro的安全策略、Realm和会话管理等。您可以使用注解或编程方式进行配置。以下是一个示例配置类的代码:
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
filterFactoryBean.setSecurityManager(securityManager);
// 设置登录url
filterFactoryBean.setLoginUrl("/login");
// 设置未授权url
filterFactoryBean.setUnauthorizedUrl("/unauthorized");
// 定义过滤器链
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
// 公开访问的资源
filterChainDefinitionMap.put("/public/**", "anon");
// 需要身份认证的资源
filterChainDefinitionMap.put("/private/**", "authc");
filterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return filterFactoryBean;
}
@Bean
public DefaultWebSecurityManager securityManager(Realm realm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm);
return securityManager;
}
@Bean
public Realm realm() {
return new MyRealm();
}
}
步骤3:实现自定义Realm
创建一个自定义的Realm类,用于处理身份认证和授权逻辑。您可以继承AuthorizingRealm类并实现其中的方法。以下是一个示例Realm类的代码:
public class MyRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 实现授权逻辑
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
// 添加角色和权限
authorizationInfo.addRole("admin");
authorizationInfo.addStringPermission("user:read");
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 实现身份认证逻辑
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
String username = usernamePasswordToken.getUsername();
String password = new String(usernamePasswordToken.getPassword());
// 根据用户名查询用户信息
User user = userService.findByUsername(username);
if (user == null || !password.equals(user.getPassword())) {
throw new AuthenticationException("用户名或密码错误");
}
return new SimpleAuthenticationInfo(username, password, getName());
}
}
步骤4:实现登录接口 创建一个登录接口,用于接收用户的用户名和密码,并使用Shiro进行身份认证。如果认证成功,生成JWT并返回给客户端。以下是一个示例登录接口的代码:
@RestController
public class LoginController {
@PostMapping("/login")
public String login(@RequestBody LoginRequest loginRequest) {
Subject currentUser = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(loginRequest.getUsername(), loginRequest.getPassword());
try {
currentUser.login(token);
} catch (AuthenticationException e) {
return "登录失败:" + e.getMessage();
}
// 生成JWT并返回给客户端
String jwt = JwtUtils.generateToken(loginRequest.getUsername());
return "登录成功,JWT:" + jwt;
}
}
步骤5:实现JWT工具类 创建一个JWT工具类,用于生成和验证JWT。您可以使用现有的JWT库(如jjwt)来简化操作。以下是一个示例JWT工具类的代码:
public class JwtUtils {
private static final String SECRET_KEY = "your-secret-key";
private static final long EXPIRATION_TIME = 86400000; // 24小时
public static String generateToken(String username) {
Date now = new Date();
Date expirationDate = new Date(now.getTime() + EXPIRATION_TIME);
return Jwts.builder()
.setSubject(username)
.setIssuedAt(now)
.setExpiration(expirationDate)
.signWith(SignatureAlgorithm.HS512, SECRET_KEY)
.compact();
}
public static boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token);
return true;
} catch (JwtException | IllegalArgumentException e) {
return false;
}
}
public static String getUsernameFromToken(String token) {
Claims claims = Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody();
return claims.getSubject();
}
}
步骤6:实现鉴权过滤器 创建一个鉴权过滤器,用于在每个请求中验证用户的角色和权限。如果用户没有足够的权限,返回相应的错误信息。以下是一个示例鉴权过滤器的代码:
public class AuthorizationFilter extends AuthorizationFilter {
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
Subject subject = getSubject(request, response);
String[] rolesArray = (String[]) mappedValue;
if (rolesArray == null || rolesArray.length == 0) {
return true;
}
for (String role : rolesArray) {
if (subject.hasRole(role)) {
return true;
}
}
return false;
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
httpServletResponse.getWriter().write("无权限访问");
return false;
}
}
步骤7:配置过滤器链 在Shiro配置类中配置过滤器链,以定义URL的访问权限。以下是一个示例过滤器链的配置代码:
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();
filterFactoryBean.setSecurityManager(securityManager);
// 设置登录url
filterFactoryBean.setLoginUrl("/login");
// 设置未授权url
filterFactoryBean.setUnauthorizedUrl("/unauthorized");
// 定义过滤器链
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
// 公开访问的资源
filterChainDefinitionMap.put("/public/**", "anon");
// 需要身份认证的资源
filterChainDefinitionMap.put("/private/**", "authc");
filterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return filterFactoryBean;
}
步骤8:测试与部署 完成开发后,您可以编写单元测试来验证代码是否按预期工作。您可以使用JUnit和Mockito等测试框架来编写测试用例。完成测试后,您可以将应用程序部署到生产环境中。