Spring Security学习二 - 自定义Login方法

Author: Kagula
Date: 2016-9-19

环境
 [1]Spring 3.1.2
 [2]Tomcat 7.x

概要
    在《Spring Security学习一》的基础上完善自定义Login界面,并增加了Login方法的自定义。
    这里仅列出源码。
 
测试内容
[1]能否把密码明文转成密文,MD5加密。pass.
[2]能否同Spring MVC兼容。pass.
[3]自定义login方法。pass.
[4]个性化提示用户没有权限。pass.
[5]排除对jpg等图片的权限检查。pass.
[6]增加一组URL的权限检查。pass.
[7]自定义404错误。pass.

正文
第一部份配置文件
文档结构如图

Spring Security学习二 - 自定义Login方法_第1张图片
pom.xml


  4.0.0
  com.nuoke
  testSpringSecurity2
  war
  0.0.1-SNAPSHOT
  testSpringSecurity2 Maven Webapp
  http://maven.apache.org

  
	UTF-8
	UTF-8
	3.1.2.RELEASE
  
  
      
    
		org.springframework
		spring-core
		${spring.version}
		
		
	
	
		org.springframework
		spring-beans
		${spring.version}
		
	
	
		org.springframework
		spring-webmvc
		${spring.version}
	
	
	
      org.springframework.security
      spring-security-core
      ${spring.version}
    
    
      
      org.springframework.security  
      spring-security-web  
      ${spring.version}
	
	 
	  
      org.springframework.security  
      spring-security-config  
      ${spring.version}  
     

      
      org.springframework.security  
      spring-security-taglibs  
      ${spring.version}  
    
    
    
      jstl
      jstl
      1.2
      
  
  
  
    testSpringSecurity2
       
       
          
          org.apache.maven.plugins  
          maven-compiler-plugin  
          3.0  
            
              1.7  
              1.7  
            
          
      
  


 

web.xml



  Archetype Created Web Application
  
  
  
  
    encodingFilter
    org.springframework.web.filter.CharacterEncodingFilter
    
      encoding
      UTF-8
    
  
    
  
  
    encodingFilter
    /*
  
  
  
  
  	contextConfigLocation  
    /WEB-INF/spring-servlet.xml,/WEB-INF/spring-security.xml
  

  
  
    org.springframework.web.context.ContextLoaderListener
   
    
    
  
    org.springframework.security.web.session.HttpSessionEventPublisher
  
  
    
  
    springSecurityFilterChain
    org.springframework.web.filter.DelegatingFilterProxy
  
  
  
    springSecurityFilterChain
    /*
  
  
  
    
    
    spring  
    org.springframework.web.servlet.DispatcherServlet  
    1  
  
  
    
    
    spring  
    *.do  
   
    
   
    index.jsp 
  
  
  
     404
     /My404.jsp
  
  
  
     java.lang.Exception
     /MyEception.jsp
     


 

spring-servlet.xml



         
      
	
	
	  
      
  
      
    
    
	
	
	    
	
		
		
	

	
	
    
        
            
                outException
                outException
            
        
    	


 

spring-security.xml

  
  
  
    
      
    
    
    
    
    
    
    
    
      
     
    
        
        
        
         
         
         
         
        

	    
	    
	    
          
          
          
          
        
        
        
        
        
        
        
        
        
            
              
            
                
                  
                    
                    
                
         
          
      
      
      
          
          
          
      
    
      
      
          
        
          
          
    
      
      
    
      
      
      
      
    
      
       
            
   


 

第二部份java源文件
共有7个class文件,这里只列出《学习一》内容不同或没有的java源文件

Spring Security学习二 - 自定义Login方法_第2张图片
MyUserDetailService.java

package com.nuoke;

import java.util.ArrayList;
import java.util.Collection;

import org.springframework.dao.DataAccessException;
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;
 
public class MyUserDetailService implements UserDetailsService {
    //登陆验证时,通过username获取用户的所有权限信息,
    //并返回User放到spring的全局缓存SecurityContextHolder中,以供授权器使用
    public UserDetails loadUserByUsername(String username) 
            throws UsernameNotFoundException, DataAccessException {   
        Collection auths=new ArrayList(); 
         
        SimpleGrantedAuthority auth2 = new SimpleGrantedAuthority("ROLE_ADMIN"); 
        SimpleGrantedAuthority auth1 = new SimpleGrantedAuthority("ROLE_USER"); 
         
        if(username.equals("admin")){ 
            auths=new ArrayList(); 
            auths.add(auth1);
            auths.add(auth2);      
        }     
         
        //第二个参数是密码。是123的md5码。        
        User user = new User(username, "202cb962ac59075b964b07152d234b70", true, true, true, true, auths);
        
        //以后还可以new a class derived from User class,为user存放更多有关这个user的信息。
        //参考下文User定义,可以存放用户的更多属性。
        //http://blog.csdn.net/ydj7501603/article/details/9049663
        return user;  
   } 
}


 

MyController.java

package com.nuoke.controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping(value = "/main")
public class MyController {	
	@RequestMapping(value = "/admin.do")
	public ModelAndView adminPage() {
		ModelAndView model = new ModelAndView();
		model.addObject("title", "Spring Security Hello World");
		model.addObject("message", "这是一个安全被保护的页面!");
		//在MyInvocationSecurityMetadataSource类中指定了保护。
		model.setViewName("admin");

		return model;
	}
	
	@RequestMapping(value = "/welcome.do")
	public ModelAndView WelcomeAction() {
		ModelAndView model = new ModelAndView();
		model.addObject("title", "Spring Security Hello World");
		model.addObject("message", "这是一个欢迎页面!");
		model.setViewName("welcome");
		return model;
	}
	
	/*
	 * 仅自定义login页面
	 * 测试url:
	 * http://localhost:8080/testSpringSecurity2/main/login.do
	 */
	@RequestMapping(value = "/login.do")
	public ModelAndView LoginAction(
			@RequestParam(value = "error", required = false) String error,
			@RequestParam(value = "logout", required = false) String logout) {
		ModelAndView model = new ModelAndView();
		if (error != null) {
			model.addObject("error", "用户名或密码不正确!");
		}

		if (logout != null) {
			model.addObject("msg", "您已成功注销系统.");
		}
		model.setViewName("login");
		return model;
	}
	
	//自定义Login方法示例
	/*
	 * 测试Url:
	 * http://localhost:8080/testSpringSecurity2/main/customLogin.do
	 * 
	 * 补充参考资料:
	 * 《在spring security手动 自定义 用户认证 SecurityContextHolder》
	 * https://my.oschina.net/lemonzone2010/blog/268452#OSC_h2_1
	 * 《》
	 * http://www.programcreek.com/java-api-examples/index.php?api=org.springframework.security.core.context.SecurityContext
	 */
	@Autowired
    private AuthenticationManager authenticationManager;
	
	@RequestMapping(value="/customLogin.do")
	public ModelAndView customLoginAction(@RequestParam(defaultValue="") String username,
			 @RequestParam(defaultValue="") String password,
			 HttpServletRequest request){
		//
		username = username.trim();

		//返回登录页面
        ModelAndView model = new ModelAndView();
    	model.setViewName("customLogin");
		
		if(username==null||username.isEmpty()||
				password==null||password.isEmpty())
		{
			return model;			
		}
		
		//向AJAX请求返回消息提醒(json字符串)
		model.setViewName("customLoginResponse");
		UsernamePasswordAuthenticationToken authRequest = 
				new UsernamePasswordAuthenticationToken(username, password);
	    //
		try {
			Authentication authentication = authenticationManager.authenticate(authRequest);
	        SecurityContextHolder.getContext().setAuthentication(authentication);
	        HttpSession session = request.getSession();
	        session.setAttribute("SPRING_SECURITY_CONTEXT", SecurityContextHolder.getContext()); // 这个非常重要,否则验证后将无法登陆
	        
	        model.addObject("message","登录用户:"+authentication.getName());
	        model.addObject("ok",1);//这样view/customLogin.jsp得到成功标记后可以做url跳转。
	    } catch (AuthenticationException ex) {
	    	model.addObject("message","用户名或密码错误");
	    	model.addObject("ok",0);//为了view/customLogin.jsp得到失败标记后可以提醒用户重新输入用户名、密码。
	    }//end catch
	    return model;
	}//end handler
}//end class


 

第三部份jsp源文件
参考图一共有十个jsp文件,这里只列出比较重要的几个jsp。

MyException.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>


    异常处理页面


<% Exception ex = (Exception) request.getAttribute("Exception");%>

Exception:<%=ex.getMessage()%>


login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>





示例一:自定义登录界面
    



    

请输入您的用户名与密码

${error}
${msg}
用户:
密码:


welcome.jsp

<%@ page language="java" import="java.util.*,java.text.*" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@page session="false"%>


    

标题 : ${title}

消息 : ${message}


<% Date date = new Date(); SimpleDateFormat t = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String time = t.format(date); %>
当前时间:<%= time %>


admin.jsp

<%@page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@page session="true"%>


    

标题 : ${title}

消息 : ${message}

欢迎 : ${pageContext.request.userPrincipal.name} 登录本系统 | 注销


customLogin.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>



自定义登录控制







	

示例二 自定义login方法


 

customLoginResponse.jsp

<%@ page language="java" import="java.util.*,java.text.*" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@page session="false"%>
{"ok":${ok},"msg":"${message}"}


遗留问题

登录的时候,如何知道帐户已经在其它地方登录?


参考资料
[1]《Spring Security》
http://docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity.html
[2]《intercept-url配置》
参考这篇文章可以限定用户只能使用https协议访问服务
http://haohaoxuexi.iteye.com/blog/2161056
[3]《Spring Security 3.1.2 + Spring Framework 3.1.2+使用Annotation实战指南》
http://www.itpub.net/thread-1719846-1-1.html
[4]《Spring Security 3.1 自定义实例之登陆》
使用AJAX来验证登录
使用了spring自带的login方法来验证登录
http://www.cnblogs.com/ilife/archive/2013/02/28/2936067.html
[5]《Spring Security 3.1.2.RELEASE API》
http://tool.oschina.net/uploads/apidocs/spring-security-3.1.2/apidocs/
[6]《spring security Controller用户角色的判断》
http://blog.csdn.net/softwarehe/article/details/7711302
[7]《How to manually log out a user with spring security?》
http://stackoverflow.com/questions/5727380/how-to-manually-log-out-a-user-with-spring-security
[8]《Spring and Angular JS: A Secure Single Page Application》
https://spring.io/blog/2015/01/12/spring-and-angular-js-a-secure-single-page-application

你可能感兴趣的:(JavaScript或前端,安全,Java)