Spring boot+Spring Security 4配置整合实例
本例所覆盖的内容:
1. 使用Spring Security管理用户身份认证、登录退出
2. 用户密码加密及验证
3. 采用数据库的方式实现Spring Security的remember-me功能
4. 获取登录用户信息。
本例所使用的框架:
1. Spring boot
2. Spring MVC
3. Spring Security
4. Spring Data JPA
5. thymeleaf
说明:
1. 本文针对采用Spring boot微框架之用户,完全采用Java config,不讨论xml配置。
2. 本例代码是完整的,请勿随意删减,否则不能运行。
一、 整合Spring Security
在pom.xml中加入如下片段:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
</dependency>
二、 配置Spring Security
几乎所有配置都在下面这个文件中完成:
@Configuration
@EnableWebMvcSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private CustomUserDetailsService customUserDetailsService;//code1
@Autowired @Qualifier("dataSource1")
private DataSource dataSource1; //code2
@Override
protected void configure(HttpSecurity http) throws Exception {
//允许所有用户访问”/”和”/home”
http.authorizeRequests().antMatchers("/", "/home").permitAll()
//其他地址的访问均需验证权限
.anyRequest().authenticated()
.and()
.formLogin()
//指定登录页是”/login”
.loginPage("/login")
.permitAll()
//登录成功后可使用loginSuccessHandler()存储用户信息,可选。
.successHandler(loginSuccessHandler())//code3
.and()
.logout()
//退出登录后的默认网址是”/home”
.logoutSuccessUrl("/home")
.permitAll()
.invalidateHttpSession(true)
.and()
//登录后记住用户,下次自动登录
//数据库中必须存在名为persistent_logins的表
//建表语句见code15
.rememberMe()
.tokenValiditySeconds(1209600)
//指定记住登录信息所使用的数据源
.tokenRepository(tokenRepository());//code4
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//指定密码加密所使用的加密器为passwordEncoder()
//需要将密码加密后写入数据库 //code13
auth.userDetailsService(customUserDetailsService).passwordEncoder(passwordEncoder());//code5
//不删除凭据,以便记住用户
auth.eraseCredentials(false);
}
// Code5----------------------------------------------
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(4);
}
// Code4----------------------------------------------
@Bean
public JdbcTokenRepositoryImpl tokenRepository(){
JdbcTokenRepositoryImpl j=new JdbcTokenRepositoryImpl();
j.setDataSource(dataSource1);
return j;
}
// Code3----------------------------------------------
@Bean
public LoginSuccessHandler loginSuccessHandler(){
return new LoginSuccessHandler();//code6
}
}
code1----------------------------------------------
@Component
public class CustomUserDetailsService implements UserDetailsService {
@Autowired //数据库服务类
private SUserService suserService;//code7
@Override
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
//SUser对应数据库中的用户表,是最终存储用户和密码的表,可自定义
//本例使用SUser中的email作为用户名:
SUser user = suserService.findUserByEmail(userName); //code8
if (user == null) {
throw new UsernameNotFoundException("UserName " + userName + " not found");
}
// SecurityUser实现UserDetails并将SUser的Email映射为username
return new SecurityUser(user); //code9
}
}
Code2----------------------------------------------
@Configuration
@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class })
public class MyConfiguration {
@Bean
public DataSource dataSource1() {
org.springframework.jdbc.datasource.DriverManagerDataSource ds = new org.springframework.jdbc.datasource.DriverManagerDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/test");
ds.setUsername("root");
ds.setPassword("****");
return ds;
}
}
Code6----------------------------------------------
//可以在这里将用户登录信息存入数据库。
public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler{
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication) throws IOException,
ServletException {
//获得授权后可得到用户信息 可使用SUserService进行数据库操作
SUser userDetails = (SUser)authentication.getPrincipal();
//输出登录提示信息
System.out.println("管理员 " + userDetails.getEmail() + " 登录");
System.out.println("IP :"+getIpAddress(request));
super.onAuthenticationSuccess(request, response, authentication);
}
public String getIpAddress(HttpServletRequest request){
String ip = request.getHeader("x-forwarded-for");
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
}
Code7----------------------------------------------
@Service("suserService")
public class SUserService {
@Autowired
private SUserRepository suserRepository;//code10
public List<SUser> findAll() {
return suserRepository.findAll();
}
public SUser create(SUser user) {
return suserRepository.save(user);
}
public SUser findUserById(int id) {
return suserRepository.findOne(id);
}
public SUser login(String email, String password) {
return suserRepository.findByEmailAndPassword(email, password);
}
public SUser update(SUser user) {
return suserRepository.save(user);
}
public void deleteUser(int id) {
suserRepository.delete(id);
}
public SUser findUserByEmail(String email) {
return suserRepository.findUserByEmail(email);
}
}
Code8----------------------------------------------
@Entity
@Table(name = "s_user", catalog = "test")//code11
public class SUser implements java.io.Serializable {
private Integer id;
private String name;
private String email;
private String password;
private Date dob;
private Set<SRole> SRoles = new HashSet<SRole>(0);// Code12
public SUser() {
}
public SUser(String name, String email, String password, Date dob, Set<SRole> SRoles) {
this.name = name;
this.email = email;
this.password = password;
this.dob = dob;
this.SRoles = SRoles;
}
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@Column(name = "name", length = 20)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
@Column(name = "email", length = 20)
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
@Column(name = "password", length = 20)
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
@Temporal(TemporalType.DATE)
@Column(name = "dob", length = 10)
public Date getDob() {
return this.dob;
}
public void setDob(Date dob) {
this.dob = dob;
}
@OneToMany(fetch = FetchType.EAGER, mappedBy = "SUser")
public Set<SRole> getSRoles() {
return this.SRoles;
}
public void setSRoles(Set<SRole> SRoles) {
this.SRoles = SRoles;
}
}
Code9----------------------------------------------
public class SecurityUser extends SUser implements UserDetails
{
private static final long serialVersionUID = 1L;
public SecurityUser(SUser suser) {
if(suser != null)
{
this.setId(suser.getId());
this.setName(suser.getName());
this.setEmail(suser.getEmail());
this.setPassword(suser.getPassword());
this.setDob(suser.getDob());
this.setSRoles(suser.getSRoles());
}
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> authorities = new ArrayList<>();
Set<SRole> userRoles = this.getSRoles();
if(userRoles != null)
{
for (SRole role : userRoles) {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(role.getName());
authorities.add(authority);
}
}
return authorities;
}
@Override
public String getPassword() {
return super.getPassword();
}
@Override
public String getUsername() {
return super.getEmail();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
Code10----------------------------------------------
public interface SUserRepository extends JpaRepository<SUser, Integer> {
@Query("select u from SUser u where u.email=?1 and u.password=?2")
SUser login(String email, String password);
SUser findByEmailAndPassword(String email, String password);
SUser findUserByEmail(String email);
}
Code11----------------------------------------------
SUser对应的表和角色表,一个都不能少
CREATE TABLE `s_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`email` varchar(20) DEFAULT NULL,
`password` varchar(60) DEFAULT NULL,
`dob` date DEFAULT NULL,
PRIMARY KEY (`id`)
)
CREATE TABLE `s_role` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(20) DEFAULT NULL,
`uid` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `userrole` (`uid`),
CONSTRAINT `userrole` FOREIGN KEY (`uid`) REFERENCES `s_user` (`id`)
)
Code12----------------------------------------------
@Entity
@Table(name = "s_role", catalog = "test")
public class SRole implements java.io.Serializable {
private Integer id;
private SUser SUser;
private String name;
public SRole() {
}
public SRole(SUser SUser) {
this.SUser = SUser;
}
public SRole(SUser SUser, String name) {
this.SUser = SUser;
this.name = name;
}
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "uid", nullable = false)
public SUser getSUser() {
return this.SUser;
}
public void setSUser(SUser SUser) {
this.SUser = SUser;
}
@Column(name = "name", length = 20)
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
Code13----------------------------------------------
@SpringBootApplication
public class Application {
@SuppressWarnings("unchecked")
public static void main(String[] args) {
SpringApplication app=new SpringApplication(Application.class);
Appctx.ctx=app.run(args);//将密码加密 必须保证数据库s_user中有id为1的用户//code14
SUserService suserService = (SUserService) Appctx.ctx.getBean("suserService");
SUser su= suserService.findUserById(1);
BCryptPasswordEncoder bc=new BCryptPasswordEncoder(4);
su.setPassword(bc.encode("111111"));
suserService.update(su);
}
Code14----------------------------------------------
public class Appctx {
public static ApplicationContext ctx=null;
public static Object getObject(String string){
return ctx.getBean(string);
}
}
Code15----------------------------------------------
//请勿手工写入数据 供remember-me功能使用
CREATE TABLE `persistent_logins` (
`username` varchar(64) NOT NULL,
`series` varchar(64) NOT NULL,
`token` varchar(64) NOT NULL,
`last_used` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`series`)
)
Code15----------------------------------------------
public interface SRoleRepository extends JpaRepository<SRole,Integer> {
}
三、 Html及controller
index.html:
-------------------------------------------------------------------
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8"/>
<title>Insert title here</title>
</head>
<body>
Welcome to Spring technology page!
</body>
</html>
hello.html
-------------------------------------------------------------------
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Hello World!</title>
</head>
<body>
<h1 th:inline="text">Hello [[${#httpServletRequest.remoteUser}]]!</h1>
<form th:action="@{/logout}" method="post">
<input type="submit" value="Sign Out"/>
</form>
</body>
</html>
home.html
-------------------------------------------------------------------
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Example</title>
</head>
<body>
<h1>Welcome!</h1>
<p>Click <a th:href="@{/hello}">here</a> to see a greeting.</p>
</body>
</html>
login.html
-------------------------------------------------------------------
本页中 username password remember-me三个控件请勿改名。
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security Example </title>
</head>
<body>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have been logged out.
</div>
<div th:if="${#httpServletRequest.remoteUser != null}">
<p th:text="${#httpServletRequest.remoteUser}">
sample_user
</p>
</div>
<form th:action="@{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
<input type="checkbox" name="remember-me" value="true" th:checked="checked"/><p>Remember me</p>
</form>
</body>
</html>
Controller:
-------------------------------------------------------------------
@Controller
@RequestMapping("/")
public class GreetingController {
@RequestMapping("/home")
public String home() {
return "home";
}
@RequestMapping("/hello")
public String hello() {
SecurityContext ctx = SecurityContextHolder.getContext();
Authentication auth = ctx.getAuthentication();
if(auth.getPrincipal() instanceof UserDetails)
{
SUser user = (SUser)auth.getPrincipal();
System.out.println(user.getEmail());
}
//本段代码演示如何获取登录的用户资料
return "hello";
}
@RequestMapping("/")
public String root() {
//如不进行此项配置,从login登录成功后,会提示找不网页
return "index";
}
}
四、 构建及运行顺序
1. 首先建立s_user s_role表,并向表中写入数据
2. 建立SUserService SUserRepository SUser SRoleRepository SRole类
3. 运行程序,将s_user中用户的密码加密
4. 如三中所述,配置Spring Security
5. 运行,访问http://localhost:8080/hello,系统出现如下界面:
用户名输入useremail 密码输入111111,点sign in则进入hello.html
重启浏览器,再访问http://localhost:8080/hello,则无需登录,直接到达。
在hello页面点sign out后,则返回home页面,退出了登录。
相关推荐
现在,你已经拥有一个基于Spring Boot、Spring Security和MongoDB的基础安全配置实例。通过此设置,你可以实现用户登录、权限控制以及密码加密等功能。随着需求的增长,你可以进一步扩展这个基础,例如添加自定义的...
5. **Chapter 08**: 这一章可能涉及Spring Boot的安全管理,如Spring Security的集成,包括用户认证、授权和CSRF保护等。 6. **Chapter 12**: 可能讲解了Spring Boot的缓存管理,如何使用Spring Cache抽象来实现...
前后端分离项目,Spring boot作为后端,vue框架实现前端,后端整合swagger3测试工具,jwt实现验证码生成,awt生成图形验证码,整合邮箱验证,使用mybatis-generator自动生成实体类以及mapper,设置有拦截器验证登录...
6. **security-jpa**:此文件名可能是某个模块或者配置文件,可能包含了与SpringSecurity和JPA整合的具体实现,比如用户Repository、安全配置类等。在项目中,它可能负责定义如何使用JPA来操作用户角色和权限数据,...
Spring Spring11 boot 和Spring Security4最新整合实例.pdf和Spring Security4最新整合实例.pdfSpring boot 和Spring Security4最新整合实例.pdf
Spring Boot 与 Spring Security 4 最新整合实例 Spring Boot 和 Spring Security 4 最新整合实例是一篇详细的教程,旨在指导用户如何使用 Spring Boot 和 Spring Security 4 实现用户身份认证、登录退出、用户...
Spring Boot 和 Spring Security 整合实例详解 Spring Boot 是一个快速开发框架,它简化了 Spring 应用的初始搭建以及开发过程。而 Spring Security 是一个强大的安全框架,用于处理身份认证(Authentication)和...
总的来说,Spring Boot与Spring Security 4的整合涉及到多个步骤,包括引入依赖、配置安全策略、实现用户认证机制、密码加密、remember-me功能以及登录和退出的处理。这个实例提供了全面的指导,帮助开发者在Spring ...
在实际开发中,你可能还需要关注安全(Spring Security)、日志(Logback或Log4j)、API文档(Swagger UI)等方面。结合这些知识点,你可以构建一个功能完善的、数据驱动的Web应用。通过不断学习和实践,可以提升你...
【标题】"管理系统系列--人事管理系统(Spring boot+ssm + jsp).zip" 提供了一个关于构建企业级人事管理系统的项目实例。这个系统利用了多种技术栈,包括Spring Boot、SSM(Spring、Spring MVC、MyBatis)以及JSP,...
综上所述,"致享出行(Spring Boot+MyBatis Plus)"项目是一个涵盖现代Web开发多项核心技术的实例,涵盖了后端开发、数据库设计、RESTful API、安全控制等多个方面,对于学习和实践Spring Boot和MyBatis Plus的开发者...
整合Spring Boot、MyBatis、Spring Security和Redis,首先需要在Spring Boot项目中引入相应的依赖。在`pom.xml`文件中添加MyBatis、Spring Security和Redis的Maven依赖。然后,配置Spring Boot的`application....
2. 安全控制:Spring Security是Spring Boot的安全组件,提供了一套完整的认证和授权机制。在本项目中,可以使用它实现用户登录验证、权限管理等功能。 3. RESTful API设计:Spring Boot内置了Spring MVC,用于构建...
4. **无 XML 配置**:Spring Boot 倡导“约定优于配置”的原则,大量减少了 XML 配置文件的需求,大多数配置可以通过 Java 配置类进行。 现在,我们看看 "Spring Boot in Action" 书中可能涉及的一些实例: 1. **...
1. **Spring Boot集成**:包括Spring MVC、Spring Data、Spring Security等模块的使用,以及配置文件(如application.properties或yaml)的设置。 2. **数据库设计**:涉及实体类的设计,可能包括用户(User)、题目...
在本实例中,我们将探讨如何使用Spring Boot与jQuery结合实现扫码登录功能。Spring Boot是Java领域的一款快速开发框架,简化了Spring应用的初始搭建以及开发过程。而jQuery是一款广泛使用的JavaScript库,它使得DOM...
《Spring Boot + Redis + MyBatis 整合实践详解》 在现代Java开发中,Spring Boot以其简洁的配置、快速的开发效率以及丰富的生态而备受青睐。本项目案例结合了Spring Boot、Redis缓存和MyBatis持久层框架,旨在提供...
同时,Spring Boot与Spring Security的整合能帮助你快速实现应用的安全控制,如登录认证、权限管理。 实际项目部分,你可以通过代码学习Spring Boot如何应用于实际业务场景。这可能包括CRUD操作、用户管理、支付...
在本项目中,我们主要探讨的是如何在Spring Boot框架下集成JWT(JSON Web Tokens...这个项目是学习和实践Spring Boot、JWT、Spring Security和Redis集成的一个很好的实例,对于提升Web应用的安全性有着重要的参考价值。