SpringSecurity自定义注解和处理器
登录功能
添加一个配置类
@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<Admin> wrapper = new QueryWrapper<>();
wrapper.eq("username", username);
Admin admin = adminMapper.selectOne(wrapper);
if (admin == null) {
throw new UsernameNotFoundException("用户名不存在");
}
List<GrantedAuthority> 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();
}
此时的登录页面
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<section>
<span>用户名:<input type="text" id="username" name="username"/> <br/> </span>
<span>用户密码:<input type="password" id="password" name="password"/> <br/> </span>
<button onclick="login()">登录</button>
</section>
<script type="text/javascript" src="../static/js/jquery.js" th:src="@{/js/jquery.js}"></script>
<script>
function login(){
let username = document.getElementById("username");
let password = document.getElementById("password");
let username_and_password = {
username:username.value,
password:password.value
}
$.ajax({
type:"Post",
url:"/user/login",
data:username_and_password,
success:function (data) {
console.log(data)
console.log(data.code)
console.log(data.msg)
if (data.code == 200){ //拿到自己定义的状态码进行跳转
alert(data.msg)
// window.location.href = "/hello";
// console.log("hehe")
}else if (data.code == 403){
alert(data.msg)
} else {
alert("客户端出错")
}
}
})
}
</script>
</body>
</html>
写一个注解
标注该注解的方法或类,直接放行。
/**
* 声明不用拦截的接口
**/
@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<String> whiteList = new ArrayList<>();
for (String url : urls) {
whiteList.add(url);
}
RequestMappingHandlerMapping requestMappingHandlerMapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
// 获取url与类和方法的对应信息
Map<RequestMappingInfo, HandlerMethod> map = requestMappingHandlerMapping.getHandlerMethods();
for (Map.Entry<RequestMappingInfo, HandlerMethod> requestMappingInfoHandlerMethodEntry : map.entrySet()) {
RequestMappingInfo key = requestMappingInfoHandlerMethodEntry.getKey();
HandlerMethod value = requestMappingInfoHandlerMethodEntry.getValue();
Set<String> 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相关的知识。
SpringSecurity自定义注解和处理器的更多相关文章
- java自定义注解学习(注解处理器)
如果没有用来读取注解的方法和工作,那么注解也就不会比注释更有用处了.使用注解的过程中,很重要的一部分就是创建于使用注解处理器.Java SE5扩展了反射机制的API,以帮助程序员快速的构造自定义注解处 ...
- java自定义注解实现前后台参数校验
2016.07.26 qq:992591601,欢迎交流 首先介绍些基本概念: Annotations(also known as metadata)provide a formalized way ...
- 深入理解Java:注解(Annotation)自定义注解入门
转载:http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html 元注解: 元注解的作用就是负责注解其他注解.Java5.0定义了4个标准 ...
- 【转】深入理解Java:注解(Annotation)自定义注解入门
http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html 元注解: 元注解的作用就是负责注解其他注解.Java5.0定义了4个标准的me ...
- java自定义注解注解方法、类、属性等等【转】
http://anole1982.iteye.com/blog/1450421 http://www.open-open.com/doc/view/51fe76de67214563b20b385320 ...
- Java注解(Annotation)自定义注解入门
要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法. 元注解: 元注解的作用就是负责注解其他注解.Java5. ...
- Java注解(自定义注解、view注入)
注解这东西虽然在jdk1.5就加进来了,但他的存在还是因为使用Afinal框架的view注入才知道的.一直觉得注入特神奇,加了一句就可以把对应view生成了. 下面我们来认识一下注解这个东西 一.注解 ...
- Java:注解(Annotation)自定义注解入门
转载地址:http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html 要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的 ...
- 注解(Annotation)自定义注解入门
摘自:http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html 元注解: 元注解的作用就是负责注解其他注解.Java5.0定义了4个标准 ...
随机推荐
- [bzoj1115]石子游戏
考虑令$bi=ai-a_{i-1}$,那么每一次操作相当于让$bi-=x$且$b_{i+1}+=x$,相当于从i向i+1移动x个石子,那么容易发现偶数堆没有用处,因为另一方可以用同样的操作,因此问题相 ...
- SQL 跨实例操作
SQL 跨实例操作 我使用的是 OpenDataSource 函数,假设你要在其他机器上访问 192.168.0.1 上的数据库: SELECT A.[Name], B.[SkillName], B. ...
- 面试官问我HTTP,我真的是
面试官:今天要不来聊聊HTTP吧? 候选者:嗯,HTTP「协议」是客户端和服务器「交互」的一种通迅的格式 候选者:所谓的「协议」实际上就是双方约定好的「格式」,让双方都能看得懂的东西而已 候选者:所谓 ...
- 24:WEB漏洞-文件上传之WAF绕过及安全修复
本课重点 案例1:上传数据包参数对应修改测试 案例2:safedog+云服务器+uploadlabs测试 案例3:safedog+云服务器+uploadlabs_fuzz测试 案例4:文件上传安全修复 ...
- [省选联考 2021 A/B 卷] 宝石
大概是一眼看出来是这个给定序列在树上序列上按顺序跑最大匹配. 然后考虑维护向上和向下的链的值. 大概的做法是用倍增维护,考虑\(f_{u,i}\)是\(c_u\)在序列里的位置向后匹配\(2^i\)位 ...
- Atcoder Regular Contest 117 D - Miracle Tree(分析性质+构造)
Atcoder 题面传送门 笑死,阴间语文作业到现在还没写完,为了在这个点保持精神,我只好来颓篇题解辣 我们考虑探究一下怎么最小化 \(\max\limits_{i=1}^nE_i\),我们假设 \( ...
- 【宏组学】如何根据taxid(或taxname)快速获得taxname(或taxid)?
需求 我有一个物种taxonomy ID的list,想获得相应的物种名,不要一个个去NCBI Taxonomy官网查.反之根据物种名list查询对应的taxid. 实现 因为之前没怎么用过,我的第一个 ...
- R语言与医学统计图形【8】颜色的选取
R语言基础绘图系统 基础绘图包之低级绘图函数--内置颜色. 1.内置颜色选取 功能657种内置颜色.colors() 调色板函数:palette(), rgb(), rainbow(). palett ...
- fping (比ping更强大的ping工具)
Fping程序类似于ping(ping是通过ICMP(网络控制信息协议InternetControl Message Protocol)协议回复请求以检测主机是否存在).Fping与ping不同的地方 ...
- Linux—yum安装python-pip
centos下安装pip时失败: [root@wfm ~]# yum -y install pipLoaded plugins: fastestmirror, refresh-packagekit, ...