您的当前位置:首页正文

安全框架Spring Security(认证和授权)

2024-12-01 来源:个人技术集锦

Spring Security

今天从以下几个内容介绍:

Spring Security简介
  • Spring Security是 Spring提供的安全认证服务的框架。 使用Spring Security可以帮助我们来简化认证和授权的过程。
  • 官网:
Spring Security的Maven依赖

如果想使用最新版本的直接搜索:maven Spring Security

<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-web</artifactId>
	<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework.security</groupId>
	<artifactId>spring-security-config</artifactId>
	<version>5.0.5.RELEASE</version>
</dependency>
Spring Security使用
  1. 导入依赖(上面已经写过了)

  2. 创建一个Web项目,在web.xml文件中配置一个过滤器:

</filter>

    <!--
      DelegatingFilterProxy用于整合第三方框架
      整合Spring Security时过滤器的名称必须为springSecurityFilterChain,
   否则会抛出NoSuchBeanDefinitionException异常
    -->
  <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配置文件,配置下面的内容:
<?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/mvc
						http://www.springframework.org/schema/mvc/spring-mvc.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="/css/**"/>
    <security:http security="none" pattern="/img/**"/>
    <security:http security="none" pattern="/js/**"/>
    <security:http security="none" pattern="/plugins/**"/>


    <security:http auto-config="true" use-expressions="true">
        <!--配置在页面中的iframe标签默认不拦截-->
        <security:headers>
            <security:frame-options policy="SAMEORIGIN"/>
        </security:headers>

        <!--配置当访问/pages目录下的所有文件时,需要登录成功才能访问-->
        <security:intercept-url pattern="/pages/**" access="isAuthenticated()"/>

        <!--配置自定义的登录页面,如果不自定义,框架会有一个不太美观的登录页面
        login-page:自定义登录页面
        login-processing-url:定义的提交登录请求
        authentication-failure-url:登录失败返回的页面
        -->
        <security:form-login login-page="/login.html"
                             username-parameter="username"
                             password-parameter="password"
                             login-processing-url="/login"
                             default-target-url="/pages/main.html"
                             always-use-default-target="true"
                             authentication-failure-url="/login.html"/>

        <!--
        csrf:对应CsrfFilter过滤器
        disabled:是否启用CsrfFilter过滤器,如果使用自定义登录页面需要关闭此项,
        否则登录操作会被禁用(403)
        -->
        <security:csrf disabled="true"/>
        <!--配置登出页面 invalidate-session指定清除登录用户的session信息-->
        <security:logout logout-url="/logout"
                         logout-success-url="/hello.html"
                         invalidate-session="true"/>

    </security:http>

    <!--配置密码加密对象-->
    <bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
    <!--认证管理器,用于处理认证操作-->
    <security:authentication-manager>
    <!--认证提供者,执行具体的认证逻辑springSecurityService这是我们自定义的类用来实现UserDetailsService接口 -->
        <security:authentication-provider user-service-ref="springSecurityService">
    <!--指定密码加密策略-->
            <security:password-encoder ref="passwordEncoder"/>
        </security:authentication-provider>
    </security:authentication-manager>

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


</beans>
         最后记得在springmvc的配置文件中导入这个文件
<import resource="spring-security.xml"/>
  1. 自己定义的类实现UserDetailsService,重写loadUserByUsername方法,返回一个User对象,将用户拥有的权限封装到这个对象中,最后在控制层中添加一个注解来让框架生效。
package com.ysdn.sercurity;

import com.alibaba.dubbo.config.annotation.Reference;
import com.ysdn.bean.Permission;
import com.ysdn.bean.Role;
import com.ysdn.bean.User;
import com.ysdn.service.UserService;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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 org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

@Service
public class SpringSecurityService implements UserDetailsService {

    @Reference(url = "dubbo://localhost:20887")
    private UserService userService;

    @Override
    //username参数是登录后框架封装传过来的
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user =  userService.findByName(username);
        if (user == null) {
            return null;
        }
        List<GrantedAuthority> list = new ArrayList<>();
        Set<Role> roles = user.getRoles();
        for (Role role : roles) {
            list.add(new SimpleGrantedAuthority(role.getKeyword()));
            Set<Permission> permissions = role.getPermissions();
            for (Permission permission : permissions) {
                list.add(new SimpleGrantedAuthority(permission.getKeyword()));
            }
        }
        return new org.springframework.security.core.userdetails.User(username, user.getPassword(), list);

    }
}

控制层代码:

//这就是Spring Security框架提供的注解
 @PreAuthorize("hasAuthority('CHECKITEM_DELETE')")
    @RequestMapping("deleteCheckItem")
    public Result deleteCheckItem(Integer id) {
        try {
            if (checkItemService.findCheckGroupId(id)) {
                return new Result(false, "已经注册到检查组中,不可删除");
            } else checkItemService.deleteCheckItem(id);
        } catch (Exception e) {
            e.printStackTrace();
            return new Result(false, MessageConstant.DELETE_CHECKITEM_FAIL);
        }
        return new Result(true, MessageConstant.DELETE_CHECKITEM_SUCCESS);
    }

在页面发送请求的地方弹出提示消息:

				//提示权限不足
                showAuthorityMessage(r) {
                    if (r == 'Error: Request failed with status code 403') {
                        this.$message.error("无权进行此操作");
                        return;
                    } else {
                        this.$message.error("未知错误");
                        return;
                    }
                },
                // 删除
                handleDelete(row) {
                    this.$confirm("您是否要删除这个检查项", "提示", {type: 'warning'}).then(() => {
                        axios.post("/checkitem/deleteCheckItem?id=" + row.id).then((result) => {
                            if (result.data.flag) {
                                this.$message({
                                    type: "success",
                                    message: result.data.message
                                });
                            } else {
                                this.$message.error(result.data.message);
                            }
                            this.findPage();
                        }).catch((r) => {
                        	//在这里调用上面的方法
                            this.showAuthorityMessage(r);
                        });
                    });
                }
  1. 测试,查看结果。
  2. 显示用户名
  • 向后台发出异步请求获取当前登录用户的用户名,显示到页面上。
//利用Vue的钩子函数,在每次初始化页面的时候显示用户名
created() {
            axios.post("/user/getUsername").then((result) => {
                if (result.data.flag) {
                	//username用来显示在页面上
                    this.username = result.data.data;
                }
            });
        }
  • 后台代码
package com.ysdn.controller;

import com.ysdn.entity.MessageConstant;
import com.ysdn.entity.Result;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/user")
public class UserController {

    @RequestMapping("/getUsername")
    public Result getUsername() {
        //这是框架的提供的类SecurityContextHolder,里面存储着登录用户的信息拥有的权限
        User principal = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String username = principal.getUsername();
        if (username != null) {
            return new Result(true, MessageConstant.GET_USERNAME_SUCCESS, username);
        }

        return new Result(false, MessageConstant.GET_USERNAME_FAIL);
    }
}

  1. 登出
  • Spring Security框架会自动处理登出,可以不用配置,这是中文官网的说明。
  • 只需要在页面配置一个请求路径就可以。
<span style="display:block;">
   <a href="/logout">退出</a>
 </span>
  • 也可以自己配置登出和相关的操作,如下的配置登出之后就会跳到hello.html页面。
<!--配置登出相关的信息 invalidate-session指定清除登录用户的session信息-->
        <security:logout logout-url="/logout"
                         logout-success-url="/hello.html"
                         invalidate-session="true"/>

以上就是全部内容了,如果有不恰当的地方,欢迎指正。

显示全文