spring security简单实例

1.Spring Security概述 
  Spring Security是一个能够为基于Spring的企业应用系统提供描述性安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC(依赖注入,也称控制反转)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作(度娘上抄的)。 
2.实例功能 
  用户登录:(认证) 
  权限控制:(访问权限、最多登录控制) 
3.jar包: 
   下载:http://dl2.iteye.com/upload/attachment/0088/7423/9f1490b7-2e67-3c9b-b3ce-a5563453645f.zip 
4:数据库: 

drop database if exists spring;
create database spring;
drop table if exists account;
create table account(
  id   int auto_increment primary key,  
  user varchar(50),  
  pass varchar(50),  
  sign int
);


注意里面的密码存的时候要用MD5加密项目包com.spring.util中有MD5工具类 

5:配置文件 

  web.xml 

  配置加载spring配置文件配置、springsecurty过滤器、用户登录过滤器、spring监听器。 

 

<xml version="1.0" encoding="UTF-8"><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>SpringSecurity</display-name>
  <context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			 /WEB-INF/account-security.xml
 		</param-value>
  </context-param>
 
  
  <filter>  
        <filter-name>springSecurityFilterChain</filter-name>  
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
  </filter> 

  <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
  </filter-mapping>
  
  
  <!-- 如果要加过滤器的话已经要在springSecurityFilterChain后面加否者得不到用户信息 -->
  <filter>
    <filter-name>AccountLogin</filter-name>
    <filter-class>com.spring.security.AccountLogin</filter-class>
  </filter>
  <filter-mapping>
    <filter-name>AccountLogin</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  
  
  <listener>
    <listener-class>
      org.springframework.web.context.ContextLoaderListener
     </listener-class>
  </listener>
 
  
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
</web-app>


  

2.account-security.xml 

设置不同用户的访问权限、登录登出情况、springsecurity认证实现类、密码用MD5加密。 

<xml version="1.0" encoding="UTF-8"><beans xmlns="http://www.springframework.org/schema/beans" xmlns:s="http://www.springframework.org/schema/security"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd"
	default-lazy-init="true">

	<description>spring security</description>

	<!-- http安全配置 -->
	<s:http auto-config="true" use-expressions="true" access-denied-page="/denied.jsp">
	    <s:intercept-url pattern="/User/index.jsp" access="hasRole('ROLE_USER')"/>
	    <s:intercept-url pattern="/Shop/index.jsp" access="hasRole('ROLE_SHOP')"/>
	    <s:intercept-url pattern="/Service/index.jsp" access="hasRole('ROLE_SERVICE')"/>
	    <s:intercept-url pattern="/Admin/index.jsp" access="hasRole('ROLE_ADMIN')"/>
		<s:form-login login-page="/login.jsp" default-target-url="/index.jsp" authentication-failure-url="/login.jsperror=true" />
        <s:logout invalidate-session="true" logout-success-url="/login.jsp" logout-url="/j_spring_security_logout" />  
        <s:remember-me />  
        <s:session-management>
          <s:concurrency-control max-sessions="1" expired-url="/logining.jsp"/>
        </s:session-management>
	</s:http>

	<!-- 设置认证类 -->
	<s:authentication-manager alias="authenticationManager">
		<s:authentication-provider user-service-ref="accountDetailsService">
			<s:password-encoder ref="passwordEncoder"/>
		</s:authentication-provider>
	</s:authentication-manager>

	<!-- 认证bean -->
	<bean id="accountDetailsService" class="com.spring.security.AccountDetailsServiceImpl" />
	<!-- 密码MD5加密bean -->
	<bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.Md5PasswordEncoder"/>
</beans>



注意: 

       SecurityContextHolder.getContext().getAuthentication()为null的情况 

      1.如果在过滤器中获取用户信息而且此过滤器写在org.springframework.web.filter.DelegatingFilterProxy过滤器之后则返回null 

     2.  <s:intercept-url pattern="/test.jsp" filters="none"/>中则如果访问test.jsp也将返回为null 

其实简单的理解spring security就是一个过滤器A如果把过滤器写在spring security之前也就是说spring security过滤器没有在A中起到作用,同样把filters="none"则spring security过滤器也不骑作用。 


6.配置文件写完了下面来看看实现类: 

AccountDetailsServiceImpl.java 

这个是用户认证实现类通过此类返回用户登录的信息如权限什么的 

public class AccountDetailsServiceImpl implements UserDetailsService {
    private AccountDao accountDao = new AccountDaoImpl();
    
	@Override
	public UserDetails loadUserByUsername(String user)
			throws UsernameNotFoundException, DataAccessException {
		Account account = accountDao.getAccountByUser(user);
		AccountDetails accountDetails = null;
		if(account != null){
			accountDetails = new AccountDetails(account.getUser(),  account.getPass(), true, true, true,
					true, getAuthorities(account.getSign()));	
		}
		return accountDetails;
	}
	/**
	 * 根据用户类别取得信息为用户分配权限
	 * **/
	public Collection<GrantedAuthority> getAuthorities(Integer access) {

		List<GrantedAuthority> authList = new ArrayList<GrantedAuthority>();
		authList.add(new GrantedAuthorityImpl("ROLE_USER"));
		if(access == 0){
			authList.add(new GrantedAuthorityImpl("ROLE_ADMIN"));
		}else if(access == 1){
			authList.add(new GrantedAuthorityImpl("ROLE_SERVICE"));
		}else if(access == 2){
			authList.add(new GrantedAuthorityImpl("ROLE_SHOP"));
        }else if(access == 3){
			authList.add(new GrantedAuthorityImpl("ROLE_USER"));
		}
		return authList;
	}
 
}



AccountDetails.java 

这个是用户信息实现类它继承User(spring)包含用户、密码、权限等 

public class AccountDetails extends User{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	public AccountDetails(String username, String password, boolean enabled,
			boolean accountNonExpired, boolean credentialsNonExpired,
			boolean accountNonLocked,
			Collection<extends GrantedAuthority> authorities) {
		super(username, password, enabled, accountNonExpired, credentialsNonExpired,
				accountNonLocked, authorities);
	}
}


基本的用户登录就关键在这两个类 


AccountLogin.java 

如果想获取用户信息请看下面的类用户每访问一个页面在上方打印当前用户的信息 

public class AccountLogin implements Filter {

	@Override
	public void destroy() {
		
	}

	@Override
	public void doFilter(ServletRequest srequest, ServletResponse sresponse,
		  FilterChain filterChain) throws IOException, ServletException {
		  HttpServletRequest request = (HttpServletRequest) srequest;  
	      HttpServletResponse response = (HttpServletResponse) sresponse; 
	      request.setCharacterEncoding("UTF-8");
	      response.setCharacterEncoding("UTF-8");
	      //得到用户登录信息
	      PrintWriter out = response.getWriter();
	      String loginmes = "用户登录信息:<br/> <font color='red'>"+
                              SecurityContextHolder.getContext().getAuthentication().getPrincipal()+
                            "</font> <br/>";
	      System.out.println( SecurityContextHolder.getContext().getAuthentication().getPrincipal());
          out.print(loginmes);
          
	      filterChain.doFilter(request, response);
	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
 
	}

}




spring security核心实现类基本以完成 


下面是操作数据库的辅助类: 

DataSource.java 

public enum DataSource {
  /**
   * 连接数据库工具类
   * */
  INSTANCE;
  private String url;
  private String user;
  private String pass;
  private Connection con;
  
  /**
   * 初始化连接数据库信息
   * */
  private DataSource() {
	 url  = "jdbc:mysql://127.0.0.1:3306/springuseUnicode=true&characterEncoding=utf8";
	 user = "root";
	 pass = "mysql";
	 try {
		Class.forName("com.mysql.jdbc.Driver");
	    con = DriverManager.getConnection(url, user, pass);
	    System.out.println("con database sucess");
	 } catch (ClassNotFoundException e) {
		System.out.println("load driver fail");
		e.printStackTrace();
	 } catch (SQLException e) {
		System.out.println("con database fail");
		e.printStackTrace();
	}
  }
  
  /**
   * 获得数据库连接
   * 
   * */
  public Connection getCon(){
	  return con;
  }
  
}



AccountDaoImpl.java 

package com.spring.dao.impl;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import com.spring.bean.Account;
import com.spring.dao.AccountDao;
import com.spring.util.DataSource;

public class AccountDaoImpl implements AccountDao {

	/**
	 * 根据用户名返回一个包含用户信息的account类
	 * */
	@Override
	public Account getAccountByUser(String name) {
		Account account = null;
		String sql = "select * from account where user = ";
		try {
			PreparedStatement ps = DataSource.INSTANCE.getCon().prepareStatement(sql);
			ps.setString(1, name);
			ResultSet rs = ps.executeQuery();
			if(rs.next()){
				account = new Account();
				account.setId(rs.getInt("id"));
				account.setUser(rs.getString("user"));
				account.setPass(rs.getString("pass"));
				account.setSign(rs.getInt("sign"));
			}
		} catch (SQLException e) {
			System.out.println("sql: " + sql + " 查询出现异常     条件 :" + name);
		}
		return account;
	}

}


java代码基本已完成: 

登录jsp页面如下 

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>登录</title>
</head>
<body>
  <form action="j_spring_security_check" method="post">
    <input type="text" name="j_username" id="j_username">
    <br/>
    <input type="password" name="j_password" id="j_password">
    <br/>
    <input type="submit" value="提交">
  </form>
</body>
</html>




注意访问的action要为j_spring_security_check,标签也要是j_username、j_password。


id="iframeu1254640_0" src="http://pos.baidu.com/acom?rdid=1254640&dc=2&di=u1254640&dri=0&dis=0&dai=2&ps=9002x8&dcb=BAIDU_UNION_define&dtm=BAIDU_DUP_SETJSONADSLOT&dvi=0.0&dci=-1&dpt=none&tsr=0&tpr=1457449957140&ti=spring%20security%E7%AE%80%E5%8D%95%E5%AE%9E%E4%BE%8B%20-%20%E8%84%9A%E6%9C%AC%E7%99%BE%E4%BA%8B%E9%80%9A&ari=1&dbv=2&drs=1&pcs=1349x588&pss=2302x9011&cfv=11&cpl=19&chi=2&cce=true&cec=GBK&tlm=1425228567<u=http%3A%2F%2Fwww.csdn123.com%2Fhtml%2Fblogs%2F20130829%2F61028.htm&ecd=1&psr=1366x768&par=1366x728&pis=-1x-1&ccd=32&cja=true&cmi=38&col=zh-CN&cdo=-1&tcn=1457449957&qn=49c22673d6eaa695&tt=1457449957125.47.78.78" width="960" height="90" align="center,center" vspace="0" hspace="0" marginwidth="0" marginheight="0" scrolling="no" frameborder="0" allowtransparency="true" style="border-width: 0px; vertical-align: bottom; margin: 0px;">