Spring的扩展 ---- SpringSecurity

72 阅读3分钟

1. 认证和授权概念

认证:系统提供用于识别用户身份的功能。认证的目的是让系统知道是谁。

授权:用户认证认证后,需要进行为用户授权,指定当前用户具有哪些功能。对后台系统进行权限控制,其本质是对用户进行认证和授权。

2. 权限模块模型

表关系如图:

image.png

认证过程:只需要用户表t_user,在用户登录时可以查询用户表进行校验,判断用户输入的用户名和密码是否正确。

授权过程:首先根据用户查询角色,根据角色查询对应的菜单,用户可以看到哪些菜单,根据用户的角色查询对应的权限。

3. 什么是spring security?

3.1 spring-security的简介

由spring提供的安全认证的服务框架。官网:Spring Security

引入对应的pom.xml依赖:

<!--spring安全框架-->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>5.2.6.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>5.2.6.RELEASE</version>
</dependency>

常用的权限框架对比:

1.** spring security**:

Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。
它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
2. Apache的**shiro**框架:
Apache Shiro是一个开源安全框架,提供身份验证、授权、密码学和会话管理。Shiro框架具有直观、易用等特性,同时也能提供健壮的安全性。

3.2 spring security的快速入门

index.jsp

<h1>hello Spring Security...</h1>

配置web.xml

<!--配置SpringSecurity整合框架-->
<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>
<!--加载spring-security配置文件-->
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-security.xml</param-value>

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: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/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
                           http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">

    <!--auto-config为true表示自动应用配置
        use-expressions 是否使用表达式来描述权限
    -->
    <security:http auto-config="true" use-expressions="true">
        <!--配置拦截规则pattern:拦截规则 access:指定访问角色或权限 -->
        <security:intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"></security:intercept-url>
    </security:http>
    
    <!--配置认证管理器-->
    <security:authentication-manager>
        <!--配置认证提供者-->
        <security:authentication-provider>
            <security:user-service>
                <security:user name="小梦" password="{noop}123" authorities="ROLE_ADMIN" />
            </security:user-service>
        </security:authentication-provider>
    </security:authentication-manager>

</beans>

测试效果

image.png

跳转spring security自定义的登录页面:

image.png

image.png

image.png

4. 改进Spring Security入门案例

4.1. 配置可匿名(不登陆)访问的资源

<!--配置资源可以匿名访问-->
<!--<security:http security="none" pattern="/pages/user.jsp"></security:http>
<security:http security="none" pattern="/pages/role.jsp"></security:http>-->
<security:http security="none" pattern="/pages/**"></security:http>

image.png

4.2. 使用指定的登录页面

<!--配置自定义的登录页面-->
<security:form-login
        login-page="/login.jsp"
        username-parameter="username"
        password-parameter="password"
        login-processing-url="/login.do"
        default-target-url="/index.jsp"
        authentication-failure-url="/login.jsp"
></security:form-login>

<!--关闭CsrfFilter过滤器-->
<security:csrf disabled="true"></security:csrf>

image.png

image.png

4.3 从数据库中查询用户信息

按照spring security框架的要求提供一个实现UserDetailsService接口的实现类,并按照框架要求进行配置。自动调用实现类中的方法并自动校验。

public class UserService implements UserDetailsService {

    public static Map<String, User> map= new HashMap<>();
    static {
        User user1 = new User();
        user1.setUsername("xiaomeng");
        user1.setPassword("123");

        User user2 = new User();
        user2.setUsername("xinru");
        user2.setPassword("123");

        map.put(user1.getUsername(), user1);
        map.put(user2.getUsername(), user2);
    }
    //根据用户名查询数据库的用户信息
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("========username======>"+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("xiaomeng")){
                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;
        }

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

<!--配置UserService实现类交给spring容器管理权-->
<bean id="userService" class="cn.hfnu.service.UserService"></bean>

image.png

image.png

4.4 对密码进行加密控制

一般情况下用户的密码进行加密后保存到数据库。常见的加密方式: 3DES、AES、DES:使用对称加密算法。MD5、SHA1:使用单向HASH算法建立彩虹表进行查表破解。bcrypt;将salt随机并混入最终加密后后的密码,验证时无需单独提供之前的salt。

<!--指定对密码进行加密对象-->
<security:password-encoder ref="passwordEncoder"></security:password-encoder>
<!--配置密码加密对象-->
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>

<!--开启spring注解-->
<context:annotation-config></context:annotation-config>
public class UserService2 implements UserDetailsService {

    @Autowired
    private BCryptPasswordEncoder passwordEncoder;

    public Map<String, User> map= new HashMap<>();

    public void initUserData(){
        User user1 = new User();
        user1.setUsername("xiaomeng");
        user1.setPassword(passwordEncoder.encode("abc"));  //密码加密

        User user2 = new User();
        user2.setUsername("xinru");
        user2.setPassword(passwordEncoder.encode("123"));

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

    //根据用户名查询数据库的用户信息
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        initUserData();
        System.out.println("========username======>"+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("xiaomeng")){
                list.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
            }

            org.springframework.security.core.userdetails.User securityUser = new org.springframework.security.core.userdetails.User(username, user.getPassword(),list);
            return securityUser;
        }

    }
}

image.png

4.5 配置多种校验规则

<!--只要认证通过就可以访问-->
<security:intercept-url pattern="/pages/user.jsp" access="isAuthenticated()"/>

<!--拥有add权限就可以访问-->
<security:intercept-url pattern="/pages/role.jsp" access="hasAuthority('add')"/>

<!--拥有ROLE_ADMIN角色就可以访问-->
<security:intercept-url pattern="/pages/service1.jsp" access="hasRole('ROLE_ADMIN')"/>

<!--拥有ROLE_ADMIN角色就可以访问-->
<security:intercept-url pattern="/pages/service2.jsp" access="hasRole('ADMIN')"/>

image.png

image.png

image.png

4.6 注解方式进行权限控制

<!--配置组件扫描-->
<mvc:annotation-driven></mvc:annotation-driven>
<context:component-scan base-package="cn.hfnu.controller"></context:component-scan>

<!--开启注解方式的权限控制-->
<security:global-method-security pre-post-annotations="enabled"/>
@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/add")
    @PreAuthorize("hasAuthority('add')")  //调用该方法用户必须拥有add权限
    public String add(){
        return "success";
    }

    @RequestMapping("/delete")
    @PreAuthorize("hasRole('ROLE_ADMIN')")   //调用该方法用户必须拥有ROLE_ADMIN角色
    public String delete(){

        return "success";
    }
}

image.png

image.png

4.7 退出登录

<!--配置退出登录-->
<security:logout logout-url="/logout.do" logout-success-url="/login.jsp" invalidate-session="true"/>

image.png

image.png

4.8 小结

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: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/context http://www.springframework.org/schema/context/spring-context.xsd
                           http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
                           http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd">

    <!--配置资源可以匿名访问-->
    <!--<security:http security="none" pattern="/pages/user.jsp"></security:http>
    <security:http security="none" pattern="/pages/role.jsp"></security:http>-->
    <security:http security="none" pattern="/login.jsp"></security:http>

    <!--auto-config为true表示自动应用配置
        use-expressions 是否使用表达式来描述权限
    -->
    <security:http auto-config="true" use-expressions="true">
        <!--只要认证通过就可以访问-->
        <security:intercept-url pattern="/pages/user.jsp" access="isAuthenticated()"/>

        <!--拥有add权限就可以访问-->
        <security:intercept-url pattern="/pages/role.jsp" access="hasAuthority('add')"/>

        <!--拥有ROLE_ADMIN角色就可以访问-->
        <security:intercept-url pattern="/pages/service1.jsp" access="hasRole('ROLE_ADMIN')"/>

        <!--拥有ROLE_ADMIN角色就可以访问-->
        <security:intercept-url pattern="/pages/service2.jsp" access="hasRole('ADMIN')"/>

        <!--配置拦截规则pattern:拦截规则 access:指定访问角色或权限 -->
        <security:intercept-url pattern="/**" access="hasRole('ROLE_ADMIN')"></security:intercept-url>
        <!--配置自定义的登录页面-->
        <security:form-login
                login-page="/login.jsp"
                username-parameter="username"
                password-parameter="password"
                login-processing-url="/login.do"
                default-target-url="/index.jsp"
                authentication-failure-url="/login.jsp"
        ></security:form-login>

        <!--关闭CsrfFilter过滤器-->
        <security:csrf disabled="true"></security:csrf>

        <!--配置退出登录-->
        <security:logout logout-url="/logout.do" logout-success-url="/login.jsp" invalidate-session="true"/>

    </security:http>

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

        </security:authentication-provider>
    </security:authentication-manager>

    <!--配置UserService实现类交给spring容器管理权-->
    <bean id="userService" class="cn.hfnu.service.UserService"></bean>
    <bean id="userService2" class="cn.hfnu.service.UserService2"></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="cn.hfnu.controller"></context:component-scan>

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

</beans>

以上内容对SpringSecurity的学习记录,后期我从数据库中查询具体的用户并赋予角色和权限。如果你认真看完,对SpringSecurity框架进行认证和授权有了初步的认识。你如果进来”在看“,就点击”在看“,点个赞,你的赞是我学习的最大动力。坚持一件事情不容易,点个”在看“,点个”赞“,你会变好看,一次点赞,一次好运。