<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-securityartifactId>
dependency>
/*
* @description: 用户信息封装
*/
@Data
public class SecurityUser implements Serializable, UserDetails {
private String username; //用户名
private String password; //密码
private List<String> roleName; //角色
private Collection<? extends GrantedAuthority> authorities; //权限
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
/*
* @description: 查询用户信息以权限
*/
@Service
public class SecurityUserDetails implements UserDetailsService {
@Autowired
private UserManageMapper userManageMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserManage user = userManageMapper.selectOne(new QueryWrapper<UserManage>().eq("username", username));
if (user==null){
throw new RuntimeException("用户名不存在");
}
List<String> roleNames = userManageMapper.findRoleNames(user.getUsername());
List<GrantedAuthority> authorities = new ArrayList<>();
for (String roleName : roleNames) {
authorities.add(new SimpleGrantedAuthority("ROLE_"+roleName));
}
SecurityUser securityUser = new SecurityUser();
securityUser.setUsername(user.getUsername());
securityUser.setPassword(user.getCryp());
securityUser.setAuthorities(authorities);
System.out.println("系统管理:用户管理========"+securityUser);
return securityUser;
}
}
/*
* @description: JWT工具类
*/
public class JwtUtil {
private final static long excTime = 604800000; // 7天过期
private static final String secretKey = "jhdr"; //秘钥
/*
* @description: 生成JWT
* @param null
* @return
*/
public static String createJwt(String jti,String username,Long timeMillis){
Date nowDate = new Date();
long nowTimeMillis = System.currentTimeMillis();
if (timeMillis == null) {
timeMillis = excTime;
}
long excTimeMillis = timeMillis + nowTimeMillis;
Date excDate = new Date(excTimeMillis);
JwtBuilder builder = Jwts.builder()
.setId(jti) //唯一的ID
.setSubject(username) //主题
.setIssuer("daishan") //签发者
.setIssuedAt(nowDate) //签发日期
.setExpiration(excDate) //设置过期时间
.signWith(SignatureAlgorithm.HS256, generalKey()); //使用HS256对称加密算法签名, 第二个参数为秘钥
return builder.compact();
}
/*
* @description: 生成JWT
* @param null
* @return
*/
public static String createJwt(SecurityUser securityUser, Long timeMillis){
Date nowDate = new Date();
long nowTimeMillis = System.currentTimeMillis();
if (timeMillis == null) {
timeMillis = excTime;
}
long excTimeMillis = timeMillis + nowTimeMillis;
Date excDate = new Date(excTimeMillis);
JwtBuilder builder = Jwts.builder()
.setSubject(securityUser.getUsername()) //主题
.setIssuer("daishan") //签发者
.setIssuedAt(nowDate) //签发日期
.setExpiration(excDate) //设置过期时间
.signWith(SignatureAlgorithm.HS256, generalKey()); //使用HS256对称加密算法签名, 第二个参数为秘钥
return builder.compact();
}
/*
* @description: 解析JWT
* @param null
* @return
*/
public static Claims parserJwt(String jwt){
return Jwts.parser()
.setSigningKey(generalKey())
.parseClaimsJws(jwt)
.getBody();
}
/*
* @description: 生成加密后的秘钥 secretKey
* @param null
* @return
*/
public static SecretKey generalKey() {
byte[] encodeKey = Base64.getDecoder().decode(secretKey);
SecretKey key = new SecretKeySpec(encodeKey,0,encodeKey.length,"AES");
return key;
}
/**
* 登录成功处理
*/
@Component
public class LoginSuccessHandler implements AuthenticationSuccessHandler {
@Autowired
private SecurityUserDetails securityUserDetails;
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.setContentType("applicatiopn/json;charset=utf-8");
PrintWriter writer = httpServletResponse.getWriter();
SecurityUser userDetailsUser = (SecurityUser) authentication.getPrincipal();
UserDetails userDetails = securityUserDetails.loadUserByUsername(authentication.getName());
System.out.println(userDetails);
String token = JwtUtil.createJwt(userDetailsUser,null);
Map<String,Object> map = new HashMap<>();
map.put("cood","200");
map.put("msg","登录成功");
map.put("token",token);
map.put("userDetails",userDetails);
map.put("username",authentication.getName());
writer.println(JSON.toJSONString(map));
writer.flush();
writer.close();
}
}
/**
* 登录失败处理
*/
@Component
public class LoginFailHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setContentType("applicatiopn/json;charset=utf-8");
PrintWriter writer = httpServletResponse.getWriter();
Map<String,Object> map = new HashMap<>();
map.put("cood","400");
map.put("msg","用户名或密码错误");
writer.println(JSON.toJSONString(map));
writer.flush();
writer.close();
}
}
/**
* 未登录处理
*/
@Component
public class NotLoginHandler implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
httpServletResponse.setContentType("applicatiopn/json;charset=utf-8");
PrintWriter writer = httpServletResponse.getWriter();
Map<String,Object> map = new HashMap<>();
map.put("cood","405");
map.put("msg","请先登录");
writer.println(JSON.toJSONString(map));
writer.flush();
writer.close();
}
}
/**
* 没有权限处理
*/
@Component
public class NotAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
httpServletResponse.setContentType("applicatiopn/json;charset=utf-8");
PrintWriter writer = httpServletResponse.getWriter();
Map<String,Object> map = new HashMap<>();
map.put("cood","403");
map.put("msg","没有权限访问或操作,请联系管理员");
writer.println(JSON.toJSONString(map));
writer.flush();
writer.close();
}
}
/**
* 退出登录
*/
@Component
public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
httpServletResponse.setContentType("applicatiopn/json;charset=utf-8");
PrintWriter writer = httpServletResponse.getWriter();
Map<String,Object> map = new HashMap<>();
map.put("cood","200");
map.put("msg","退出成功");
writer.println(JSON.toJSONString(map));
writer.flush();
writer.close();
}
}
/*
* 拦截器
*/
public class JwtAuthorizationFilter extends BasicAuthenticationFilter {
private UserDetailsService userDetailsService;
// 从 Spring Security 配置文件那里传过来
public JwtAuthorizationFilter(AuthenticationManager authenticationManager, UserDetailsService userDetailsService) {
super(authenticationManager);
this.userDetailsService = userDetailsService;
}
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
// 获取当前认证成功的权限信息
UsernamePasswordAuthenticationToken authentication = getAuthentication(request);
if (authentication !=null){
//设置springsecurity上下文中
SecurityContextHolder.getContext().setAuthentication(authentication);
}
chain.doFilter(request,response);
}
private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) throws IOException {
try {
//获取请求头token
String token = request.getHeader("token");
if (token !=null){
//解析Token
Claims claims = JwtUtil.parserJwt(token);
String username = claims.getSubject(); //获取用户名
UserDetails userDetails = userDetailsService.loadUserByUsername(username); //获取用户信息以及角色
Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities(); //获取权限
return new UsernamePasswordAuthenticationToken(userDetails,token,authorities); //返回用户以及权限
}
} catch (UsernameNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
配置如下:
@Autowired
private SecurityUserDetails securityUserDetails;
@Override
protected void configure(HttpSecurity http) throws Exception {
// addFilterBefore也可以
http.addFilter(new JwtAuthorizationFilter(authenticationManager(),securityUserDetails));
/**
* @description: 拦截器
*/
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
private SecurityUserImpl securityUser;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String token = request.getHeader("token");
if (token !=null){
Claims claims = JwtUtil.parserJwt(token);
String username = claims.getSubject();
UserDetails userDetails = securityUser.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails,userDetails.getPassword(),userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); //这个可写可不写
//用户信息以及权限设置到上下文中
SecurityContextHolder.getContext().setAuthentication(authentication);
}
filterChain.doFilter(request,response); //放行
}
}
配置如下:
@Autowired
private JwtAuthorizationTokenFilter jwtAuthorizationTokenFilter;
@Override
protected void configure(HttpSecurity http) throws Exception {
// 只能是addFilterBefore
http.addFilterBefore(jwtAuthorizationTokenFilter, UsernamePasswordAuthenticationFilter.class);
public class Filter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
//逻辑都是一样的,配置只能配置addFilterBefore,不能配置addFilter
}
}
@Configuration
public class MyAuthenticationProvider implements AuthenticationProvider {
@Autowired
private SecurityUserDetails securityUserDetails;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String userName = authentication.getName();// 这个获取表单输入中的用户名
String password = (String) authentication.getCredentials();
UserDetails userDetails = securityUserDetails.loadUserByUsername(userName);
String encodePassword = passwordEncoder.encode(password);
if (!passwordEncoder.matches(password,userDetails.getPassword())) {
throw new UsernameNotFoundException("用户名或者密码不正确");
}
Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
System.out.println("=============用户名:"+userName);
System.out.println("=============密码:"+password);
System.out.println("=============UserDetails数据集合:"+userDetails);
System.out.println("=============权限为:"+authorities);
return new UsernamePasswordAuthenticationToken(userDetails, encodePassword, authorities);
}
@Override
public boolean supports(Class<?> aClass) {
return true;
}
}
/**
* Spring Security 配置类
* @EnableGlobalMethodSecurity 开启注解的权限控制,默认是关闭的。
* prePostEnabled:使用表达式实现方法级别的控制,如:@PreAuthorize("hasRole('ADMIN')")
* securedEnabled: 开启 @Secured 注解过滤权限,如:@Secured("ROLE_ADMIN")
* jsr250Enabled: 开启 @RolesAllowed 注解过滤权限,如:@RolesAllowed("ROLE_ADMIN")
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private LoginSuccessHandler loginSuccessHandler; //登录成功
@Autowired
private LoginFailHandler loginFailHandler; //登录失败
@Autowired
private LogoutSuccessHandlerImpl logoutSuccessHandler; //退出成功
@Autowired
private NotAccessDeniedHandler notAccessDeniedHandler; //没有权限处理
@Autowired
private NotLoginHandler notLoginHandler; //未登录处理
@Autowired
private MyAuthenticationProvider myAuthenticationProvider;
@Autowired
private SecurityUserDetails securityUserDetails;
@Autowired
private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.authenticationProvider(myAuthenticationProvider); //认证提供者自定义认证
auth.userDetailsService(securityUserDetails); //实现UserDetails类认证
}
/**
* anyRequest | 匹配所有请求路径
* access | SpringEl表达式结果为true时可以访问
* anonymous | 匿名可以访问
* denyAll | 用户不能访问
* fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录)
* hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问
* hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问
* hasAuthority | 如果有参数,参数表示权限,则其权限可以访问
* hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
* hasRole | 如果有参数,参数表示角色,则其角色可以访问
* permitAll | 用户可以任意访问
* rememberMe | 允许通过remember-me登录的用户访问
* authenticated | 用户登录后可访问
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
//禁用缓存
// http.headers().cacheControl();
// 基于Token不需要session
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.formLogin().loginProcessingUrl("/user/login").usernameParameter("username").passwordParameter("password");
//如果conroller写了自定义接口,登录成功失败处理器可以不用写
// .successHandler(loginSuccessHandler).failureHandler(loginFailHandler);
http.logout().logoutUrl("/user/logout").logoutSuccessHandler(logoutSuccessHandler);
http.httpBasic().authenticationEntryPoint(notLoginHandler);
http.exceptionHandling().accessDeniedHandler(notAccessDeniedHandler);
// 添加JWT过滤器
// 继承 BasicAuthenticationFilter类的拦截器配置
// http.addFilter(new JwtAuthorizationFilter(authenticationManager(),securityUserDetails));
// 继承 OncePerRequestFilter类的拦截器配置
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
}
private static final String [] excludeUrl = {"/user/login","/doc.html/**","/swagger-resources/**","/v2/**","/webjars/**","/image/**"};
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers(excludeUrl);
}
https://blog.csdn.net/yuanlaijike/category_9283872.html