springboot shiro前后端分离 多用户
时间: 2023-07-23 13:03:31 浏览: 122
Spring Boot和Shiro与前后端分离的结合可以使用RESTful API来实现。多用户可以通过Shiro的Realm来实现用户的认证和授权。下面是一个简单的示例:
1. 配置Shiro
在Spring Boot中,可以使用Shiro的Java Config方式配置Shiro。
```java
@Configuration
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
Map<String, Filter> filters = new LinkedHashMap<>();
filters.put("jwt", new JwtFilter());
shiroFilterFactoryBean.setFilters(filters);
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/api/login", "anon");
filterChainDefinitionMap.put("/api/logout", "logout");
filterChainDefinitionMap.put("/**", "jwt");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public SecurityManager securityManager(Realm realm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm);
return securityManager;
}
@Bean
public Realm realm() {
return new MyRealm();
}
}
```
在上面的代码中,我们配置了Shiro的过滤器,并且设置了登录URL和未授权URL。我们还配置了一个JwtFilter来验证JWT Token。最后,我们将所有URL都设置为需要通过JwtFilter才能访问。
2. 自定义Realm
```java
public class MyRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String username = (String) principals.getPrimaryPrincipal();
User user = userService.findByUsername(username);
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
authorizationInfo.setRoles(user.getRoles());
authorizationInfo.setStringPermissions(user.getPermissions());
return authorizationInfo;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();
User user = userService.findByUsername(username);
if (user == null) {
throw new UnknownAccountException();
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());
return authenticationInfo;
}
}
```
在上面的代码中,我们自定义了一个Realm,用于用户的认证和授权。在认证时,我们根据用户名查询数据库,如果查询到了对应的用户,则返回一个SimpleAuthenticationInfo对象;否则抛出UnknownAccountException异常。在授权时,我们根据用户名查询数据库,然后将用户的角色和权限设置到SimpleAuthorizationInfo对象中。
3. 编写JWT Filter
```java
public class JwtFilter extends AuthenticatingFilter {
@Autowired
private UserService userService;
@Autowired
private JwtUtils jwtUtils;
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String token = httpServletRequest.getHeader("Authorization");
if (StringUtils.isEmpty(token)) {
throw new UnauthorizedException();
}
try {
Claims claims = jwtUtils.getClaimsFromToken(token);
String username = claims.getSubject();
User user = userService.findByUsername(username);
if (user == null) {
throw new UnauthorizedException();
}
JwtToken jwtToken = new JwtToken(token);
getSubject(request, response).login(jwtToken);
return true;
} catch (Exception e) {
throw new UnauthorizedException();
}
}
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
return false;
}
}
```
在上面的代码中,我们编写了一个JwtFilter,用于验证JWT Token。在过滤器中,我们从Header中获取Token,并解析出其中的用户名。然后根据用户名查询数据库,如果查询到了对应的用户,则创建一个JwtToken对象,调用Subject的login方法进行登录。
4. 编写Controller
```java
@RestController
@RequestMapping("/api")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("/login")
public Result login(@RequestBody User user) {
User dbUser = userService.findByUsername(user.getUsername());
if (dbUser == null || !dbUser.getPassword().equals(user.getPassword())) {
return Result.fail("用户名或密码错误");
}
String token = JwtUtils.generateToken(dbUser.getUsername());
return Result.success(token);
}
@GetMapping("/user")
public Result getUser() {
String username = (String) SecurityUtils.getSubject().getPrincipal();
User user = userService.findByUsername(username);
return Result.success(user);
}
@RequiresPermissions("user:add")
@PostMapping("/user")
public Result addUser(@RequestBody User user) {
userService.addUser(user);
return Result.success();
}
}
```
在上面的代码中,我们编写了一个UserController,用于处理用户相关的请求。在登录接口中,我们根据用户名和密码查询数据库,如果查询到了对应的用户,则使用JwtUtils生成一个Token并返回。在getUser接口中,我们获取当前登录的用户名,然后根据用户名查询数据库并返回用户信息。在addUser接口中,我们使用@RequiresPermissions注解来限制只有拥有user:add权限的用户才能访问该接口。
5. 测试
使用Postman等工具来测试接口,可以通过登录接口获取Token,并在后续请求中将Token加入到Header中进行访问。
以上就是Spring Boot和Shiro与前后端分离结合实现多用户认证和授权的示例。
阅读全文