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个标准 ...
随机推荐
- [bzoj3170]松鼠聚会
这个距离就是切比雪夫距离,有一个神奇的东西是说将(x,y)变成(x+y,x-y),然后就是曼哈顿距离,因此转化后对x坐标和y坐标分别统计排序和求和(求前缀和预处理+二分) 1 #include< ...
- Dubbo的反序列化安全问题——kryo和fst
目录 0 前言 1 Dubbo的协议设计 2 Dubbo中的kryo序列化协议触发点 3 Dubbo中的fst序列化协议触发点 3.1 fst复现 3. 2 思路梳理 4 总结 0 前言 本篇是Dub ...
- 一文详解 OpenGL ES 3.x 渲染管线
OpenGL ES 构建的三维空间,其中的三维实体由许多的三角形拼接构成.如下图左侧所示的三维实体圆锥,其由许多三角形按照一定规律拼接构成.而组成圆锥的每一个三角形,其任意一个顶点由三维空间中 x.y ...
- 性能压测-压力测试-Apache JMeter安装使用
http://jmeter.apache.org/download_jmeter.cgi 下载win10得zip文件 在有java环境后进入项目得bin->jmeter.bat 启动 自带国际化 ...
- DotNetty实现WebSocket的简单使用
工作中项目是物联网项目的,管理平台又是bs架构. 如果用 Socket 的话,Web 端还需要转发,就全部统一采用了 WebSocket . DotNet 平台上的 WebSocket 实现有很多种, ...
- 洛谷 P4708 - 画画(Burnside 引理+组合数学)
洛谷题面传送门 神仙题 %%%%%%%%%%%%%%%%%%%% 题解搬运人来了 首先看到本质不同(无标号)的图计数咱们可以想到 Burnside 引理,具体来说,我们枚举一个排列 \(p\),并统计 ...
- Codeforces 917D - Stranger Trees(矩阵树定理/推式子+组合意义)
Codeforces 题目传送门 & 洛谷题目传送门 刚好看到 wjz 在做这题,心想这题之前好像省选前做过,当时觉得是道挺不错的题,为啥没写题解呢?于是就过来补了,由此可见我真是个大鸽子(( ...
- 【GS文献】测序时代植物复杂性状育种之基因组选择
综述:Genomic Selection in the Era of Next Generation Sequencing for Complex Traits in Plant Breeding 要 ...
- KEGG通路图应该怎么看(转载)
转载:http://www.omicshare.com/forum/thread-107-1-3219.html (出处: OmicShare Forum) 不管是RNA-seq的分析数据,还是蛋白组 ...
- Dango之form校验组件
目录 1.引入案例 2. form组件的功能 3. form组件的使用 3.1 自定义form校验类 3.2 校验数据 3.3 渲染页面 3.4 展示错误信息 3.5 自定义校验结果 3.6 form ...