对比了shiro和spring security之后选择使用shiro作为权限验证的框架
1.在pom中添加
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.4.0</version>
</dependency>
开始时没注意写成了shiro-spring-boot-starter
在运行的时候会报
No SecurityManager accessible to the calling code
2.创建shiro的配置文件
因为之前定接口的时候没有对用户类型进行划分,所以使用注解的方式配置controller
/*
* shiro配置
* */
@Configuration
public class ShiroConfig {
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor =
new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor;
}
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator app = new DefaultAdvisorAutoProxyCreator();
app.setProxyTargetClass(true);
return app;
}
@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(realm());
return securityManager;
}
//注入自定义的realm
@Bean
public Realm realm() {
return new CustomRealm();
}
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
DefaultShiroFilterChainDefinition chain = new DefaultShiroFilterChainDefinition();
//验证由注解完成,这里全部放行
chain.addPathDefinition("/**", "anon");
return chain;
}
}
3.其中的CustomRealm是需要自己实现的用户和权限获取方法
/*
* 用于shiro的权限认证实现
* */
public class CustomRealm extends AuthorizingRealm {
@Autowired
private IUsersService usersService;
/**
* 获取身份验证信息
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
// 获取用户输入的用户名和密码
String phone = (String) token.getPrincipal();
String password = new String((char[]) token.getCredentials());
// 通过用户名到数据库查询用户信息
QueryWrapper queryWrapper = new QueryWrapper();
queryWrapper.eq("phone", phone);
Users user = usersService.getOne(queryWrapper);
if (user == null) {
throw new UnknownAccountException();
}
if (!password.equals(user.getPwd())) {
throw new IncorrectCredentialsException();
}
if (user.getFlag().equals(1)) {
throw new LockedAccountException();
}
return new SimpleAuthenticationInfo(user, password, getName());
}
/**
* 获取授权信息
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
Users user = (Users) SecurityUtils.getSubject().getPrincipal();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
String role = user.getType().equals(1) ? "teacher" : "student";
System.out.println("role = " + role);
Set<String> set = new HashSet<>();
set.add(role);
//设置该用户拥有的角色
info.setStringPermissions(set);
return info;
}
}
4.这其中获取的数据来自于login中调用
Subject subject = SecurityUtils.getSubject();
//在认证提交前准备 token(令牌)
UsernamePasswordToken token = new UsernamePasswordToken(phone, password);
//执行认证登陆
subject.login(token);
5.最后添加全局的异常捕获处理
/*
* shiro的全局异常捕获处理
* */
@ControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler(ShiroException.class)
@ResponseBody
public Map<String, String> handleShiroException(HttpServletResponse response) {
Map<String, String> map = get401Map(response);
map.put("msg", "鉴权或授权过程出错");
return map;
}
@ExceptionHandler(UnauthenticatedException.class)
@ResponseBody
public Map<String, String> UnauthenticatedException(HttpServletResponse response) {
Map<String, String> map = get401Map(response);
map.put("msg", "认证失败");
return map;
}
@ExceptionHandler(UnauthorizedException.class)
@ResponseBody
public Map<String, String> UnauthorizedException(HttpServletResponse response) {
Map<String, String> map = get401Map(response);
map.put("msg", "授权失败");
return map;
}
@ExceptionHandler(LockedAccountException.class)
@ResponseBody
public Map<String, String> LockedAccountException(HttpServletResponse response) {
Map<String, String> map = get401Map(response);
map.put("msg", "该账号已被禁用");
return map;
}
@ExceptionHandler(IncorrectCredentialsException.class)
@ResponseBody
public Map<String, String> IncorrectCredentialsException(HttpServletResponse response) {
Map<String, String> map = get401Map(response);
map.put("msg", "用户名或密码错误");
return map;
}
@ExceptionHandler(UnknownAccountException.class)
@ResponseBody
public Map<String, String> UnknownAccountException(HttpServletResponse response) {
Map<String, String> map = get401Map(response);
map.put("msg", "未注册的用户");
return map;
}
private Map<String, String> get401Map(HttpServletResponse response) {
response.setStatus(401);
Map<String, String> map = generalMethod.getErrorMap();
map.put("state", "401");
return map;
}
}