spring-security框架

Posted 黑面书生

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring-security框架相关的知识,希望对你有一定的参考价值。

1 第一步

搭建一个基于maven的web工程

2 第二步

在web.xml配置文件中写上如下代码

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <filter>
    <!--
      DelegatingFilterProxy用于整合第三方框架
      整合Spring Security时过滤器的名称必须为springSecurityFilterChain,
	  否则会抛出NoSuchBeanDefinitionException异常
    -->
    <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>
  <servlet>
    <servlet-name>springmvc</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 指定加载的配置文件 ,通过参数contextConfigLocation加载 -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-security.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>springmvc</servlet-name>
    <url-pattern>*.do</url-pattern>
  </servlet-mapping>
</web-app>

第三步:建立Spring-security的配置文件

<?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:context="http://www.springframework.org/schema/context"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       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/mvc
						http://www.springframework.org/schema/mvc/spring-mvc.xsd
						http://code.alibabatech.com/schema/dubbo
						http://code.alibabatech.com/schema/dubbo/dubbo.xsd
						http://www.springframework.org/schema/context
						http://www.springframework.org/schema/context/spring-context.xsd
                     http://www.springframework.org/schema/security
                     http://www.springframework.org/schema/security/spring-security.xsd">

    <!--配置哪些资源匿名可以访问(不登录也可以访问)-->
    <!--<security:http security="none" pattern="/pages/a.html"></security:http>
    <security:http security="none" pattern="/pages/b.html"></security:http>-->
    <!--<security:http security="none" pattern="/pages/**"></security:http>-->
    <security:http security="none" pattern="/login.html"></security:http>
    <!--
        auto-config:自动配置,如果设置为true,表示自动应用一些默认配置,比如框架会提供一个默认的登录页面
        use-expressions:是否使用spring security提供的表达式来描述权限
    -->
    <security:http auto-config="true" use-expressions="true">
        <!--配置拦截规则,/** 表示拦截所有请求-->
        <!--
            pattern:描述拦截规则
            asscess:指定所需的访问角色或者访问权限
        -->
        <!--只要认证通过就可以访问-->
        <security:intercept-url pattern="/pages/a.html"  access="isAuthenticated()" />

        <!--拥有add权限就可以访问b.html页面-->
        <security:intercept-url pattern="/pages/b.html"  access="hasAuthority(‘add‘)" />

        <!--拥有ROLE_ADMIN角色就可以访问c.html页面-->
        <security:intercept-url pattern="/pages/c.html"  access="hasRole(‘ROLE_ADMIN‘)" />

        <!--拥有ROLE_ADMIN角色就可以访问d.html页面,
            注意:此处虽然写的是ADMIN角色,框架会自动加上前缀ROLE_-->
        <security:intercept-url pattern="/pages/d.html"  access="hasRole(‘ADMIN‘)" />
        <security:intercept-url pattern="/**" access="hasRole(‘ROLE_ADMIN‘)"></security:intercept-url>

        <!--如果我们要使用自己指定的页面作为登录页面,必须配置登录表单.页面提交的登录表单请求是由框架负责处理-->
        <!--
            login-page:指定登录页面访问URL
        -->
        <security:form-login
                login-page="/login.html"
                username-parameter="username"
                password-parameter="password"
                login-processing-url="/login.do"
                default-target-url="/index.html"
                authentication-failure-url="/login.html"></security:form-login>

        <!--
          csrf:对应CsrfFilter过滤器
          disabled:是否启用CsrfFilter过滤器,如果使用自定义登录页面需要关闭此项,否则登录操作会被禁用(403)
        -->
        <security:csrf disabled="true"></security:csrf>

        <!--
          logout:退出登录
          logout-url:退出登录操作对应的请求路径
          logout-success-url:退出登录后的跳转页面
        -->
        <security:logout logout-url="/logout.do"
                         logout-success-url="/login.html" invalidate-session="true"/>

    </security:http>

    <!--配置认证管理器-->
    <security:authentication-manager>
        <!--配置认证提供者-->
        <security:authentication-provider user-service-ref="userService2">
            <!--
                    配置一个具体的用户,后期需要从数据库查询用户
            <security:user-service>
                <security:user name="admin" password="{noop}1234" authorities="ROLE_ADMIN"/>
            </security:user-service>
            -->
            <!--指定度密码进行加密的对象-->
            <security:password-encoder ref="passwordEncoder"></security:password-encoder>
        </security:authentication-provider>
    </security:authentication-manager>

    <bean id="userService" class="com.itheima.service.SpringSecurityUserService"></bean>
    <bean id="userService2" class="com.itheima.service.SpringSecurityUserService2"></bean>
    <!--配置密码加密对象-->
    <bean id="passwordEncoder"
          class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />

    <!--开启spring注解使用-->
    <context:annotation-config></context:annotation-config>

    <mvc:annotation-driven></mvc:annotation-driven>
    <context:component-scan base-package="com.itheima.controller"></context:component-scan>

    <!--开启注解方式权限控制-->
    <security:global-method-security pre-post-annotations="enabled" />
</beans>

4 关于第三步配置文件的讲解

4-1 配置拦截

<security:http auto-config="true" use-expressions="true">
        <security:intercept-url pattern="/**" access="hasRole(‘ROLE_ADMIN‘)"></security:intercept-url>
    </security:http>
  • auto-config 自动配置,如果设置为true,表示自动应用一些默认配置,比如框架会提供一个默认的登录页面,会帮我们提供一个Spring生成的Controller
  • use-expressions:是否使用spring security提供的表达式来描述权限
  • pattern:描述拦截规则
  • asscess:指定所需的访问角色或者访问权限

4-2 配置认证管理器

<security:authentication-manager>
        <!--配置认证提供者-->
        <security:authentication-provider>
            <security:user-service >
                <security:user name="admin" password="{noop}1234" authorities="ROLE_ADMIN"></security:user>
            </security:user-service>
        </security:authentication-provider>
    </security:authentication-manager>

这段代码表示写死一个用户,其中,{noop}表示密码使用明文来登录,不加密。

4-3 配置可匿名访问,不用登录就可以访问

    <security:http security="none" pattern="/pages/a.html"></security:http>
    <security:http security="none" pattern="/pages/**"></security:http>

4-4 使用指定的登录页面

第一步对登录页面放行,不拦截

<security:http security="none" pattern="login.html"></security:http>

第二步:定义表单登录信息

 <security:form-login login-page="/login.html"
                             username-parameter="username"
                             password-parameter="password"
                             login-processing-url="/login.do"
                             default-target-url="/index.html"
                             authentication-failure-url="/login.html"
        ></security:form-login>

第3步,关闭csrf过滤器

<security:csrf disabled="true"></security:csrf>

5 从数据库查询用户信息

5-1

编写一个类SpringSecurityUserService,实现UserDetailsService接口并重写方法,框架会自动帮我们调用这个方法,username就是前端登录的用户名,但是框架怎样就能自动帮我们调用一个我们自己写的方法呢,所以,我们需要配置一下

public class SpringSecurityUserService implements UserDetailsService {

    @java.lang.Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //这个方法框架帮我们调用,username是登录传进来的,但我们要配置这个类。
        System.out.println("输入的用户名是"+username);
        return null;
    }
}

5-2 在配置文件中配置刚才5-1写的类

<security:authentication-manager>
        <!--配置认证提供者-->
        <security:authentication-provider user-service-ref="userService">
            <!--<security:user-service >-->
                <!--<security:user name="admin" password="{noop}1234" authorities="ROLE_ADMIN"></security:user>-->
            <!--</security:user-service>-->
        </security:authentication-provider>
    </security:authentication-manager>

    <bean id="userService" class="com.itheima.service.SpringSecurityUserService"></bean>

2个地方,第一个,需要配置<bean id="userService" class="com.itheima.service.SpringSecurityUserService"></bean>,
第二个,需要引用这个对象。

5-3 模拟从数据库查询

package com.itheima.service;

import com.itheima.pojo.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SpringSecurityUserService implements UserDetailsService {
    //模拟数据库中的用户数据
    public  static Map<String, User> map = new HashMap<>();
    static {
        com.itheima.pojo.User user1 = new com.itheima.pojo.User();
        user1.setUsername("admin");
        user1.setPassword("admin");//明文密码(没有加密)

        com.itheima.pojo.User user2 = new com.itheima.pojo.User();
        user2.setUsername("xiaoming");
        user2.setPassword("1234");

        map.put(user1.getUsername(),user1);
        map.put(user2.getUsername(),user2);
    }

    //根据用户名查询用户信息
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("用户输入的用户名为:" + username);
        //根据用户名查询数据库获得用户信息(包含数据库中存储的密码信息)
        User user = map.get(username);//模拟查询根据用户名查询数据库
        if(user == null){
            //用户名不存在
            return null;
        }else{
            //将用户信息返回给框架
            //框架会进行密码比对(页面提交的密码和数据库中查询的密码进行比对)
            List<GrantedAuthority> list = new ArrayList<>();
            //为当前登录用户授权,后期需要改为从数据库查询当前用户对应的权限
            list.add(new SimpleGrantedAuthority("permission_A"));//授权
            list.add(new SimpleGrantedAuthority("permission_B"));

            if(username.equals("admin")){
                list.add(new SimpleGrantedAuthority("ROLE_ADMIN"));//授予角色
            }
            org.springframework.security.core.userdetails.User securityUser = new org.springframework.security.core.userdetails.User(username,"{noop}"+user.getPassword(),list);
            return securityUser;
        }
    }
}

5-4 不同权限控制

  • isAuthenticated()只要认证通过就可以放访问
  • hasAuthority()只要拥有某个角色就可以通过
  • hasRole()有某个角色才可以通过

5-5 通过注解控制权限

第一步:

在Spring-security.xml中配置组建扫描,扫描controller

<mvc:annotation-driven></mvc:annotation-driven>
<context:component-scan base-package="com.itheima.controller"></context:component-scan>

第二步

开启注解方式权限控制

<!--开启注解方式权限控制-->
<security:global-method-security pre-post-annotations="enabled" />

第三步

创建controller类并使用权限注解

package com.itheima.controller;
?
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
?
@RestController
@RequestMapping("/hello")
public class HelloController {
    @RequestMapping("/add")
    @PreAuthorize("hasAuthority(‘add‘)")//表示用户必须拥有add权限才能调用当前方法
    public String add(){
        System.out.println("add...");
        return "success";
    }
?
    @RequestMapping("/delete")
    @PreAuthorize("hasRole(‘ROLE_ADMIN‘)")//表示用户必须拥有ROLE_ADMIN角色才能调用当前方法
    public String delete(){
        System.out.println("delete...");
        return "success";
    }
}

6 退出登录

<security:logout logout-url="/logout.do" 
                 logout-success-url="/login.html" invalidate-session="true"/>

7 完成版的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:context="http://www.springframework.org/schema/context"
       xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       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/mvc
						http://www.springframework.org/schema/mvc/spring-mvc.xsd
						http://code.alibabatech.com/schema/dubbo
						http://code.alibabatech.com/schema/dubbo/dubbo.xsd
						http://www.springframework.org/schema/context
						http://www.springframework.org/schema/context/spring-context.xsd
                     http://www.springframework.org/schema/security
                     http://www.springframework.org/schema/security/spring-security.xsd">


    <security:http security="none" pattern="/pages/**"></security:http>
    <security:http security="none" pattern="login.html"></security:http>

    <security:http auto-config="true" use-expressions="true">
        <security:intercept-url pattern="/**" access="hasRole(‘ROLE_ADMIN‘)"></security:intercept-url>

        <!--配置登录表单-->
        <!--<security:form-login login-page="/login.html"-->
                             <!--username-parameter="username"-->
                             <!--password-parameter="password"-->
                             <!--login-processing-url="/login.do"-->
                             <!--default-target-url="/index.html"-->
                             <!--authentication-failure-url="/login.html"-->
        <!--&gt;</security:form-login>-->
        <!--<security:csrf disabled="true"></security:csrf>-->

        <security:logout logout-url="/logout.do"
                         logout-success-url="/login.html" invalidate-session="true"/>
    </security:http>

    <security:authentication-manager>
        <!--配置认证提供者-->
        <security:authentication-provider user-service-ref="userService">
            <!--<security:user-service >-->
                <!--<security:user name="admin" password="{noop}1234" authorities="ROLE_ADMIN"></security:user>-->
            <!--</security:user-service>-->
            <!--指定对密码进行加密的对象-->
            <security:password-encoder ref="passwordEncoder"></security:password-encoder>
        </security:authentication-provider>
    </security:authentication-manager>

    <bean id="userService" class="com.itheima.service.SpringSecurityUserService"></bean>


    <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean>

    <!--开启spring注解使用-->
    <context:annotation-config></context:annotation-config>

    <mvc:annotation-driven></mvc:annotation-driven>
    <context:component-scan base-package="com.itheima.controller"></context:component-scan>
    <security:global-method-security pre-post-annotations="enabled" />
</beans>

以上是关于spring-security框架的主要内容,如果未能解决你的问题,请参考以下文章

Spring-Security权限管理框架——根据角色权限登录

安全框架配置文件(spring-security.xml)

spring-security

web应用安全框架选型:Spring Security与Apache Shiro

spring-security的细节

Spring-Security