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

springsecurity第三章——实现基于内存修改密码

阅读更多

为了进一步加强用户体验,提供密码修改功能是必须的。因为密码修改功能更多的是应用在用户名和密码都存到数据库的,所以这里基于内存修改密码不会关注存储机制,更多的会关注security框架本身对这种方式的拓展的整体流程和设计。

security框架中提供了一个UserDetailService的实现类InMemoryDaoImpl的类来管理内存用户,它的内存凭证存储使用了一个Map来存储内存中的用户和所关联的UserDetails。而这个UserDetails的实现类,security已经封装好了——o.s.s.core.userDetails.User。

既然我们知道了是InMemoryDaoImpl来管理内存中的用户,那我们只需要对UserDetailService以及它的实现类InMemoryDaoImpl进行拓展就可以达到密码修改的功能了。

 

首先我们需要做的是拓展UserDetailService以及它的实现类InMemoryDaoImpl,拓展完成之后,我们就想办法把我们拓展后的类覆盖掉security框架中原有的处理类。

 

第一步,拓展UserDetailService和InMemoryDaoImpl:

UserDetailService拓展:我们需要一个修改密码的方法,而UserDetailService是不具有的,所以我们需要创建一个继承了UserDetailService的类IChangePassword:

package securityservice;

import org.springframework.security.core.userdetails.UserDetailsService;

//imports omitted

public interface IChangePassword extends UserDetailsService{

	void changePassword(String username,String password);
}

 

InMemoryDaoImpl拓展:这里的拓展我们需要保留它之前的方法,而且要实现我们刚拓展的那个修改密码的方法,所以需要继承InMemoryDaoImpl和实现IChangePassword:

package securityDaoImpl;

import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.memory.InMemoryDaoImpl;

import securityservice.IChangePassword;

public class InMemoryChangePasswordDaoImpl extends InMemoryDaoImpl implements IChangePassword {

	public void changePassword(String username,String password)
	{
		//get the UsrDetails
		
		User userDetails=(User)getUserMap().getUser(username);
		
		//creat a new UserDetails with the new password
		
		User newUserDetails=new User(userDetails.getUsername(),password,userDetails.isEnabled(),userDetails.isAccountNonExpired(),userDetails.isCredentialsNonExpired(),userDetails.isAccountNonLocked(),userDetails.getAuthorities());
		
		//add to the map
		
		getUserMap().addUser(newUserDetails);
	}
	
}

 

我们可以看到上面的实现代码,它从存储集合Map里面拿到当前的那个UserDetails凭证,然后创建一个新的UserDetails,修改了密码,然后保存到Map里,覆盖掉之前那个。

 

这里的拓展代码并不难实现,最主要的是理解它的整个处理流程和设计。

 

现在已经拓展完了,下一步需要把我们拓展好的类放到security框架中,覆盖掉原有的那个,这需要从配置文件里下手。ps:这里可能由于每个人的命名空间的不同,所以配置文件的标签会有不一样,不过这并不影响。

 

第二步:配置拓展后的UserDetailService到security框架中:

security有提供配置自定义UserDetailService的方法:

<authentication-manager alias="authenticationManager">
        <authentication-provider user-service-ref="InMemoryChangePasswordDaoImpl">
             
        
        </authentication-provider>

 

如上面代码显示,user-service-ref这个属性就是为了方便开发工程中拓展UserDetailService所提供的。

 

现在已经将其配置到security里面了,下一步要在配置文件初始化这个bean:

<beans:bean id="InMemoryChangePasswordDaoImpl" class="securityDaoImpl.InMemoryChangePasswordDaoImpl">
        <beans:property name="userProperties">
           <beans:props>
             <beans:prop key="guest">guest,ROLE_USER</beans:prop>
           </beans:props>
        </beans:property>
    </beans:bean>

 

到这一步,基于内存修改密码的功能已经拓展完了,剩下的工作只需要在controller里面调用这个改密的方法就ok了,下面是笔者本人的controller代码(只供参考):

package controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import securityservice.IChangePassword;

@Controller
public class ChangePasswordController {

	@Autowired	
	private IChangePassword iChangePasswordDao;
	
	@RequestMapping(value="/changePassword",method=RequestMethod.POST)
	public String changePassword(@RequestParam("newPassword") String newpassword,@RequestParam("oldPassword") String oldpassword)
	{
		Object principal =SecurityContextHolder.getContext().getAuthentication().getPrincipal();
		
		String username=principal.toString();
		
		if(principal instanceof UserDetails)
		{
			username=((UserDetails)principal).getUsername();
		}	
		
//		if(((UserDetails)principal).getPassword().equals(oldpassword))
//		{
			iChangePasswordDao.changePassword(username, newpassword);
//		}	
		
		return "redirect:home.jsp";
		
	}
	
}

 

到这里,整个后台过程已经拓展完了,其实这里的拓展并不难,主要还是要理解其整体的处理流程和设计方法,然后按照security框架作者的设计思想去拓展,然后就可以水到渠成了。

 

本文是笔者学习经验所得,仅供参考,希望能帮到有需要的人。

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics