@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(password());
}
@Bean
PasswordEncoder password() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() // 表单登录
.and().authorizeRequests()
.anyRequest()//其他请求
.authenticated();//需要认证
//关闭csrf
http.csrf().disable();
}
}
/**
* SpringSecurity 自动调用该类
* 登录实现类 默认 继承 UserDetailsService
*/
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
@Resource
private AdminMapper adminMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper wrapper = new QueryWrapper<>();
wrapper.eq("username", username);
Admin admin = adminMapper.selectOne(wrapper);
if (admin == null) {
throw new UsernameNotFoundException("用户名不存在");
}
List auths = new ArrayList<>();
return new User(admin.getUsername(), new BCryptPasswordEncoder().encode(admin.getPassword()), auths);
}
}
只需要修改一下配置类
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() // 表单登录
.loginPage("/login") //配置登录页面 引入了thymeleaf
.loginProcessingUrl("/user/login")//设置哪个是登录的url
.permitAll()
.and().authorizeRequests()
.anyRequest()//其他请求
.authenticated();//需要认证
//关闭csrf
http.csrf().disable();
}
如果你想要在认证成功或者失败后拿到你自己定义的状态码,那你可以参考以下步骤
主要是下面的两个处理器
/**
* 用户认证失败处理类
*/
@Component("userLoginAuthenticationFailureHandler")
public class UserLoginAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
System.out.println("===" + exception.getMessage());
JsonData jsonData = null;
jsonData = new JsonData(403,"用户名或密码错误");
String json = new Gson().toJson(jsonData);//包装成Json 发送的前台
System.out.println(json);
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
out.write(json);
out.flush();
out.close();
}
}
/**
* 用户认证成功处理类
*/
@Component("userLoginAuthenticationSuccessHandler")
public class UserLoginAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
JsonData jsonData = new JsonData(200,"认证OK");
String json = new Gson().toJson(jsonData);
response.setContentType("application/json;charset=utf-8");
PrintWriter out = response.getWriter();
out.write(json);
out.flush();
out.close();
}
}
在配置类中添加自己写的两个处理类
注入自己写的两个处理器
@Resource
private UserLoginAuthenticationFailureHandler userLoginAuthenticationFailureHandler;//验证失败的处理类
@Resource
private UserLoginAuthenticationSuccessHandler userLoginAuthenticationSuccessHandler;//验证成功的处理类
配置上两个处理类
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin() // 表单登录
.loginPage("/login") //配置登录页面 引入了thymeleaf
.loginProcessingUrl("/user/login")//设置哪个是登录的url
.failureHandler(userLoginAuthenticationFailureHandler)//验证失败处理
.successHandler(userLoginAuthenticationSuccessHandler)//验证成功处理
.permitAll()
.and().authorizeRequests()
.anyRequest()//其他请求
.authenticated();//需要认证
//关闭csrf
http.csrf().disable();
}
登录
用户名:
用户密码:
标注该注解的方法或类,直接放行。
/**
* 声明不用拦截的接口
**/
@Target({ElementType.TYPE, ElementType.METHOD}) //该注解可以用在类上或者方法上
@Retention(RetentionPolicy.RUNTIME)
public @interface NoAuthentication {
}
配置类中主要是以下这个方法
//设置哪些不需要认证
@Override
public void configure(WebSecurity web) throws Exception {
//静态资源放行,我就随便写写,根据自己静态资源结构去写。
String[] urls = new String[]{
"/js/**",
"/imgs/**",
"/css/**"
};
ApplicationContext applicationContext = ApplicationContextHelper.getApplicationContext();
List whiteList = new ArrayList<>();
for (String url : urls) {
whiteList.add(url);
}
RequestMappingHandlerMapping requestMappingHandlerMapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
// 获取url与类和方法的对应信息
Map map = requestMappingHandlerMapping.getHandlerMethods();
for (Map.Entry requestMappingInfoHandlerMethodEntry : map.entrySet()) {
RequestMappingInfo key = requestMappingInfoHandlerMethodEntry.getKey();
HandlerMethod value = requestMappingInfoHandlerMethodEntry.getValue();
Set patterns = key.getPatternsCondition().getPatterns();
//无需权限都可以访问的类型
NoAuthentication noAuthentication = value.getBeanType().getAnnotation(NoAuthentication.class);
if (null != noAuthentication) {//整个controller不需要权限访问的
RequestMapping annotation = value.getBeanType().getAnnotation(RequestMapping.class);
if (null != annotation) {
String path = annotation.value()[0];
String suffix = "**";
if (path.lastIndexOf("/") != path.length() - 1)
suffix = "/**";
String s = path + suffix;
if (!whiteList.contains(s)) {
whiteList.add(s);
}
}
} else {//方法不需要权限访问的
NoAuthentication annotation = value.getMethod().getAnnotation(NoAuthentication.class);
if (null != annotation) {
patterns.forEach(p -> {
if (!whiteList.contains(p)) {
whiteList.add(p);
}
});
}
}
}
System.out.println("-----");
for (String s : whiteList) {
System.out.println(s);
}
urls = whiteList.toArray(urls);
super.configure(web);
web.httpFirewall(defaultHttpFirewall());
web.ignoring().antMatchers(urls);
}
/**
* 允许出现双斜杠的URL
*
* @return
*/
@Bean
public HttpFirewall defaultHttpFirewall() {
return new DefaultHttpFirewall();
}
测试:把注解放在某个方法或者某个类上面,可以发现不用登陆也能直接进行接口的访问
作用:如果你有一些接口是不需要认证的,比如说你去淘宝逛东西,你只是看看的话,要是让你登陆的话就有些不合理了,这时你就可以在类似需求的类上加上该注解,就能实现不用登陆也能访问。
源码:https://github.com/zhi-ac/security_demo
如果觉得有收获,不妨花个几秒钟点个赞,欢迎关注我的公众号玩编程地码农,目前在写数据结构与算法、计算机基础、java相关的知识。