赞
踩
认证:系统提供的用于识别用户身份的功能,通常提供用户名和密码进行登录其实就是在进行认证,认证的目的是让系统知道你是谁。
授权:用户认证成功后,需要为用户授权,其实就是指定当前用户可以操作哪些功能。
实现认证和授权需要以下七张表
所有用户都存在t_user中
给用户授予不同的权限,权限保存在t_premission中
角色表t_role是便于为用户授权而建立的表,角色就是一堆权限的集合,角色和权限是多对多的关系
页面的全部菜单保存在t_menu中
以上四个主表通过三张副表实现两两对应关系,且都是多对多关系
用户user和角色role进行关联
角色role和premission关联
角色role和菜单menu关联
角色表有着重要作用,因为都和角色表有多对多关系
用户表ID和角色表ID相关联,关联信息在user_role表中
用户需要不同角色,赋予不同的角色ID
认证过程:只需要用户表就可以了,在用户登录时可以查询用户表t_user进行校验,判断用户输入的用户名和密码是否正确。
授权过程:用户必须完成认证之后才可以进行授权,首先可以根据用户查询其角色,再根据角色查询对应的菜单,这样就确定了用户能够看到哪些菜单。然后再根据用户的角色查询对应的权限,这样就确定了用户拥有哪些权限。所以授权过程会用到上面7张表。
Spring Security可以帮助我们来简化认证和授权
1.在web.xml中配置文件
- <!--/*表示安全框架启动之后会扫描所有的请求-->
- <filter-name>springSecurityFilterChain</filter-name>
- <url-pattern>/*</url-pattern>
2.resources提供spring_security配置文件
1.设置拦截规则
- <security:http auto-config="true" use-expressions="true">
-
- <security:intercept-url pattern="/pages/**" access="isAuthenticated()" />
2.配置认证管理器
- <!--认证管理器,用于处理认证操作-->
- <security:authentication-manager>
- <!--认证提供者,执行具体的认证逻辑,此处爆红不影响使用-->
- <security:authentication-provider user-service-ref="springSecurityUserService">
- <!--指定密码加密策略-->
- <security:password-encoder ref="passwordEncoder" />
- </security:authentication-provider>
- </security:authentication-manager>
{noop}表示明文
web.xml
- <!--/*表示安全框架启动之后会扫描所有的请求-->
- <filter-name>springSecurityFilterChain</filter-name>
- <url-pattern>/*</url-pattern>
spring_security配置文件
- <!--
- intercept-url:定义一个拦截规则
- pattern:对哪些url进行权限控制
- access:在请求对应的URL时需要什么权限,默认配置时它应该是一个以逗号分隔的角色列表,请求的用户只需拥有其中的一个角色就能成功访问对应的URL
- isAuthenticated():已经经过认证(不是匿名用户),只要是
- -->
- <security:intercept-url pattern="/pages/**" access="isAuthenticated()" />
配置可以匿名访问的资源
- <!--
- http:用于定义相关权限控制
- 指定哪些资源不需要进行权限校验,匿名(不登陆)即可访问以下资源,可以使用通配符
- -->
- <security:http security="none" pattern="/js/**" />
- <security:http security="none" pattern="/css/**" />
- <security:http security="none" pattern="/img/**" />
- <security:http security="none" pattern="/plugins/**" />
使用自己指定的页面作为登录页面
username,password对应登录界面的参数
login-processing-url:登录表单提交的地址,后续不需要创建controller类,框架会自动处理 default-target-url:认证成功跳转界面
authentication-failure-url:失败跳转界面
- <!--form-login:定义表单登录信息-->
- <security:form-login login-page="/login.html"
- username-parameter="username"
- password-parameter="password"
- login-processing-url="/login.do"
- default-target-url="/pages/main.html"
- always-use-default-target="true"
- authentication-failure-url="/login.html"
- />
配置crsf项
- <!--
- csrf:对应CsrfFilter过滤器
- disabled:是否启用CsrfFilter过滤器,如果使用自定义登录页面需要关闭此项,否则登录操作会被禁用(403)。默认是开启的,true表示关闭
- -->
- <security:csrf disabled="true"></security:csrf>
如果我们要从数据库动态查询用户信息,就必须按照spring security框架的要求提供一个实现UserDetailsService接口的实现类,并按照框架的要求进行配置即可。框架会自动调用实现类中的方法并自动进行密码校验。
1.创建一个service类
- /**
- * 动态给用户授予角色和权限
- */
- @Component
- public class SpringSecurityUserService implements UserDetailsService {
-
- @Reference //注意:此处要通过dubbo远程调用用户服务
- private UserService userService;
-
- //根据用户名查询用户信息
- public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
- User user = userService.findByUsername(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()));
- }
- }
- org.springframework.security.core.userdetails.User securityUser = new org.springframework.security.core.userdetails.User(username,user.getPassword(),list);
- return securityUser;
- }
- }
//User是框架提供的User,根据用户名查询数据库信息(包含存储的密码,将用户信息返回给框架,框架会进行密码比对 User user = userService.findByUsername(username);
bcrypt:将salt随机并混入最终加密后的密码,验证时也无需单独提供之前的salt,从而无需单独处理salt问题
第一步:在spring-security.xml文件中指定密码加密对象
user1.setPassword(passwordEncoder.encode("admin"));
数据库中的密码是经过加密之后的密码,前端提交的密码会自动加密并和数据库中作比较
记得在xml文件中开启注解控制
- <!--只要认证通过就可以访问-->
- <security:intercept-url pattern="/index.jsp" access="isAuthenticated()" />
- <security:intercept-url pattern="/a.html" access="isAuthenticated()" />
-
- <!--拥有add权限就可以访问b.html页面-->
- <security:intercept-url pattern="/b.html" access="hasAuthority('add')" />
-
- <!--拥有ROLE_ADMIN角色就可以访问c.html页面-->
- <security:intercept-url pattern="/c.html" access="hasRole('ROLE_ADMIN')" />
-
- <!--拥有ROLE_ADMIN角色就可以访问d.html页面,
- 注意:此处虽然写的是ADMIN角色,框架会自动加上前缀ROLE_-->
- <security:intercept-url pattern="/d.html" access="hasRole('ADMIN')" />
针对不同页面访问的权限要求,SpringSecurity提供了注解方式权限控制,可以精确到方法控制级别
第一步:在spring-security.xml文件中配置组件扫描,用于扫描Controller
- <mvc:annotation-driven></mvc:annotation-driven>
- <context:component-scan base-package="com.itheima.controller"></context:component-scan>
第二步:在spring-security.xml文件中开启权限注解支持
- <!--开启注解方式权限控制-->
- <security:global-method-security pre-post-annotations="enabled" />
controller类中的代码
- @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";
- }
- }
注意注解代码中的权限必须和数据中权限表的关键字一致
1.新建存储空间,并使用javaSDK方式操作空间
Java SDK的所有的功能,都需要合法的授权。授权凭证的签算需要七牛账号下的一对有效的Access Key和Secret Key。
后端代码
新建上传文件工具类Utils。工具类中需要配置云存储的相关参数,
- public class QiniuUtils {
- public static String accessKey = "YLRQlxIU5IyLEGSbhFt-hAYKvGY0_zNk_eABhM8t";
- public static String secretKey = "eswtzJogA9qDSne9Z9uZM8Kt8QNS0AYPNS971dxX";
- public static String bucket = "ahtcm-space-01";
-
- //上传文件(方法1
- public static void upload2Qiniu(String filePath,String fileName){
- //构造一个带指定Zone对象的配置类
- Configuration cfg = new Configuration(Region.region2());//使用华南机房
- cfg.resumableUploadAPIVersion = Configuration.ResumableUploadAPIVersion.V2;// 指定分片上传版本
- //...其他参数参考类注释
- UploadManager uploadManager = new UploadManager(cfg);
- //...生成上传凭证,然后准备上传
- Auth auth = Auth.create(accessKey, secretKey);
- String upToken = auth.uploadToken(bucket);
- try {
- Response response = uploadManager.put(filePath, fileName, upToken);
- //解析上传成功的结果
- DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
- System.out.println("文件名:" + putRet.key);
- System.out.println("文件在云存储中的唯一标识符:" + putRet.hash);
- } catch (QiniuException ex) {
- Response r = ex.response;
- System.err.println(r.toString());
- try {
- System.err.println(r.bodyString());
- } catch (QiniuException ex2) {
- //ignore
- }
- }
- }
-
- //上传文件(法2
- public static void upload2Qiniu(byte[] bytes, String fileName){
- //构造一个带指定Zone对象的配置类
- Configuration cfg = new Configuration(Region.region2());//使用华南机房
- //...其他参数参考类注释
- UploadManager uploadManager = new UploadManager(cfg);
-
- //默认不指定key的情况下,以文件内容的hash值作为文件名
- String key = fileName;
- Auth auth = Auth.create(accessKey, secretKey);
- String upToken = auth.uploadToken(bucket);
- try {
- Response response = uploadManager.put(bytes, key, upToken);
- //解析上传成功的结果
- DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
- System.out.println("文件名:" + putRet.key);
- System.out.println("文件在云存储中的唯一标识符:" + putRet.hash);
- } catch (QiniuException ex) {
- Response r = ex.response;
- System.err.println(r.toString());
- try {
- System.err.println(r.bodyString());
- } catch (QiniuException ex2) {
- //ignore
- }
- }
- }
-
- //删除文件
- public static void deleteFileFromQiniu(String fileName){
- //构造一个带指定Zone对象的配置类
- Configuration cfg = new Configuration(Zone.zone0());
- String key = fileName;
- Auth auth = Auth.create(accessKey, secretKey);
- BucketManager bucketManager = new BucketManager(auth, cfg);
- try {
- bucketManager.delete(bucket, key);
- } catch (QiniuException ex) {
- //如果遇到异常,说明删除失败
- System.err.println(ex.code());
- System.err.println(ex.response.toString());
- }
- }
- }
在controller中调用工具类方法进行文件上传
- //文件上传,图片上传
- @RequestMapping("/upload")
- public Result upload(@RequestParam("imgFile") MultipartFile imgFile) {//使用springmvc的上传组件来上传文件,后台接收到文件
- //System.out.println(imgFile);
- //获取原始文件名
- String originalFilename = imgFile.getOriginalFilename();
- int lastIndexOf = originalFilename.lastIndexOf(".");
- //获取文件后缀
- String suffix = originalFilename.substring(lastIndexOf - 1);
- //使用UUID随机产生文件名称,防止同名文件覆盖
- String fileName = UUID.randomUUID().toString() + suffix;
- try {
- QiniuUtils.upload2Qiniu(imgFile.getBytes(), fileName);//使用七牛云工具类的bytes数组上传文件方法,第二个参数为文件名
- //将上传图片名称存入Redis,基于Redis的Set集合存储
- String urlFileName = "http://ruh9fwjil.hn-bkt.clouddn.com/" + fileName;
- jedisPool.getResource().sadd(RedisConstant.RECORD_PIC_RESOURCES,urlFileName);
- //图片上传成功
- Result result = new Result(true, MessageConstant.PIC_UPLOAD_SUCCESS);
- result.setData(fileName);
- return result;
- } catch (IOException e) {
- e.printStackTrace();
- //图片上传失败
- return new Result(false, MessageConstant.PIC_UPLOAD_FAIL);
- }
- }
如果网络地址配置正确,但前端不能实时查看到文件,去云平台查看是否是将空间设置为了私有空间,私有空间中的bucket不能被直接访问。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。