`
zhh9106
  • 浏览: 58195 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

springsecurity第四章——security基于数据库后台的修改密码

阅读更多

之前有讨论过security空间基于内存修改密码的,因为绝大部分应用的用户及其用户信息都是存到数据库当中的,所以,修改密码肯定也是基于数据库操作的。

 

其实基于内存的修改密码和基于数据库的修改密码原理基本上是一样的,只不过UserDetailService的实现类已经ChangePassword()方法的实现方式不同而已。在这里重新提一遍修改密码的原理(基于数据库):

我们知道基于内存的用户数据是存到内存的一个Map中的,但是无论存到内存中还是存到数据库中,当用户登录的时候都是调用一个UserDetailService接口的方法loadUserByUsername来把User查出来,然后放到SecurityContextHolder(security框架的用户凭证的维护中心)来维护的。

 

我们知道它的原理之后,就很容易发现,基于内存和基于数据库的不同就是UserDetailService接口的实现类不同,loadUserByUsername的实现方法不同,所以我们实现密码修改时changePassword的实现方法也会不同,因为security的这两种情况只是中间那部分不同而已,所以我们关注的是UserDetailService接口的实现。上一节一节比对了基于内存认证和基于数据库认证的异同。这里就直接比较修改密码的异同。

 

首先,我们需要了解基于数据库密码修改的步骤:

1、用户数据存到数据库当中,肯定用修改数据库中的用户密码。

2、因为用户第一次登录使用的是旧密码,所以security框架中拥有的当前用户的凭证还是旧的,所以我们修改了密码之后要更新security框架中的用户凭证,而这个用户凭证是交给security框架中的securityContextHolder来维护的。所以我们修改了密码之后,只要创建一个新的用户凭证更新到色粗ContextHolder中,那么基于数据库修改密码的操作就真正的完成了。

 

因为这里提到securityContextHolder这个类,所以在这里有必要说明一下这个类:

SecurityContextHolder是security框架中的提供的类,它是里面维护了security的上下文信息,已经登录用户的权限,用户凭证等等信息。ps:为什么当前登录用户信息已经那么多用户同时登录时,securityContextHolder不仅不会丢失这些信息而且能把每一个用户的信息分得很清楚,是因为securityContextHolder是维护在线程中的,每个用户登录之后拥有的行程都是不同的,拥有的session也是不同的,所以securityContextHolder能准确无误的管理好各个用户的用户信息与用户凭证。

 

 下面我们要实现基于用户修改密码,第一步,继承UserDetailService接口,声明我们需要的方法:

package service;

import java.util.HashSet;
import java.util.Set;

import javax.annotation.Resource;

import model.Users;

import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserCache;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.core.userdetails.cache.NullUserCache;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import dao.BaseCollectionDao;
import dao.BaseEntityDao;


public interface HibernateUserDetailsService extends UserDetailsService
{

   
	public void changePassword(String username,String newpassword,String oldpassword);
	
	
	
}

 

 

第二步,实现上面定义的接口:

package service.impl;

import java.util.HashSet;
import java.util.Set;

import javax.annotation.Resource;

import model.Users;

import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserCache;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.core.userdetails.cache.NullUserCache;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import service.HibernateUserDetailsService;

import dao.BaseCollectionDao;
import dao.BaseEntityDao;

@Service("hibernateUserDetailsService")
public class HibernateUserDetailsServiceImpl implements HibernateUserDetailsService {

    private BaseCollectionDao baseCollectionDao;
     
    private BaseEntityDao baseEntityDao;
    
    private UserCache userCache = new NullUserCache(); 
	
	@Resource(name="baseCollectionDao")
	public void setBaseCollectionDao(BaseCollectionDao baseCollectionDao)
	{
		this.baseCollectionDao = baseCollectionDao;
	}
	
	
	@Resource(name="baseEntityDao")
	public void setBaseEntityDao(BaseEntityDao baseEntityDao) {
		this.baseEntityDao = baseEntityDao;
	}


	@Transactional
	public UserDetails loadUserByUsername(String username)
			throws UsernameNotFoundException
	{
		Users users = baseCollectionDao.findUniqueByProperty(Users.class, "username", username);
		
		if(users == null) 
			throw new UsernameNotFoundException("用户" + username + " 不存在!!!");
		
		String[] roles = users.getRoles().split(",");
		
		
		Set<GrantedAuthority> authorities = new HashSet<GrantedAuthority>();
		
		for(String role : roles)
		{
			authorities.add(new SimpleGrantedAuthority(role));
		}
		
		
		return new User(users.getUsername(), users.getPassword(), authorities);
	}

	@Transactional
	public void changePassword(String username,String newpassword,String oldpassword)
	{
		Authentication currentuser=SecurityContextHolder.getContext().getAuthentication();
		
		if(currentuser==null)
		{
			// This would indicate bad coding somewhere
            throw new AccessDeniedException("Can't change password as no Authentication object found in context " +
                    "for current user.");
		}
		
		
		Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
		
		String username2=((UserDetails)principal).getUsername();
		
		Users users=baseCollectionDao.findUniqueByProperty(Users.class, "username", username2);
		
		if(users.getPassword().equals(oldpassword))
		{
			users.setPassword(newpassword);
			
			baseEntityDao.update(users);
			
			SecurityContextHolder.getContext().setAuthentication(createNewAuthentication(currentuser, newpassword));
			
			userCache.removeUserFromCache(username);
			
		}
	
		
	}
	
	public Authentication createNewAuthentication(Authentication currentAuth, String newPassword)
	{
        UserDetails user = loadUserByUsername(currentAuth.getName());

        UsernamePasswordAuthenticationToken newAuthentication =
                new UsernamePasswordAuthenticationToken(user, user.getPassword(), user.getAuthorities());
        newAuthentication.setDetails(currentAuth.getDetails());

        return newAuthentication;
	}
}

 

由上面的代码可以看到,当我们完成了第一步把新密码更新到数据库之后,我们需要创建一个新的凭证Authentication,并且更新到SecurityContextHolder,因为security框架在匹配当前用户的信息以及用户权限,都是从SecurityContextHolder里面拿到这个Authentication凭证,然后再拿到相应的信息。创建新凭证的过程很简单,相信大家很容易看懂。最后一步是移除用户缓存里面的缓存的旧数据。

 

做好上面那几步,security基于数据库的密码修改功能就真正完成了。

 

 

 

分享到:
评论

相关推荐

    SpringSecurity 中文

    **使用数据库后台的Spring Security认证** - **配置**:定义数据源、用户细节服务以及密码编码器。 - **实现**:通过继承`UserDetailsService`接口并实现`loadUserByUsername`方法加载用户信息。 **基于JDBC的内置...

    springboot整合activity工作流审批前后台代码(有数据库)

    在本项目中,"springboot整合activity工作流审批前后台代码(有数据库)"是一个基于Spring Boot框架的应用,用于实现企业内部的工作流程审批系统。这个系统涵盖了员工、部门经理和BOSS三个不同的审批角色,旨在提供...

    基于springboot的后台管理系统基本框架.zip

    8. **配置文件**:如数据库连接配置、安全配置(Spring Security)、定时任务配置(Spring Scheduler)等。 9. **静态资源**(CSS、JavaScript、图片等):用于前端页面的展示。 10. **测试类**:对各个模块进行...

    基于springboot的明星周边产品销售网站源码数据库.doc

    ### 基于Spring Boot的明星周边产品销售网站——《星之语》系统设计与实现 #### 一、项目背景及概述 随着信息技术的迅速发展,互联网已经渗透到生活的各个角落,无纸化作业成为现代企业的必然选择。《星之语》明星...

    基于ssm+jsp的共享客栈管理系统源码数据库.zip

    本系统采用先进的技术栈——SSM(Spring、SpringMVC、MyBatis)+JSP,构建了一个高效、易用的共享客栈管理系统。下面将详细介绍这个系统的各个组成部分以及其背后的原理。 首先,SSM框架是Java开发Web应用的主流...

    vue-基于Spring Boot的拍卖管理系统设计与实现论文+答辩ppt.rar

    基于Spring Security实现用户认证与授权,确保只有合法用户才能进行拍卖操作。使用JWT(JSON Web Token)进行状态less的权限验证,提升系统的安全性。 六、API接口设计 前后端分离的架构中,后端提供RESTful API供...

    spring boot 项目,Meeting会议管理系统

    《Meeting会议管理系统——基于Spring Boot与JavaEE的实践探索》 在现代企业中,高效的会议管理是提升组织协同效率的关键。本项目“Meeting会议管理系统”是利用Spring Boot和JavaEE技术栈开发的一款实用工具,旨在...

    商城购物系统设计与实现(Java毕业设计-SSM项目)

    《商城购物系统设计与实现——基于Java的SSM项目》 在信息技术日新月异的今天,商城购物系统的开发已经成为企业提升效率、拓展业务的重要手段。本项目是使用Java编程语言,结合Spring、SpringMVC和MyBatis(简称SSM...

    毕设项目:基于SpringBoot+MyBatis+mysql的飞机订票系统.zip

    这是一个基于SpringBoot、MyBatis和MySQL数据库技术构建的毕业设计项目——飞机订票系统。这个系统涵盖了在线预订、查询、支付以及管理等核心功能,是学习和实践Web开发技术的良好实例。 首先,SpringBoot是Spring...

    基于SSM框架的网上体育用品商城项目源代码.rar

    4. **后台管理系统**:管理员对商品、订单、用户等信息的管理和维护,通常有专门的管理界面。 5. **支付集成**:与第三方支付平台(如支付宝、微信支付)的接口对接,涉及到HTTP请求的发送和接收,以及异步通知的...

    基于ssm+vue校园二手交易平台.zip

    SSM是Java Web开发中常用的三大组件——Spring、SpringMVC和MyBatis的组合。Spring作为核心容器,负责管理对象及依赖注入;SpringMVC作为Web层框架,处理HTTP请求与响应;MyBatis则作为持久层框架,实现了SQL语句与...

    JSP基于SSM框架校园二手商城设计源码案例设计.zip

    本篇将深入探讨一个具体的案例——"JSP基于SSM框架校园二手商城设计源码",该案例为学习者提供了丰富的实践素材,帮助理解SSM框架在实际项目中的应用。 首先,我们来了解SSM框架的核心组件: 1. **Spring**:作为...

    springboot241基于SpringBoot+Vue的电商应用系统的设计与实现.zip

    Spring Data JPA用于简化数据库操作,而Spring Security则为系统提供了安全验证和授权机制。 2. **Vue.js前端框架** Vue.js是一个轻量级的前端MVVM框架,以其高可维护性和易用性受到广泛青睐。在本电商系统中,Vue...

    官方推荐——>jsp ssm mysql实现的校园二手市场交易平台源码

    《基于JSP、SSM和MySQL的校园二手市场交易平台源码解析》 本文将深入探讨一个官方推荐的校园二手市场交易平台的源码实现,该平台是利用Java Web技术中的JSP(JavaServer Pages)、SSM(Spring、SpringMVC、MyBatis...

    课设毕设基于SpringBoot+Vue的小区物业管理系统 LW+PPT+源码可运行.zip

    本项目——“课设毕设基于SpringBoot+Vue的小区物业管理系统”旨在利用先进的Web开发技术,为小区物业提供一个高效、便捷的管理平台,以提升服务质量和管理水平。 一、核心技术栈介绍 1. SpringBoot:作为Java领域...

    java 全端开源 电商系统 springboot uniapp 小程序 前后端分离 高可用(csdn)————程序..pdf

    Lilishop是一个全面开源的B2B2C电商平台,它基于Java开发,利用SpringBoot框架构建,实现了前后端分离,并且支持小程序、PC、H5和APP等多种终端展示。这个系统设计为高可用性,适合高并发场景,包含了丰富的功能模块...

    外卖点餐系统.zip

    《外卖点餐系统详解——基于Java Spring Boot的毕业设计实践》 外卖点餐系统是现代生活中不可或缺的一部分,尤其是在快节奏的城市生活中,它极大地便利了人们的饮食需求。本系统以Java Spring Boot框架为核心,实现...

    基于ssm+jsp咖啡在线销售系统.zip

    本系统——基于SSM+JSP的咖啡在线销售系统,便是针对这一需求而设计的。它融合了Spring、SpringMVC、MyBatis(SSM)三大主流Java开发框架,结合JSP技术,为用户提供了一个功能齐全、操作便捷的线上购物体验。下面...

    15-汽车租赁(ssm+layui).rar

    《汽车租赁系统实现详解——基于SSM+LayUI技术栈》 汽车租赁系统作为现代生活中常见的服务之一,其信息化管理对于提升业务效率至关重要。本课程设计以“汽车租赁”为主题,采用主流的SSM(Spring、SpringMVC、...

    基于SSM和SpringBoot的毕业设计&;动态旅游网站.zip

    4. **支付接口集成**:为了实现在线支付,开发者可能需要集成第三方支付平台如支付宝、微信支付,SpringBoot的RestTemplate或WebClient可以方便地调用API。 5. **后台管理系统**:管理员可以发布信息、管理用户和...

Global site tag (gtag.js) - Google Analytics