登录功能

添加一个配置类

@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自定义注解和处理器的更多相关文章

  1. java自定义注解学习(注解处理器)

    如果没有用来读取注解的方法和工作,那么注解也就不会比注释更有用处了.使用注解的过程中,很重要的一部分就是创建于使用注解处理器.Java SE5扩展了反射机制的API,以帮助程序员快速的构造自定义注解处 ...

  2. java自定义注解实现前后台参数校验

    2016.07.26 qq:992591601,欢迎交流 首先介绍些基本概念: Annotations(also known as metadata)provide a formalized way ...

  3. 深入理解Java:注解(Annotation)自定义注解入门

    转载:http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html 元注解: 元注解的作用就是负责注解其他注解.Java5.0定义了4个标准 ...

  4. 【转】深入理解Java:注解(Annotation)自定义注解入门

    http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html 元注解: 元注解的作用就是负责注解其他注解.Java5.0定义了4个标准的me ...

  5. java自定义注解注解方法、类、属性等等【转】

    http://anole1982.iteye.com/blog/1450421 http://www.open-open.com/doc/view/51fe76de67214563b20b385320 ...

  6. Java注解(Annotation)自定义注解入门

    要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法. 元注解: 元注解的作用就是负责注解其他注解.Java5. ...

  7. Java注解(自定义注解、view注入)

    注解这东西虽然在jdk1.5就加进来了,但他的存在还是因为使用Afinal框架的view注入才知道的.一直觉得注入特神奇,加了一句就可以把对应view生成了. 下面我们来认识一下注解这个东西 一.注解 ...

  8. Java:注解(Annotation)自定义注解入门

    转载地址:http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html 要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的 ...

  9. 注解(Annotation)自定义注解入门

    摘自:http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html 元注解: 元注解的作用就是负责注解其他注解.Java5.0定义了4个标准 ...

随机推荐

  1. [noi253]A

    定义f[i][j]表示从(i,j)走到最后一行的期望,不断从下往上dp那么对于每一行都可以得到m个方程. 但由于这m个方程不是DAG,因此考虑用高斯消元,但时间复杂度不对. 观察方程可以发现如果不断将 ...

  2. [hdu4582]DFS spanning tree

    考虑每一条非树边都连接了祖先和儿子,类似于序列上的问题,从底往上算,当发现如果走到某个环的祖先,且这个环中还没有被选到,那么就将最浅的那条边贪心选择即可具体实现可以使用bitset维护当前子树的询问, ...

  3. [bzoj5294]二进制

    首先可以发现$2^k$模3意义下有循环节,也就是1,-1,1,-1--考虑对于x个1,y个0,判断是否存在3的倍数1.x为偶数时一定可以,选择等量的1和-1即可2.x为奇数,要满足$x\ge 3$且$ ...

  4. Feed系统设计分析(类似微博的用户动态分享问题)

    Feed系统 最近在研究一个个人动态分享平台,对动态的推送方式有些疑惑,于是研究到了以下结果. 简介 在信息学里面,Feed其实是一个信息单元,比如一条朋友圈状态.一条微博.一条资讯或一条短视频等,所 ...

  5. [R] cbind和filter函数的坑

    最近我用cbind函数整合数据后,再用filter过滤数据,碰到了一个大坑. 以两组独立样本t检验筛选差异蛋白为例进行说明吧. pro2 <- df2[1:6] Pvalue<-c(rep ...

  6. Linux关机/重启/用户切换/注销

    目录 1. 关机/重启命令 2. 用户切换/注销 2.1 基本说明 2.2 切换用户 2.3 注销用户 1. 关机/重启命令 # shutdown命令 shutdown -h now # 立即关机 s ...

  7. DOM给表格添加新一行和删除整个行的内容

    DOM用appendChild()给表格添加新一行时,要注意,在HTML中没特别设置<thead>,<tbody>时,会自动添加上,所以要选择表格第一个元素在添加tr. // ...

  8. sed 修改文件

    总结 正确的修改进文件命令(替换文件内容):sed -i "s#machangwei#mcw#g" mcw.txt 正确的修改追加进文件命令(追加文件内容):sed -i &quo ...

  9. 前端4 — jQuery — 更新完毕

    1.下载jQuery 网址:Download jQuery | jQuery  最好下载最新版的,因为有什么bug问题,最新版的都会有,所以学技术就用最新版的,实际开发用的时候就要讲究了 2.开始用j ...

  10. MPI 学习笔记

    目录 MPI学习笔记 MPI准备 概述 前置知识补充 环境部署 1.修改IP及主机名 2.关闭防火墙 3.实现免密码SSH登录 4.配置MPI运行环境 5.测试 程序的执行 编译语句 运行语句 MPI ...