返回
技术指南:用SpringBoot整合Shiro(后端)
后端
2023-09-14 08:21:25
SpringBoot整合Shiro(后端)技术指南
本指南将指导您将SpringBoot与Shiro集成,并在前后端分离模式下实现JWT认证。通过重写Shiro的过滤器,您可以自定义错误返回,避免重定向到登录页面,从而实现前后端分离的无缝衔接。
为什么要集成SpringBoot和Shiro?
SpringBoot是一个流行的Java框架,它简化了Spring应用的配置和开发。Shiro是一个功能强大的安全框架,它提供了灵活的认证和授权机制。将SpringBoot与Shiro集成,可以为您的应用提供强大的安全保障,并简化安全配置和管理。
集成步骤
- 添加SpringBoot和Shiro依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-starter</artifactId>
<version>1.4.0</version>
</dependency>
</dependencies>
- 配置Shiro
在application.yml
文件中配置Shiro:
shiro:
web:
enabled: true
jwt:
secret: my-secret-key
- 创建自定义Realm
自定义Realm用于验证用户身份和授权。创建一个实现org.apache.shiro.realm.Realm
接口的类,并重写doGetAuthenticationInfo
和doGetAuthorizationInfo
方法。
public class MyRealm implements Realm {
@Override
public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
// 从token中获取用户名和密码
String username = (String) token.getPrincipal();
String password = new String((char[]) token.getCredentials());
// 根据用户名从数据库中查询用户
User user = userService.findByUsername(username);
// 如果用户存在并密码正确,则返回AuthenticationInfo
if (user != null && user.getPassword().equals(password)) {
return new SimpleAuthenticationInfo(username, password, getName());
}
// 如果用户不存在或密码不正确,则抛出异常
throw new UnknownAccountException("用户不存在或密码不正确");
}
@Override
public AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 从principals中获取用户名
String username = (String) principals.getPrimaryPrincipal();
// 根据用户名从数据库中查询用户的角色和权限
Set<String> roles = userService.findRolesByUsername(username);
Set<String> permissions = userService.findPermissionsByUsername(username);
// 返回AuthorizationInfo
return new SimpleAuthorizationInfo(roles, permissions);
}
}
- 配置自定义Realm
在ShiroConfig
类中配置自定义Realm:
@Configuration
public class ShiroConfig {
@Bean
public Realm realm() {
return new MyRealm();
}
}
- 重写Shiro的过滤器
为了实现前后端分离,我们需要重写Shiro的过滤器,以便在用户未认证时返回JSON格式的错误信息,而不是重定向到登录页面。
public class JwtFilter extends PathMatchingFilter {
@Override
protected boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
// 从请求头中获取JWT token
String token = request.getHeader("Authorization");
// 如果token为空,则返回JSON格式的错误信息
if (token == null) {
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(new ObjectMapper().writeValueAsString(new ResponseResult(401, "Unauthorized")));
return false;
}
// 如果token不为空,则解析JWT token
try {
Jwts.parser().setSigningKey(ShiroConfig.SECRET_KEY).parseClaimsJws(token);
} catch (Exception e) {
// 如果解析JWT token失败,则返回JSON格式的错误信息
response.setContentType("application/json;charset=UTF-8");
response.getWriter().write(new ObjectMapper().writeValueAsString(new ResponseResult(401, "Unauthorized")));
return false;
}
// 如果解析JWT token成功,则继续执行请求
return true;
}
}
- 注册JwtFilter
在ShiroConfig
类中注册JwtFilter:
@Configuration
public class ShiroConfig {
@Bean
public Realm realm() {
return new MyRealm();
}
@Bean
public JwtFilter jwtFilter() {
return new JwtFilter();
}
@Bean
public DefaultFilterInvocationDefinitionMap filterInvocationDefinitionMap() {
DefaultFilterInvocationDefinitionMap definitionMap = new DefaultFilterInvocationDefinitionMap();
definitionMap.put("/**", "jwtFilter");
return definitionMap;
}
}
总结
通过以上步骤,您就可以将SpringBoot与Shiro集成,并在前后端分离模式下实现JWT认证。通过重写Shiro的过滤器,您可以自定义错误返回,避免重定向到登录页面,从而实现前后端分离的无缝衔接。