一、pom依赖
1.POM依赖
<!--security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.2.4.RELEASE</version>
</dependency>
<!--jwt-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
二、UserDetails
1、CustomerUserDetails实现security的UserDetails 接口
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
public class CustomerUserDetails implements UserDetails {
private String userId;
private String userName;
private String account;
private String password;
private Boolean available;
private Boolean adminFlag;
private Boolean validUrlFlag;
private Collection<? extends GrantedAuthority> authorities;
public CustomerUserDetails(String userId, String userName, String account, Collection<? extends GrantedAuthority> authorities) {
this.setUserId(userId);
this.setAccount(account);
this.setUserName(userName);
this.setAuthorities(authorities);
}
@Override
public String getUsername() {
return this.userName;
}
@Override
public boolean isAccountNonExpired() {
return false;
}
@Override
public boolean isAccountNonLocked() {
return false;
}
@Override
public boolean isCredentialsNonExpired() {
return false;
}
@Override
public boolean isEnabled() {
return false;
}
}
2、CustomerUserDetailsService实现security的UserDetailsService接口
@Component
public class CustomerUserDetailsService implements UserDetailsService {
private final UserService userService;
public CustomerUserDetailsService(UserService userService) {
this.userService = userService;
}
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
UserListVO userListVO = userService.getByUserName(userName);
List<GrantedAuthority> authorityList = new ArrayList<>();
authorityList.add(new SimpleGrantedAuthority("ROLE_USER"));
authorityList.add(new SimpleGrantedAuthority("角色2"));
return new CustomerUserDetails(userListVO.getId(), userListVO.getName(), userListVO.getName(), authorityList);
}
}
三、自定义处理器
1、CustomerOncePerRequestFilter继承OncePerRequestFilter类
这个处理器一定要有,核心代码SecurityContextHolder.getContext().setAuthentication(authentication)才有权限,不然会提示没有权限,也才能获取当前用户
@Component
public class CustomerOncePerRequestFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("进入自定义jwt过滤器");
//1.解析jwt获取用户信息
// UserDetailVO userDetailVO = dbUser();
//2.转成CustomerUserDetails对象
CustomerUserDetails customerUserDetails = new CustomerUserDetails("用户id1", "用户名称1", "登录账号1", new ArrayList<>());
//3.转成UsernamePasswordAuthenticationToken对象
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(customerUserDetails, "123451", customerUserDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
//4将UsernamePasswordAuthenticationToken信息放入到上下文对象中, 这样后面的过滤器看到我们上下文对象中有authentication对象,就相当于我们认证过了
SecurityContextHolder.getContext().setAuthentication(authentication);
//5.放行
chain.doFilter(request, response);
}
}
2、认证失败处理器
/**
* 认证失败处理器
*/
@Component
public class SecurityAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) {
System.out.println("进入token认证失败处理器");
throw new RuntimeException("token无效,请重新登录");
}
}
3、权限不足处理器
/**
* 权限不足处理器
*/
@Component
public class SecurityAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException {
System.out.println("进入权限不足处理器");
}
}
四、配置类
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private SecurityAccessDeniedHandler restfulAccessDeniedHandler; //权限不足处理器
@Resource
private SecurityAuthenticationEntryPoint restAuthenticationEntryPoint; //认证失败处理器
@Resource
private CustomerOncePerRequestFilter customerOncePerRequestFilter; //自己的jwt过滤器
/**
* 自定义加密器Bean
* 强散列哈希加密实现,在Controller新增用户的时候用此bean生成密码,与及修改密码的时候用到此bean比较新旧密码是否匹配
*/
// @Bean
// public PasswordEncoder passwordEncoder() {
// return new BCryptPasswordEncoder();
// }
/**
* 定义AuthenticationManager
* 声明它的作用是用它帮我们进行认证操作,调用这个Bean的authenticate方法会由Spring Security自动帮我们做认证
*/
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
auth.userDetailsService(userDetailsService());
}
/**
* 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 httpSecurity) throws Exception {
httpSecurity
.csrf().disable() //由于使用的是JWT,我们这里不需要csrf
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) //基于token,所以不需要session
.and()
.authorizeRequests()
.antMatchers(HttpMethod.GET, //允许对于网站静态资源的无授权访问
"/",
"/*.html",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/swagger.**",
"/v3.**",
"**_notify_url"
).permitAll()
.antMatchers("/user/login", "/Register").permitAll() //对登录注册要允许匿名访问
.antMatchers(HttpMethod.OPTIONS).permitAll() //跨域请求会先进行一次options请求
// .antMatchers("/**").permitAll() //测试时全部运行访问
.anyRequest() //除上面外的所有请求全部需要鉴权认证
.authenticated()
.and()
.headers().cacheControl() //禁用缓存
;
//添加认证失败处理器和权限不足处理器
httpSecurity.exceptionHandling()
.authenticationEntryPoint(restAuthenticationEntryPoint) //认证失败处理器
.accessDeniedHandler(restfulAccessDeniedHandler); //权限不足处理器
//配置自己的JWT过滤器
httpSecurity.addFilterBefore(customerOncePerRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
五、获取当前用户
public static Object getPrincipal() {
return SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
public class SecurityUtils {
private static final String USER_ID_KEY = "userId";
private static final String USERNAME_KEY = "username";
private static final String ADMIN_FLAG_KEY = "adminFlag";
private static final String VALID_URL_FLAG = "validUrlFlag";
/**
* 判断是否登录
*
* @return 是否登录
*/
public static boolean isLogin() {
Object principal = getPrincipal();
boolean isLogin = true;
if (principal instanceof String) {
// isLogin = !Constants.ANONYMOUS_USER.equals(principal.toString());
}
return isLogin;
}
/**
* 返修操作人ID
*
* @return 操作人ID
*/
public static String getOperatorId() {
Object principal = getPrincipal();
if (principal instanceof LinkedHashMap) {
return ((LinkedHashMap) principal).get(USER_ID_KEY).toString();
} else if (principal instanceof CustomerUserDetails) {
return ((CustomerUserDetails) principal).getUserId();
} else {
return "";
}
}
/**
* 返回登录人员是否admin
*
* @return 是否admin
*/
public static Boolean isAdmin() {
Object principal = getPrincipal();
if (principal instanceof LinkedHashMap) {
return (boolean) ((LinkedHashMap) principal).get(ADMIN_FLAG_KEY);
} else if (principal instanceof CustomerUserDetails) {
return ((CustomerUserDetails) principal).getAdminFlag();
} else {
return null;
}
}
/**
* 返回登录人员是否admin
*
* @param principal 授权信息map
* @return 是否admin
*/
public static Boolean isAdmin(Object principal) {
if (principal instanceof LinkedHashMap) {
return (boolean) ((LinkedHashMap) principal).get(ADMIN_FLAG_KEY);
} else if (principal instanceof CustomerUserDetails) {
return ((CustomerUserDetails) principal).getAdminFlag();
} else {
return null;
}
}
/**
* 返回是否验证url
*
* @param principal 授权信息map
* @return 是否验证url
*/
public static Boolean isValidUrl(Object principal) {
if (principal instanceof LinkedHashMap) {
return (boolean) ((LinkedHashMap) principal).get(VALID_URL_FLAG);
} else if (principal instanceof CustomerUserDetails) {
return ((CustomerUserDetails) principal).getValidUrlFlag();
} else {
return null;
}
}
/**
* 返回登录人员名称
*
* @return 登录人员名称
*/
public static String getOperatorName() {
Object principal = getPrincipal();
if (principal instanceof LinkedHashMap) {
return ((LinkedHashMap) principal).get(USERNAME_KEY).toString();
} else if (principal instanceof CustomerUserDetails) {
return ((CustomerUserDetails) principal).getUsername();
} else {
return "";
}
}
/**
* 获取用户详情
*
* @return 用户详情
*/
public static Object getPrincipal() {
return SecurityContextHolder.getContext().getAuthentication().getPrincipal();
}
}