前置博客:JWT工具类
数据库:
@Slf4j
@Component
public class JwtAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws ServletException {
log.info("用户访问没有授权资源:{}", e.getMessage());
response.setContentType("application/json;charset=utf-8");
response.setCharacterEncoding("utf-8");
try (PrintWriter out = response.getWriter();) {
Result result = ResultUtil.fail("用户访问未授权资源").setCode(HttpServletResponse.SC_UNAUTHORIZED);
out.write(JsonUtil.obj2String(result));
out.flush();
} catch (IOException exception) {
log.error(e.getMessage());
e.printStackTrace();
}
}
}
第二步:访问受限资源时未登录或未携带正确token时返回信息的EntryPoint
@Slf4j
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws ServletException, IOException {
log.info("登录失败or用户访问资源没有携带正确的token:{}", e.getMessage());
response.setContentType("application/json;charset=utf-8");
response.setCharacterEncoding("utf-8");
try (PrintWriter out = response.getWriter();) {
Result result = ResultUtil.fail("用户访问资源没有携带正确的token").setCode(HttpServletResponse.SC_UNAUTHORIZED);
out.write(JsonUtil.obj2String(result));
out.flush();
} catch (IOException exception) {
log.error(e.getMessage());
e.printStackTrace();
}
}
}
第三步:定义JWT认证过滤器
@Slf4j
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Resource
private JwtUtil jwtUtil;
@Resource
private UserDetailsServiceImpl userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) throws ServletException, IOException {
String token = request.getHeader(jwtUtil.getHeader());
log.info("header token:{}", token);
//如果请求头中有token,则进行解析,并且设置认证信息
if (token != null && token.trim().length() > 0) {
//根据token获取用户名
String username = jwtUtil.getSubjectFromToken(token);
// 验证username,如果验证合法则保存到SecurityContextHolder
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
// JWT验证通过,使用Spring Security 管理
if (jwtUtil.validateToken(token, userDetails)) {
//加载用户、角色、权限信息
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(username, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
}
//如果请求头中没有Authorization信息则直接放行
chain.doFilter(request, response);
}
}
第四步:自定义UserDetailsService
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Resource
private UserService userService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
MenuItemAuth menuItemAuth = userService.getAuthoritiesPermissions(username);
System.out.println(JsonUtil.obj2String(menuItemAuth));
UserDetails userDetails = org.springframework.security.core.userdetails.User.withUsername(username)
.password(menuItemAuth.getPassword())
.authorities(menuItemAuth.getAuth().split(","))
.build();
//UserDetails userDetails = new org.springframework.security.core.userdetails.User(username, passwordEncoder.encode("1234"),
// AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_vip,user:list,user:update"));
return userDetails;
}
}
相关的代码如下所示:
- MenuItem.java
@Getter
@Setter
@Builder
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class MenuItem {
/**
* 编号
*/
private Integer id;
/**
* 名称
*/
private String name;
/**
* 权限名称
*/
private String code;
/**
* 父编号
*/
private Integer pid;
}
- MenuItemAuth.java
@Getter
@Setter
@ToString
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class MenuItemAuth {
/**
* 后台管理系统菜单项列表
*/
List menuItemList;
/**
* 用户的密码
*/
private String password;
/**
* 用户角色code+权限code的字符串
*/
private String auth;
}
第五步:定义SpringSecurity配置类
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityJwtConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Resource
private JwtAccessDeniedHandler jwtAccessDeniedHandler;
@Resource
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Resource
private JwtAuthenticationFilter jwtAuthenticationFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
// 禁用session
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests()
//login 不拦截
.antMatchers("/user/login").permitAll()
.antMatchers("/user/login0").permitAll()
.antMatchers("/init/redis").permitAll()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.antMatchers("/").permitAll()
.anyRequest().authenticated();
//用户访问没有授权资源
http.exceptionHandling().accessDeniedHandler(jwtAccessDeniedHandler);
//授权错误信息处理
//用户访问资源没有携带正确的token
http.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint);
// 使用自己定义的拦截机制验证请求是否正确,拦截jwt
http.addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
}
Controller
@RestController
@RequestMapping("/authority")
public class AuthorityController {
@PostMapping("/login")
public Result login(@RequestBody User user) {
// 登陆验证
UsernamePasswordAuthenticationToken token0 =
new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());
Authentication authentication = authenticationManager.authenticate(token0);
SecurityContextHolder.getContext().setAuthentication(authentication);
//生成token,返回给客户端
MenuItemAuth menuItemAuth = userService.getAuthoritiesPermissions(user.getUsername());
UserDetails userDetails = org.springframework.security.core.userdetails.User.withUsername(user.getUsername())
.password(menuItemAuth.getPassword())
.authorities(menuItemAuth.getAuth().split(","))
.build();
String token = jwtUtil.generateToken(userDetails, user1.getId() + "");
return ResultUtil.success().setData("token", token);
}
@GetMapping("/fun1")
@PreAuthorize("hasRole(\"vip\")")
public Result fun1() {
return ResultUtil.success("fun1");
}
@GetMapping("/fun2")
@PreAuthorize("hasRole(\"admin\")")
public Result fun2() {
return ResultUtil.success("fun2");
}
@GetMapping("/fun3")
@PreAuthorize("hasAuthority(\"user:list\")")
public Result fun3() {
return ResultUtil.success("fun3");
}
@GetMapping("/fun4")
@PreAuthorize("hasAuthority(\"user:delete\")")
public Result fun4() {
return ResultUtil.success("fun4");
}
}
相关代码
@Service
@CacheConfig(cacheManager = "cacheManager")
public class UserServiceImpl extends ServiceImpl implements UserService {
@Resource
RedisService userRedisServiceImpl;
@Resource
private RoleService roleService;
@Resource
private UserPermissionService userPermissionService;
@Resource
private PermissionService permissionService;
@Resource
private RolePermissionService rolePermissionService;
@Override
public MenuItemAuth getAuthoritiesPermissions(String username) {
List menuItemList = new ArrayList();
//根据用户名查找用户
User user = baseMapper.selectOne(new QueryWrapper()
.select("id", "username", "password", "nickname", "email", "tel", "gender", "birth", "avatar", "role_id")
.eq("username", username)
.eq("status", BaseStatus.Status.ok));
//查找角色
Role role = roleService.getOne(new QueryWrapper()
.select("id", "name", "code")
.eq("status", BaseStatus.Status.ok)
.eq("id", user.getRoleId()));
menuItemList.add(MenuItem.builder()
.id(role.getId())
.name(role.getName())
.code(role.getCode())
.pid(-1) // -1表示是角色
.build());
String authorities = "ROLE_" + role.getCode() + ",";
// 当前用户拥有的权限permission的id的集合
List permissionIdList = new ArrayList();
//在tb_role_permission中查找Role所对应的角色
List rolePermissionList = rolePermissionService.list(new QueryWrapper()
.select("permission_id")
.eq("role_id", role.getId())
.eq("status", BaseStatus.Status.ok));
List pid1 = rolePermissionList.stream().map(item -> item.getPermissionId()).collect(Collectors.toList());
permissionIdList.addAll(pid1);
//在tb_user_permission中查找权限
List userPermissionList = userPermissionService.list(new QueryWrapper()
.select("permission_id")
.eq("user_id", user.getId())
.eq("status", BaseStatus.Status.ok));
List pid2 = userPermissionList.stream().map(item -> item.getPermissionId()).collect(Collectors.toList());
permissionIdList.addAll(pid2);
//查找具体的权限信息
List permissionList = permissionService.list(new QueryWrapper()
.select("id", "name", "code", "pid")
.eq("status", BaseStatus.Status.ok)
.in("id", permissionIdList));
List permissionMenuItemList = permissionList.stream().map(item -> MenuItem.builder()
.id(item.getId())
.name(item.getName())
.code(item.getCode())
.pid(item.getPid())
.build()).collect(Collectors.toList());
menuItemList.addAll(permissionMenuItemList);
String permissions = permissionList.stream().map(item -> item.getCode() + ",").collect(Collectors.joining());
System.out.println(permissions);
//去掉最后一个逗号
permissions = permissions.substring(0, permissions.length() - 1);
System.out.println(authorities + permissions);
MenuItemAuth res = MenuItemAuth.builder()
.menuItemList(menuItemList)
.auth(authorities + permissions)
.password(user.getPassword())
.build();
return res;
}
}