网站建设营销外包公司哪家好,网站建设哪家好公司,石家庄新闻头条新闻最新今天,建设网站如何收费前面我们已经完成了传智健康后台管理系统的部分功能#xff0c;例如检查项管理、检查组管理、套餐管理、预 约设置等。接下来我们需要思考2个问题#xff1a; 问题1#xff1a;在生产环境下我们如果不登录后台系统就可以完成这些功能操作吗#xff1f; 答案显然是否定的例如检查项管理、检查组管理、套餐管理、预 约设置等。接下来我们需要思考2个问题 问题1在生产环境下我们如果不登录后台系统就可以完成这些功能操作吗 答案显然是否定的要操作这些功能必须首先登录到系统才可以。 问题2是不是所有用户只要登录成功就都可以操作所有功能呢 答案是否定的并不是所有的用户都可以操作这些功能。不同的用户可能拥有不同的权限这就需要进 行授权了。 认证系统提供的用于识别用户身份的功能通常提供用户名和密码进行登录其实就是在进行认证认 证的目的是让系统知道你是谁。 授权用户认证成功后需要为用户授权其实就是指定当前用户可以操作哪些功能。 本章节就是要对后台系统进行权限控制其本质就是对用户进行认证和授权。 3.2 权限模块数据模型 前面已经分析了认证和授权的概念要实现最终的权限控制需要有一套表结构支撑 用户表t_user、权限表t_permission、角色表t_role、菜单表t_menu、用户角色关系表t_user_role、角 色权限关系表t_role_permission、角色菜单关系表t_role_menu。 表之间关系如下图 通过上图可以看到权限模块共涉及到7张表。在这7张表中角色表起到了至关重要的作用其处于核心位置因为用户、权限、菜单都和角色是多对多关系。
接下来我们可以分析一下在认证和授权过程中分别会使用到哪些表
认证过程只需要用户表就可以了在用户登录时可以查询用户表t_user进行校验判断用户输入的用户名和密码是否正确。
授权过程用户必须完成认证之后才可以进行授权首先可以根据用户查询其角色再根据角色查询对应的菜单这样就确定了用户能够看到哪些菜单。然后再根据用户的角色查询对应的权限这样就确定了用户拥有哪些权限。所以授权过程会用到上面7张表。
3.3 Spring Security简介
Spring Security是 Spring提供的安全认证服务的框架。 使用Spring Security可以帮助我们来简化认证和授权的过程。官网https://spring.io/projects/spring-security 对应的maven坐标
dependencygroupIdorg.springframework.security/groupIdartifactIdspring-security-web/artifactIdversion5.0.5.RELEASE/version
/dependency
dependencygroupIdorg.springframework.security/groupIdartifactIdspring-security-config/artifactIdversion5.0.5.RELEASE/version
/dependency常用的权限框架除了Spring Security还有Apache的shiro框架。
3.4 Spring Security入门案例
3.4.1 工程搭建
创建maven工程打包方式为war为了方便起见我们可以让入门案例工程依赖health_interface这样相关的依赖都继承过来了。
pom.xml
?xml version1.0 encodingUTF-8?
project xmlnshttp://maven.apache.org/POM/4.0.0xmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexsi:schemaLocationhttp://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsdmodelVersion4.0.0/modelVersion
groupIdcom.itheima/groupIdartifactIdspringsecuritydemo/artifactIdversion1.0-SNAPSHOT/versionpackagingwar/packaging
namespringsecuritydemo Maven Webapp/nameurlhttp://www.example.com/url
propertiesproject.build.sourceEncodingUTF-8/project.build.sourceEncodingmaven.compiler.source1.8/maven.compiler.sourcemaven.compiler.target1.8/maven.compiler.target/properties
dependenciesdependencygroupIdcom.itheima/groupIdartifactIdhealth_interface/artifactIdversion1.0-SNAPSHOT/version/dependency/dependenciesbuildpluginsplugingroupIdorg.apache.tomcat.maven/groupIdartifactIdtomcat7-maven-plugin/artifactIdconfiguration!-- 指定端口 --port85/port!-- 请求路径 --path//path/configuration/plugin/plugins/build
/project提供index.html页面内容为hello Spring Security!!
3.4.2 配置web.xml 在web.xml中主要配置SpringMVC的DispatcherServlet和用于整合第三方框架的DelegatingFilterProxy用于整合Spring Security。
!DOCTYPE web-app PUBLIC-//Sun Microsystems, Inc.//DTD Web Application 2.3//ENhttp://java.sun.com/dtd/web-app_2_3.dtd
web-appdisplay-nameArchetype Created Web Application/display-namefilter!--DelegatingFilterProxy用于整合第三方框架整合Spring Security时过滤器的名称必须为springSecurityFilterChain否则会抛出NoSuchBeanDefinitionException异常--filter-namespringSecurityFilterChain/filter-namefilter-classorg.springframework.web.filter.DelegatingFilterProxy/filter-class/filterfilter-mappingfilter-namespringSecurityFilterChain/filter-nameurl-pattern/*/url-pattern/filter-mappingservletservlet-namespringmvc/servlet-nameservlet-classorg.springframework.web.servlet.DispatcherServlet/servlet-class!-- 指定加载的配置文件 通过参数contextConfigLocation加载 --init-paramparam-namecontextConfigLocation/param-nameparam-valueclasspath:spring-security.xml/param-value/init-paramload-on-startup1/load-on-startup/servletservlet-mappingservlet-namespringmvc/servlet-nameurl-pattern*.do/url-pattern/servlet-mapping
/web-app3.4.3 配置spring-security.xml 在spring-security.xml中主要配置Spring Security的拦截规则和认证管理器。
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxmlns:dubbohttp://code.alibabatech.com/schema/dubboxmlns:mvchttp://www.springframework.org/schema/mvcxmlns:securityhttp://www.springframework.org/schema/securityxsi:schemaLocationhttp://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/mvchttp://www.springframework.org/schema/mvc/spring-mvc.xsdhttp://code.alibabatech.com/schema/dubbohttp://code.alibabatech.com/schema/dubbo/dubbo.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/securityhttp://www.springframework.org/schema/security/spring-security.xsd
!--http用于定义相关权限控制auto-config是否自动配置设置为true时框架会提供默认的一些配置例如提供默认的登录页面、登出处理等设置为false时需要显示提供登录表单配置否则会报错use-expressions用于指定intercept-url中的access属性是否使用表达式--security:http auto-configtrue use-expressionstrue!--intercept-url定义一个拦截规则pattern对哪些url进行权限控制access在请求对应的URL时需要什么权限默认配置时它应该是一个以逗号分隔的角色列表请求的用户只需拥有其中的一个角色就能成功访问对应的URL--security:intercept-url pattern/** accesshasRole(ROLE_ADMIN) //security:http
!--authentication-manager认证管理器用于处理认证操作--security:authentication-manager!--authentication-provider认证提供者执行具体的认证逻辑--security:authentication-provider!--user-service用于获取用户信息提供给authentication-provider进行认证--security:user-service!--user定义用户信息可以指定用户名、密码、角色后期可以改为从数据库查询用户信息{noop}表示当前使用的密码为明文--security:user nameadmin password{noop}admin authoritiesROLE_ADMIN/security:user/security:user-service/security:authentication-provider/security:authentication-manager
/beans3.5 对入门案例改进
前面我们已经完成了Spring Security的入门案例通过入门案例我们可以看到Spring Security将我们项目中的所有资源都保护了起来要访问这些资源必须要完成认证而且需要具有ROLE_ADMIN角色。
但是入门案例中的使用方法离我们真实生产环境还差很远还存在如下一些问题
1、项目中我们将所有的资源所有请求URL都保护起来实际环境下往往有一些资源不需要认证也可以访问也就是可以匿名访问。
2、登录页面是由框架生成的而我们的项目往往会使用自己的登录页面。
3、直接将用户名和密码配置在了配置文件中而真实生产环境下的用户名和密码往往保存在数据库中。
4、在配置文件中配置的密码使用明文这非常不安全而真实生产环境下密码需要进行加密。
本章节需要对这些问题进行改进。
3.5.1 配置可匿名访问的资源
第一步在项目中创建pages目录在pages目录中创建a.html和b.html
第二步在spring-security.xml文件中配置指定哪些资源可以匿名访问
!--http用于定义相关权限控制指定哪些资源不需要进行权限校验可以使用通配符
--
security:http securitynone pattern/pages/a.html /
security:http securitynone pattern/paegs/b.html /
security:http securitynone pattern/pages/**/security:http通过上面的配置可以发现pages目录下的文件可以在没有认证的情况下任意访问。
3.5.2 使用指定的登录页面 第一步提供login.html作为项目的登录页面
html
headtitle登录/title
/head
bodyform action/login.do methodpostusernameinput typetext nameusernamebrpasswordinput typepassword namepasswordbrinput typesubmit valuesubmit/form
/body
/html第二步修改spring-security.xml文件指定login.html页面可以匿名访问
security:http securitynone pattern/login.html /
第三步修改spring-security.xml文件加入表单登录信息的配置!--form-login定义表单登录信息
--
security:form-login login-page/login.htmlusername-parameterusernamepassword-parameterpasswordlogin-processing-url/login.dodefault-target-url/index.htmlauthentication-failure-url/login.html/第四步修改spring-security.xml文件关闭CsrfFilter过滤器
!--csrf对应CsrfFilter过滤器disabled是否启用CsrfFilter过滤器如果使用自定义登录页面需要关闭此项否则登录操作会被禁用403
--
security:csrf disabledtrue/security:csrf3.5.3 从数据库查询用户信息 如果我们要从数据库动态查询用户信息就必须按照spring security框架的要求提供一个实现UserDetailsService接口的实现类并按照框架的要求进行配置即可。框架会自动调用实现类中的方法并自动进行密码校验。
实现类代码
package com.itheima.security;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
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 UserService implements UserDetailsService {//模拟数据库中的用户数据public static MapString, com.itheima.pojo.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);}/*** 根据用户名加载用户信息* param username* return* throws UsernameNotFoundException*/public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {System.out.println(username: username);com.itheima.pojo.User userInDb map.get(username);//模拟根据用户名查询数据库if(userInDb null){//根据用户名没有查询到用户return null;}
//模拟数据库中的密码后期需要查询数据库String passwordInDb {noop} userInDb.getPassword();
ListGrantedAuthority list new ArrayList();//授权后期需要改为查询数据库动态获得用户拥有的权限和角色list.add(new SimpleGrantedAuthority(add));list.add(new SimpleGrantedAuthority(delete));list.add(new SimpleGrantedAuthority(ROLE_ADMIN));UserDetails user new User(username,passwordInDb,list);return user;}
}spring-security.xml
!--authentication-manager认证管理器用于处理认证操作
--
security:authentication-manager!--authentication-provider认证提供者执行具体的认证逻辑--security:authentication-provider user-service-refuserService/security:authentication-provider
/security:authentication-manager 本章节我们提供了UserService实现类并且按照框架的要求实现了UserDetailsService接口。在spring配置文件中注册UserService指定其作为认证过程中根据用户名查询用户信息的处理类。当我们进行登录操作时spring security框架会调用UserService的loadUserByUsername方法查询用户信息并根据此方法中提供的密码和用户页面输入的密码进行比对来实现认证操作。
3.5.4 对密码进行加密 前面我们使用的密码都是明文的这是非常不安全的。一般情况下用户的密码需要进行加密后再保存到数据库中。
常见的密码加密方式有
3DES、AES、DES使用对称加密算法可以通过解密来还原出原始密码
MD5、SHA1使用单向HASH算法无法通过计算还原出原始密码但是可以建立彩虹表进行查表破解
bcrypt将salt随机并混入最终加密后的密码验证时也无需单独提供之前的salt从而无需单独处理salt问题
加密后的格式一般为
$2a101010/bTVvqqlH9UiE0ZJZ7N2Me3RIgUCdgMheyTgV0B4cMCSokPa.6oCa 加密后字符串的长度为固定的60位。其中$是分割符无意义2a是bcrypt加密版本号10是cost的值而后的前22位是salt值再然后的字符串就是密码的密文了。
实现步骤
第一步在spring-security.xml文件中指定密码加密对象
!--配置密码加密对象--
bean idpasswordEncoder classorg.springframework.security.crypto.bcrypt.BCryptPasswordEncoder /
!--认证管理器用于处理认证操作--
security:authentication-manager!--认证提供者执行具体的认证逻辑--security:authentication-provider user-service-refuserService!--指定密码加密策略--security:password-encoder refpasswordEncoder //security:authentication-provider
/security:authentication-manager
!--开启spring注解使用--
context:annotation-config/context:annotation-config第二步修改UserService实现类
package com.itheima.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class UserService implements UserDetailsService {Autowiredprivate BCryptPasswordEncoder passwordEncoder;
public MapString, com.itheima.pojo.User map new HashMap();//模拟数据库中的用户数据
public void initData(){com.itheima.pojo.User user1 new com.itheima.pojo.User();user1.setUsername(admin);user1.setPassword(passwordEncoder.encode(admin));
com.itheima.pojo.User user2 new com.itheima.pojo.User();user2.setUsername(xiaoming);user2.setPassword(passwordEncoder.encode(1234));
map.put(user1.getUsername(),user1);map.put(user2.getUsername(),user2);}/*** 根据用户名加载用户信息* param username* return* throws UsernameNotFoundException*/public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {initData();System.out.println(username: username);com.itheima.pojo.User userInDb map.get(username);//模拟根据用户名查询数据库if(userInDb null){//根据用户名没有查询到用户return null;}
String passwordInDb userInDb.getPassword();//模拟数据库中的密码后期需要查询数据库
ListGrantedAuthority list new ArrayList();//授权后期需要改为查询数据库动态获得用户拥有的权限和角色list.add(new SimpleGrantedAuthority(add));list.add(new SimpleGrantedAuthority(delete));list.add(new SimpleGrantedAuthority(ROLE_ADMIN));UserDetails user new User(username,passwordInDb,list);return user;}
}3.5.5 配置多种校验规则 为了测试方便首先在项目中创建a.html、b.html、c.html、d.html几个页面
修改spring-security.xml文件
!--只要认证通过就可以访问--
security:intercept-url pattern/index.jsp accessisAuthenticated() /
security:intercept-url pattern/a.html accessisAuthenticated() /
!--拥有add权限就可以访问b.html页面--
security:intercept-url pattern/b.html accesshasAuthority(add) /
!--拥有ROLE_ADMIN角色就可以访问c.html页面--
security:intercept-url pattern/c.html accesshasRole(ROLE_ADMIN) /
!--拥有ROLE_ADMIN角色就可以访问d.html页面注意此处虽然写的是ADMIN角色框架会自动加上前缀ROLE_--
security:intercept-url pattern/d.html accesshasRole(ADMIN) /3.5.6 注解方式权限控制 Spring Security除了可以在配置文件中配置权限校验规则还可以使用注解方式控制类中方法的调用。例如Controller中的某个方法要求必须具有某个权限才可以访问此时就可以使用Spring Security框架提供的注解方式进行控制。
实现步骤
第一步在spring-security.xml文件中配置组件扫描用于扫描Controller
mvc:annotation-driven/mvc:annotation-driven
context:component-scan base-packagecom.itheima.controller/context:component-scan第二步在spring-security.xml文件中开启权限注解支持
!--开启注解方式权限控制--
security:global-method-security pre-post-annotationsenabled /第三步创建Controller类并在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;}
}3.5.7 退出登录 用户完成登录后Spring Security框架会记录当前用户认证状态为已认证状态即表示用户登录成功了。那用户如何退出登录呢我们可以在spring-security.xml文件中进行如下配置
!--logout退出登录logout-url退出登录操作对应的请求路径logout-success-url退出登录后的跳转页面
--
security:logout logout-url/logout.do logout-success-url/login.html invalidate-sessiontrue/通过上面的配置可以发现如果用户要退出登录只需要请求/logout.do这个URL地址就可以同时会将当前session失效最后页面会跳转到login.html页面。