Spring Security实现用户授权
思路:
- 进行登录,根据用户名查询用户操作权限,查询当前登录用户操作权限数据放到Redis中(key:username value:权限数据)。
- 校验的时候,从请求头获取token字符串,从token中获取username,用username到redis中查询权限数据。
详细思路
- 修改配置类,添加redis部分
- 修改loadUserByUsername接口方法:根据用户名查询用户操作权限数据,封装返回。
- 修改TokenLoginFilter,增加权限数据部分:获取当前登录用户的权限数据,把权限数据放到redis中
- 修改TokenAuthenticationFilter:从请求头获取token,从token获取username,从username到redis查询权限数据
- 在controller层加上权限判断注解
具体实现
- 修改loadUserByUsername接口方法:根据用户名查询用户操作权限数据,封装返回
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private SysUserService userService;
@Autowired
private SysMenuService menuService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//根据用户名查询用户
SysUser user = userService.getUserByUserName(username); //需要在SysUserService中具体实现功能
if(null == user) {
throw new UsernameNotFoundException("用户名不存在!");
}
if(user.getStatus().intValue() == 0) {
throw new RuntimeException("账号已停用");
}
//##################################################
//根据用户id查询用户操作权限数据
List<String> buttonList = menuService.getButtonByUserId(user.getId());
//把权限数据封装成需要的格式
List<SimpleGrantedAuthority> authList = new ArrayList<>();
for (String button : buttonList) {
authList.add(new SimpleGrantedAuthority(button.trim()));
}
return new CustomUser(user, authList);
}
//#################################################
}
- 修改TokenLoginFilter,增加权限数据部分:获取当前登录用户的权限数据,把权限数据放到redis中
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
private RedisTemplate redisTemplate;
//构造方法
public TokenLoginFilter(AuthenticationManager authenticationManager,RedisTemplate redisTemplate) {
this.setAuthenticationManager(authenticationManager);
this.setPostOnly(false);
//指定登录接口及提交方式,可以指定任意路径
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/system/index/login","POST"));
this.redisTemplate = redisTemplate;
}
//登录认证
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
try {
LoginVo loginVo = new ObjectMapper().readValue(request.getInputStream(), LoginVo.class);
Authentication authenticationToken = new UsernamePasswordAuthenticationToken(loginVo.getUsername(), loginVo.getPassword());
return this.getAuthenticationManager().authenticate(authenticationToken);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
//登录成功
@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
CustomUser customUser = (CustomUser) authResult.getPrincipal();
String token = JwtHelper.createToken(customUser.getSysUser().getId(), customUser.getSysUser().getUsername());
//#####################################
//把权限数据保存在redis中
redisTemplate.opsForValue().set(customUser.getUsername(), JSON.toJSON(customUser.getAuthorities()));
//#####################################
Map<String, Object> map = new HashMap<>();
map.put("token", token);
ResponseUtil.out(response, Result.ok(map));
}
- 修改TokenAuthenticationFilter:从请求头获取token,从token获取username,从username到redis查询权限数据
public class TokenAuthenticationFilter extends OncePerRequestFilter {
private RedisTemplate redisTemplate;
public TokenAuthenticationFilter(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
}
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
//如果是登录接口,直接放行
if("/admin/system/index/login".equals(httpServletRequest.getRequestURI())) {
filterChain.doFilter(httpServletRequest, httpServletResponse);
return;
}
UsernamePasswordAuthenticationToken authentication = getAuthentication(httpServletRequest);
if(null != authentication) {
SecurityContextHolder.getContext().setAuthentication(authentication);
filterChain.doFilter(httpServletRequest, httpServletResponse);
} else {
ResponseUtil.out(httpServletResponse, Result.build(null, ResultCodeNum.PERMISSION));
}
}
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
// token置于header里
String token = request.getHeader("token");
logger.info("token:"+token);
if (!StringUtils.isEmpty(token)) {
String useruame = JwtHelper.getUsername(token);
logger.info("useruame:"+useruame);
if (!StringUtils.isEmpty(useruame)) {
//#########################################
//通过username从redis中获取权限数据
String authString = (String) redisTemplate.opsForValue().get(useruame);
//把redis中字符串类型的数据转换为所需的数据类型
if (!StringUtils.isEmpty(authString)){
List<Map> mapList = JSON.parseArray(authString, Map.class);
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (Map map : mapList) {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority((String)(map.get("authority")));
authorities.add(authority);
}
return new UsernamePasswordAuthenticationToken(useruame, null, authorities);
}else {
return new UsernamePasswordAuthenticationToken(useruame, null, Collections.emptyList());
}
}
}
return null;
}
}
浙公网安备 33010602011771号