springSecurity入门笔记(一)

介绍

Spring Security是Spring项目组中用来提供安全认证服务的框架,不仅可以基于数据库进行操作,还可以基于配置文件操作
包括两个主要操作:

  1. 认证
  2. 授权

使用spring security快速入门步骤

  1. 导入依赖
<!-- SpringSecurity相关依赖-->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>4.1.0.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>4.1.0.RELEASE</version>
</dependency>
  1. web.xml文件中配置过滤器链
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-security.xml</param-value>
    </context-param>
  
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
	
    <!-- Spring Secutiry 过滤器链,springSecurityFilterChain名称不能变,否则无法被识别 -->
    <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>

  1. spring security核心配置文件配置(spring-security.xml)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:security="http://www.springframework.org/schema/security"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/security
       http://www.springframework.org/schema/security/spring-security.xsd">
 <!--配置不过滤的资源(静态资源、登录相关)-->
 <security:http security="none" pattern="WEB-INF/view/login.ftl"/>
 
 <security:http auto-config="true" use-expressions="true">
        <!--
        auto-config =true时,会配置十个默认过滤器 
        use-expressions:
		        声明为true,那么在access属性要用access="hasRole(‘ROLE_USER‘)"
		        声明为false(默认),那么access直接就是access="ROLE_USER"
		-->

		<!--  
			intercept-url 定义过滤规则
			pattern 表示对哪些URL进行权限控制
			access 表示在请求对赢得URL需要什么权限
		-->
        <security:intercept-url pattern="/**" access="hasRole('ROLE_USER')" />
        
        
        <!--  自定义登录页面 
	        authentication-failure-url权限校验失败后跳转页面
	        default-target-url登录成功后跳转页
        	登录页面用户名固定为username,密码password,action:login
         -->
        <security:form-login
                    login-page='/login'
                    default-target-url="/welcome"
                    authentication-failure-url="/login?error"
                    username-parameter="username"
                    password-parameter="password"/>
       
	   
	    <!--没有权限错误页面-->
        <security:access-denied-handler error-page="/nopermit"/>      
        
        <!--退出只需要简单配置-->
        <security:logout
                logout-success-url="/login?logout"/>
                
         <!--CSRF跨服务器的request、forward请求访问,默认开启-->
        <security:csrf />  
    </security:http>
    
    <!--
    	 基于内存的用户认证 InMemoryUserDetailsManager
    -->
    <security:authentication-manager>
        <security:authentication-provider>
            <security:user-service>
                <security:user name="memory1" password="123456" authorities="ROLE_USER, ROLE_ADMIN" />
                <security:user name="memory2" password="123456" authorities="ROLE_USER" />
            </security:user-service>
        </security:authentication-provider>
    </security:authentication-manager>
</beans>

从别人那剽来的工作原理图

在这里插入图片描述

  • WebAsyncManagerIntegrationFilter:将 Security 上下文与 Spring Web 中用于处理异步请求映射的 WebAsyncManager 进行集成。

  • SecurityContextPersistenceFilter:在每次请求处理之前将该请求相关的安全上下文信息加载到 SecurityContextHolder 中,然后在该次请求处理完成之后,将 SecurityContextHolder 中关于这次请求的信息存储到一个“仓储”中,然后将 SecurityContextHolder 中的信息清除,例如在Session中维护一个用户的安全信息就是这个过滤器处理的。

  • HeaderWriterFilter:用于将头信息加入响应中。

  • CsrfFilter:用于处理跨站请求伪造。

  • LogoutFilter:用于处理退出登录。

  • UsernamePasswordAuthenticationFilter:用于处理基于表单的登录请求,从表单中获取用户名和密码。默认情况下处理来自 /login 的请求。从表单中获取用户名和密码时,默认使用的表单 name 值为 username 和 password,这两个值可以通过设置这个过滤器的usernameParameter 和 passwordParameter 两个参数的值进行修改。

  • DefaultLoginPageGeneratingFilter:如果没有配置登录页面,那系统初始化时就会配置这个过滤器,并且用于在需要进行登录时生成一个登录表单页面。

  • BasicAuthenticationFilter:检测和处理 http basic 认证。

  • RequestCacheAwareFilter:用来处理请求的缓存。

  • SecurityContextHolderAwareRequestFilter:主要是包装请求对象request。

  • AnonymousAuthenticationFilter:检测 SecurityContextHolder 中是否存在 Authentication 对象,如果不存在为其提供一个匿名 Authentication。

  • SessionManagementFilter:管理 session 的过滤器

  • ExceptionTranslationFilter:处理 AccessDeniedException 和 AuthenticationException 异常。

  • FilterSecurityInterceptor:可以看做过滤器链的出口。

  • RememberMeAuthenticationFilter:当用户没有登录而直接访问资源时, 从 cookie 里找出用户的信息, 如果 Spring Security 能够识别出用户提供的remember me cookie, 用户将不必填写用户名和密码, 而是直接登录进入系统,该过滤器默认不开启。

Spring Security登录认证

使用UserDetails和UserDetailsService来认证

  • UserDetails:封装当前正在认证的用户信息
  • UserDetailsService:规范了进行认证的方法
使用Spring Security之前的登录流程
  1. 登录页面提交登录信息
  2. controller获得登录信息交给service
  3. service调用dao层完成认证,根据用户名密码查询数据库
  4. dao层返回用户对象给service
  5. service将用户对象返回给controller
  6. controller去判断登录成功失败跳转页面
使用Spring Security登录流程
  1. 不需要controller层,这一部分由Spring Security完成,在security.xml进行配置
  2. 让自己的myUserDetailsService类 实现 UserDetailsService接口,重写loadUserByUsername方法,在调用service时就会调用这个接口
  3. 调用dao层返回我们自己的user对象封装成security提供的user对象

在spring-security.xml配置

<security:authentication-manager>
    <security:authentication-provider user-service-ref='myUserDetailsService'/>
</security:authentication-manager>

<!--
	<bean id="myUserDetailsService"
      	class="org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl">
        <!--<property name="dataSource" ref="dataSource"/>
	</bean>
-->

这个配置中的myUserDetailsService需要自己定义,去扩展UserDetailsService
userService

public interface userService extends UserDetailsService {

}

**userServiceImpl **

@Service("myUserDetailsService")
@Transactional
public interface userServiceImpl implements interface {
	@Autowired
	private UserDao userDao;
	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		UserInfo userInfo = null;
		try {
			userInfo = userDao.findByUsername(username) ;
		} catch (Exception e) {
			e.printStackTrace();
		}
		//security提供的user对象,三个参数分别是 账号、密码、权限
		User user = new User(userInfo.getUsername(), userInfo.getPassword(),null );
		return user ;
	}

}

userDao

public class UserDao {
	/**
	 *返回的对象和数据库表对应,为了和security提供的user对象区分,叫UserUnfo
	 */
	@Select("select * from users where username=#{username}")
	public UserInfo findByUsername(String username) throws Exception;
}

例子1

创建一个web工程
pom.xml

		<dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>4.1.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>4.1.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
         xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
        http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-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>

    <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>

spring-security.xml

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

    <!--配置不过滤的资源(静态资源、登录相关)-->
    <security:http security="none" pattern="/login.jsp"/>

    <security:http auto-config="true" use-expressions="true">
        <!--
        auto-config =true时,会配置十个默认过滤器
        use-expressions:
                声明为true,那么在access属性要用access="hasRole(‘ROLE_USER‘)"
                声明为false(默认),那么access直接就是access="ROLE_USER"
        -->
        <!--
            intercept-url 定义过滤规则
            pattern 表示对哪些URL进行权限控制
            access 表示在请求对赢得URL需要什么权限
        -->
        <security:intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"/>
        <!--没有权限错误页面-->
        <security:access-denied-handler error-page="/noauthority.jsp"/>
        <!--CSRF跨服务器的request、forward请求访问,默认开启-->
        <security:csrf/>
    </security:http>

    <!--
         基于内存的用户认证 InMemoryUserDetailsManager
    -->
    <security:authentication-manager>
        <security:authentication-provider>
            <security:user-service>
                <security:user name="root1" password="123456" authorities="ROLE_USER, ROLE_ADMIN"/>
                <security:user name="root2" password="123456" authorities="ROLE_USER"/>
            </security:user-service>
        </security:authentication-provider>
    </security:authentication-manager>
</beans>

使用root1登录,跳转到index.jsp
使用root2登录,跳转到noauthority.jsp

例子2,从数据库查询用户(非自定义数据库)

pom.xml增加数据库依赖

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.46</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.8.RELEASE</version>
        </dependency>

spring-security.xml认证配置修改

    <security:authentication-manager>
        <security:authentication-provider>
            <security:jdbc-user-service data-source-ref="dataSource"/>
        </security:authentication-provider>
    </security:authentication-manager>

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&amp;characterEncoding=UTF8"/>
        <property name="username" value="root"/>
        <property name="password" value="123456"/>
    </bean>

创建表

#用户表
create table users(
    username VARCHAR(50) not null primary key,
    password VARCHAR(50) not null,
    enabled boolean not null
);
#权限表
create table authorities (
    username VARCHAR(50) not null,
    authority VARCHAR(50) not null,
    constraint fk_authorities_users foreign key(username) references users(username)
);
#权限表username,authority两个字段创建唯一索引(可以不用)
create unique index ix_auth_username on authorities (username,authority);


insert into users(username,password,enabled) values('admin','admin',true);
insert into users(username,password,enabled) values('user','user',true);

insert into authorities(username,authority) values('admin','ROLE_ADMIN');
insert into authorities(username,authority) values('admin','ROLE_USER');
insert into authorities(username,authority) values('user','ROLE_USER');

security.xml 配置属性部分介绍

Spring EL表达式

表达式描述
hasRole([role])当前用户是否拥有指定角色。
hasAnyRole([role1,role2])多个角色是一个以逗号进行分隔的字符串。如果当前用户拥有指定角色中的任意一个则返回true。
hasAuthority([auth])等同于hasRole
hasAnyAuthority([auth1,auth2])等同于hasAnyRole
Principle代表当前用户的principle对象
authentication直接从SecurityContext获取的当前Authentication对象
permitAll总是返回true,表示允许所有的
denyAll总是返回false,表示拒绝所有的
isAnonymous()当前用户是否是一个匿名用户
isRememberMe()表示当前用户是否是通过Remember-Me自动登录的
isAuthenticated()表示当前用户是否已经登录认证成功了。
isFullyAuthenticated()如果当前用户既不是一个匿名用户,同时又不是通过Remember-Me自动登录的,则返回true。
	<!-- 指定login.jsp安全性为none-->
   <security:http security="none" pattern="/login.jsp" />

   <security:http auto-config="true">

      <security:form-login
      	 <!-- 指定自定义登录页 -->
      	 login-page="/login.jsp"
		<!-- 指定提action,默认为login-->
         login-processing-url="/login.do" 
		 <!-- 指定登陆成功后跳转页 -->
         default-target-url="/success.jsp"
         <!--登录失败跳转页,默认会返回登录页,要配置成未登录也可以访问-->
         authentication-failure-url="/login_failure.jsp"
         <!-- 认证成功处理 -->
         authentication-success-handler-ref ="authSuccess"
         <!-- 认证失败处理,配置后authentication-failure-url属性将不再发生作用 -->
        authentication-failure-handler-ref="authFailure"
         <!-- 指定用户名参数,默认为username -->
         username-parameter="username"
		 <!-- 指定密码,默认为password -->
         password-parameter="password" />
		 <!-- 为所有请求配置权限 -->
      <security:intercept-url pattern="/**" access="ROLE_USER" />

   </security:http>
      
    <!-- 认证成功后的处理类 -->
    <bean id="authSuccess" class="com.xxx.AuthenticationSuccessHandlerImpl"/>
        <!-- 认证成功后的处理类 -->
    <bean id="authFailure" class="com.xxx.AuthenticationFailureHandlerImpl"/>
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {

    @Override
    public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {

    }
}
public class AuthenticationFailureHandlerImpl implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
        
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值