SpringSecurity给我们提供了一套最基本的认证方式,可是这种方式远远不能满足大多数系统的需求。不过好在SpringSecurity给我们预留了许多可扩展的接口给我们,我们可以基于这些接口实现自己的认证方式。

一、前期准备工作

1.1、创建示例数据库

Student表:

create table student
(
id int auto_increment
primary key,
stuName varchar(8) null,
password varchar(16) null,
joinTime datetime null,
clz_id int null
)
;

Classes(班级)表:

create table classes
(
id int auto_increment
primary key,
clz_name varchar(16) not null
)
;

1.2、添加相关依赖

compile group: 'mysql', name: 'mysql-connector-java'
compile group: 'org.springframework.security', name: 'spring-security-taglibs'
compile('org.springframework.boot:spring-boot-starter-jdbc')

二、实现步骤

2.1  定义Student类

package com.bdqn.lyrk.security.study.app.pojo;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User; import java.sql.Timestamp;
import java.util.Collection; public class Student extends User { private Timestamp joinTime; public Timestamp getJoinTime() {
return joinTime;
} public void setJoinTime(Timestamp joinTime) {
this.joinTime = joinTime;
} public Student(String username, String password, Collection<? extends GrantedAuthority> authorities) {
super(username, password, authorities);
} }

  在这里定义的类继承User,User是SpringSecurity里的一个类,用以描述一个用户和其最基本的属性,当然我们要扩展它的用户我们也可以实现UserDetails接口

2.2 实现UserDetailsService

package com.bdqn.lyrk.security.study.app.service;

import com.bdqn.lyrk.security.study.app.pojo.Student;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.core.GrantedAuthority;
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.Service; import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; @Service
public class UserService implements UserDetailsService { @Autowired
private JdbcTemplate jdbcTemplate; @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User.UserBuilder users = User.withDefaultPasswordEncoder();
Map<String, Object> map = jdbcTemplate.queryForMap("select t.clz_name,t1.stuName,t1.password,t1.joinTime from student t1 inner join classes t on t.id = t1.clz_id where stuName = ?", username);
Timestamp joinTime = null;
if (map != null && map.size() > 0) {
String stuName = (String) map.get("stuName");
String password = (String) map.get("password");
joinTime = (Timestamp) map.get("joinTime");
String clzName = (String) map.get("clz_name");
users.password(password);
users.username(stuName);
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(clzName);
List<GrantedAuthority> list = new ArrayList<>();
list.add(authority);
users.authorities(list);
}
UserDetails userDetails = users.build();
Student student = new Student(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities());
// UserDetails userDetails = User.withDefaultPasswordEncoder().
student.setJoinTime(joinTime);
return student;
}
}

  在这个接口里我们要实现根据用户名查找用户的方法,那么一般情况下我们都会根据自己系统的用户表来获取用户信息,这里面注意几个方面:

  1)需要设置PasswordEncoder

  2) 需要设置其角色信息,那么在这里我用班级来表示用户的角色

  3)用户的三个重要属性就是 用户名,密码与权限

  4) 这里的返回值(UserDetails)不能返回null,如果根据用户名找不到对应的用户可以抛出UsernameNotFoundException异常

2.3 改造WebSecurityConfig

package com.bdqn.lyrk.security.study.app.config;

import com.bdqn.lyrk.security.study.app.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; /**
* spring-security的相关配置
*
* @author chen.nie
* @date 2018/6/7
**/
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired
private UserService userService; @Override
protected void configure(HttpSecurity http) throws Exception {
/*
1.配置静态资源不进行授权验证
2.登录地址及跳转过后的成功页不需要验证
3.其余均进行授权验证
*/
http.
authorizeRequests().antMatchers("/static/**").permitAll().
and().authorizeRequests().antMatchers("/user/**").hasRole("7022").
and().authorizeRequests().anyRequest().authenticated().
and().formLogin().loginPage("/login").successForwardUrl("/toIndex").permitAll()
.and().logout().logoutUrl("/logout").invalidateHttpSession(true).deleteCookies().permitAll()
;
} @Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//设置自定义userService
auth.userDetailsService(userService);
}
}

在这里主要做以下处理:

 1)针对于/user/**路径的请求需要设置对应的权限

 2) 做用户注销的处理,用户注销时需要销毁session与cookie

 3)配置自定义UserDetailService

2.4、改造index.jsp

<%--
Created by IntelliJ IDEA.
User: chen.nie
Date: 2018/6/8
Time: 上午9:56
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>
<html>
<head>
<title>Title</title>
</head>
<body>
欢迎:${user.username}
<sec:authorize access="hasRole('7022')">
加入时间:${user.joinTime}
</sec:authorize>
<form action="/logout" method="post">
<input type="submit" value="退出" />
<sec:csrfInput/>
</form> </body>
</html>

  在这里面我们使用spring对security标签的支持判断当前用户是否有对应的角色,另外我们在处理登出操作时必须为post提交且有对应的token防止csrf

最新文章

  1. Elasticsearch集群状态脚本及grafana监控面板导出的json文件
  2. 关于MYSQL数据库安装方式及相关设置简要说明
  3. 在linux上搭建本地yum源
  4. 20145236 《Java程序设计》第九周学习总结
  5. form表单中的enctype属性什么意思?
  6. leetcode@ [127] Word Ladder (BFS / Graph)
  7. Java Serializable(序列化)的理解和总结、具体实现过程(转)
  8. jQuery之防止冒泡事件,冒泡事件就是点击子节点,会向上触发父节点,祖先节点的点击事件。
  9. Minimum Inversion Number(归并排序)
  10. boost:regex分割字符串(带有'\'字符) - zzusimon的专栏 - 博客频道 - CSDN.NET
  11. GG同步sqlserver报错一个案例 Invalid date format
  12. 201521123092《java程序设计》第四周学习总结
  13. react-todoMVC脚手架
  14. pyspider安装出现问题参考
  15. Python开发【初始篇】:Linux下安装Python3
  16. Javascript高级编程学习笔记(50)—— DOM2和DOM3(2)样式
  17. [poj P1141] Brackets Sequence
  18. Conditional特性用法
  19. 【前端安全】JavaScript防http劫持与XSS (转)
  20. js数据类型隐式转换问题

热门文章

  1. .net 根据图片网络地址获取图片二进制字节数据流
  2. Sprinig泛型依赖注入
  3. xslt 简单的语法
  4. excel双击文件打开时空白,使用菜单打开正常的解决办法
  5. (区间dp + 记忆化搜索)Treats for the Cows (POJ 3186)
  6. 当有多个form表单请求时如何处理?
  7. Android-WebView与本地HTML(播放视频)
  8. Java 学习的几个基础实验(Learn by doing)
  9. matplotlib可视化之如何给图形添加数据标签?
  10. 【UOJ244】 【UER #7】短路(贪心)