基本全是这篇文章的代码:http://www.javaboy.org/2019/1015/springsecurity.html
第一步
import java.util.Collection;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import com.derek.laundry.entity.SeMenu;
import com.derek.laundry.entity.SeRole;
import com.derek.laundry.service.SeMenuService;
/**
* 这个类的作用,主要是根据用户传来的请求地址,分析出请求需要的角色
*
*/
@Component
public class WebFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
@Autowired
SeMenuService menuService;
AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
String requestUrl = ((FilterInvocation) object).getRequestUrl();
//查询所有菜单以及对应的权限
List<SeMenu> menus = menuService.selectAllMenu();
for (SeMenu menu : menus) {
if (antPathMatcher.match(menu.getUrl(), requestUrl)) {
List<SeRole> roles = menu.getSeRole();
String[] str = new String[roles.size()];
for (int i = 0; i < roles.size(); i++) {
str[i] = roles.get(i).getRoleKey();
}
return SecurityConfig.createList(str);
}
}
return SecurityConfig.createList("ROLE_LOGIN");
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
return null;
}
@Override
public boolean supports(Class<?> clazz) {
return FilterInvocation.class.isAssignableFrom(clazz);
}
}
第二步
import java.util.Collection;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Component;
/**
* 自定义权限决策管理器
*/
@Component
public class WebUrlAccessDecisionManager implements AccessDecisionManager {
/**
* decide 方法是判定是否拥有权限的决策方法,
* 参数1:authentication 是UserService中循环添加到 GrantedAuthority对象中的权限信息集合.
* 参数2:object 包含客户端发起的请求的requset信息,可转换为 HttpServletRequest request =((FilterInvocation) object).getHttpRequest();
* 参数3: configAttributes为WebFilterInvocationSecurityMetadataSource的getAttributes(Object object)这个方法返回的结果,
* 此方法是为了判定用户请求的url 是否在权限表中,如果在权限表中,则返回给 decide 方法,用来判定用户是否有此权限。如果不在权限表中则放行。
*/
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException, InsufficientAuthenticationException {
for (ConfigAttribute configAttribute : configAttributes) {
String needRole = configAttribute.getAttribute();
if ("ROLE_LOGIN".equals(needRole)) {
if (authentication instanceof AnonymousAuthenticationToken) {
throw new AccessDeniedException("尚未登录,请登录!");
} else {
return;
}
}
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
for (GrantedAuthority authority : authorities) {
if (authority.getAuthority().equals(needRole)) {
return;
}
}
}
throw new AccessDeniedException("权限不足,请联系管理员!");
}
@Override
public boolean supports(ConfigAttribute attribute) {
// TODO Auto-generated method stub
return true;
}
@Override
public boolean supports(Class<?> clazz) {
// TODO Auto-generated method stub
return true;
}
}
第三部
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
/**
* <p>
* 服务实现类
user roler 类就是自己的表字段,没有任何其他集成、实现接口等等
* </p>
*
* @since 2020-01-19
*/
@Service
public class SeUserService implements UserDetailsService {
@Autowired
private SeRoleMapper seRoleMapper;
/**
*
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//根据用户名查询用户
SeUser seUser = this.baseMapper.selectOne(username);
if (seUser == null) {
throw new UsernameNotFoundException("用户名不存在!");
}
//获取到当前用户所有权限
List<SeRole> roleList = seRoleMapper.selectRoleByUserId(seUser.getUserId());
List<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
if (roleList != null && !roleList.isEmpty()) {
roleList.stream().forEach(role -> authorities.add(new SimpleGrantedAuthority(role.getRoleKey())));
}
return new User(seUser.getUsername(), seUser.getPassword(), authorities);
}
}
第四步
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AccountExpiredException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.CredentialsExpiredException;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.authentication.LockedException;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import com.derek.common.JSONResult;
import com.derek.laundry.service.SeUserService;
import com.fasterxml.jackson.databind.ObjectMapper;
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
SeUserService seUserService;
@Autowired
WebFilterInvocationSecurityMetadataSource webFilterInvocationSecurityMetadataSource;
@Autowired
WebUrlAccessDecisionManager webUrlAccessDecisionManager;
@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 配置认证时用户信息获取来源以及密码校验规则
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(seUserService).passwordEncoder(new BCryptPasswordEncoder());
}
/**
* 配置放行的资源
*/
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/resources/**", "/favicon.ico", "/fonts/**", "/login.do", "/login.html", "/error");
}
/**
* @Description: HttpSecurity包含了原数据(主要是url)
* 通过withObjectPostProcessor将WebFilterInvocationSecurityMetadataSource和WebUrlAccessDecisionManager注入进来
* 此url先被WebFilterInvocationSecurityMetadataSource处理,然后 丢给
* MyAccessDecisionManager处理 如果不匹配,返回 MyAccessDeniedHandler
*
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// .anyRequest().authenticated()
.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
@Override
public <O extends FilterSecurityInterceptor> O postProcess(O object) {
object.setAccessDecisionManager(webUrlAccessDecisionManager);
object.setSecurityMetadataSource(webFilterInvocationSecurityMetadataSource);
return object;
}
}).and().formLogin().usernameParameter("username").passwordParameter("password")
// /login是登录页面的请求,/doLogin是登录页面表单的请求接口地址
.loginProcessingUrl("/doLogin").loginPage("/login").successHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(HttpServletRequest req, HttpServletResponse resp,
Authentication authentication) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
String s = new ObjectMapper().writeValueAsString(JSONResult.ok("登录成功"));
out.write(s);
out.flush();
out.close();
}
}).failureHandler(new AuthenticationFailureHandler() {
@Override
public void onAuthenticationFailure(HttpServletRequest req, HttpServletResponse resp,
AuthenticationException exception) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
String message = "登录失败!";
if (exception instanceof LockedException) {
message = "账户被锁定,请联系管理员!";
} else if (exception instanceof CredentialsExpiredException) {
message = "密码过期,请联系管理员!";
} else if (exception instanceof AccountExpiredException) {
message = "账户过期,请联系管理员!";
} else if (exception instanceof DisabledException) {
message = "账户被禁用,请联系管理员!";
} else if (exception instanceof BadCredentialsException) {
message = "用户名或者密码输入错误,请重新输入!";
}
out.write(new ObjectMapper().writeValueAsString(JSONResult.errorMsg(message)));
out.flush();
out.close();
}
}).permitAll().and().logout() // 注销成功之后来到首页
.logoutSuccessHandler(new LogoutSuccessHandler() {
@Override
public void onLogoutSuccess(HttpServletRequest req, HttpServletResponse resp,
Authentication authentication) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
out.write(new ObjectMapper().writeValueAsString(JSONResult.ok("注销成功!")));
out.flush();
out.close();
}
}).permitAll().and().csrf().disable().exceptionHandling()
// 没有认证时,在这里处理结果,不要重定向
.authenticationEntryPoint(new AuthenticationEntryPoint() {
@Override
public void commence(HttpServletRequest req, HttpServletResponse resp,
AuthenticationException authException) throws IOException, ServletException {
resp.setContentType("application/json;charset=utf-8");
resp.setStatus(401);
PrintWriter out = resp.getWriter();
String message = "访问失败!";
if (authException instanceof InsufficientAuthenticationException) {
message = "请求失败,请联系管理员!";
}
out.write(new ObjectMapper().writeValueAsString(JSONResult.errorMsg(message)));
out.flush();
out.close();
}
});
}
}
完成