shiro介绍
shiro是一个权限管理框架,基于用户-角色-权限。一个用户可以有多个角色,一个角色有多个权限,每个权限指定了资源的访问。
shiro的原理是在所有请求之前设置一个filter,这个filter判断哪些资源需要权限,哪些不要,对于不需要权限的直接放行,对于需要权限的,使用securityManager和realm进行身份验证和授权,如果验证失败或者权限不足,都跳转到登录页面或者返回错误信息。这和我们自己使用账号密码判断是一样的,只是这个框架让我们少写很多代码。
spring-boot 集成shiro其实相当简单。
加入依赖
//shiro
compile group: 'org.apache.shiro', name: 'shiro-spring', version: '1.4.0'
ShiroConfig
建立一个配置文件,用来配置shiro
package com.example.shiro;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.text.TextConfigurationRealm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Shiro 配置
*/
@Configuration
public class ShiroConfig {
//创建shiroFilterFactoryBean, 设置securityManager、配置filterChain
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean createShiroFilterFactoryBean() {
ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
bean.setSecurityManager(createSecurityManager());
bean.setLoginUrl("/admin/web/login"); //登录页面
Map<String, String> filterChainMap = new LinkedHashMap<>(); //这里一定要是有序的
//这里可以从数据库中读取权限-资源规则
filterChainMap.put("/api/v1/admin/login", "anon"); //登录不需要验证权限
filterChainMap.put("/api/v1/admin/**", "authc"); //其他api需要权限
filterChainMap.put("/admin/web/login", "anon");//登录页面不需要权限
filterChainMap.put("/admin/web/**", "authc");//其他页面需要权限
bean.setFilterChainDefinitionMap(filterChainMap);
return bean;
}
//创建一个securityManager
@Bean(name = "securityManager")
public SecurityManager createSecurityManager() {
DefaultWebSecurityManager manager = new DefaultWebSecurityManager(new UserRealm());
return manager;
}
}
创建realm
realm 主要用来验证密码和授权
@Component
public class UserRealm extends AuthorizingRealm {
@Autowired
private UserService userService;
@Override
public String getName() {
return "user-realm";
}
@Override
public boolean supports(AuthenticationToken token) {
return true;
}
//获取用户的验证信息,用于和token进行对比
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String userName = (String) token.getPrincipal();
User user = userService.findUserByAccount(userName);
if (user == null) {
return null;
}
return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
}
//给用户设置角色信息
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
User user = (User) principals.getPrimaryPrincipal();
Set<String> roles=new HashSet<>();
roles.add(user.getRole());
return new SimpleAuthorizationInfo(roles);
}
//设置权限信息
@Override
protected Collection<Permission> getPermissions(AuthorizationInfo info) {
return super.getPermissions(info);
}
}
登录
@PostMapping("/login")
@ResponseBody
public DtoWrap login(@RequestBody UserDto userDto) {
DtoWrap result = new DtoWrap();
Subject subject = SecurityUtils.getSubject();
AuthenticationToken token = new UsernamePasswordToken(userDto.getUserName(), userDto.getPassword());
try {
subject.login(token);
//if no exception, that's it, we're done!
} catch (AuthenticationException ae) {
throw new BusinessException("用户名或密码错误");
}
return result;
}