十次方第六天 密码加密与微服务鉴权 JWT

jwt 用于登录(认证)功能

学习目标:

  1. 能够使用BCrypt密码加密算法实现注册与登陆功能
  2. 能够说出常见的认证机制
  3. 能够说出JWT的组成部分,以及使用JWT的优点
  4. 能够使用 JWT 创建和解析token(令牌)
  5. 能够使用 JWT完成微服务鉴权

认证就是登录,说白了就是告诉系统你是谁,认证之后,则需要授权。

授权就是系统根据你当前登录用户的角色,给予对应的权限。分两步走:先认证,后授权。

BCrypt密码加密

任何应用考虑到安全,绝不能明文的方式保存密码。密码应该通过哈希算法进行加密。 有很多标准的算法比如SHA或者MD5,结合salt(盐)是一个不错的选择。 Spring Security 提供了BCryptPasswordEncoder类,实现Spring的PasswordEncoder接口使用BCrypt强 哈希方法来加密密码。 BCrypt强哈希方法 每次加密的结果都不一样。

(1)tensquare_user微服务的pom引入依赖

<dependency> 
	<groupId>org.springframework.boot</groupId> 
	<artifactId>spring‐boot‐starter‐security</artifactId> 
</dependency>

(2)添加配置类 (资源/工具类中提供) 对加盐起作用

我们在添加了spring security依赖后,所有的地址都被spring security所控制了,我们目 前只是需要用到BCrypt密码加密的部分,所以我们要添加一个配置类,配置为所有地址 都可以匿名访问。

/*** 安全配置类 */
    @Configuration
    @EnableWebSecurity
    public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests()
                    .antMatchers("/**").permitAll()
                    .anyRequest().authenticated()
                    .and().csrf().disable();
        }
    }

备注
authorizeRequests():

  1. 是所有 security 全注解配置实现的开端,表示开始说明需要的权限。
  2. 需要的权限为两部分,第一部分是拦截的路径,第二部分访问该路径需要的权限。

antMatchers: 表示拦截什么路径,permitAll表示任何权限都可以访问,直接放行所有。

anyRequest():任何请求,authenticated 表示认证后才能访问。

and().csrf().disable(): 固定写法,表示使 csrf 拦截失效。csrf 是一种网络攻击技术。也就是Spring Security 设置的安全级别略高

如果使用 Spring 做开发,不用 Spring Boot开发的话,一般自己写的类加 注解,框架的类使用 配置文件。

如果使用全注解开发,则应使用Spring Boot来开发。
(3)修改tensquare_user工程的Application, 配置bean

@Bean 
public BCryptPasswordEncoder bcryptPasswordEncoder() { 
	return new BCryptPasswordEncoder();
 }

管理员密码加密

(1)新增管理员密码加密

@Autowired BCryptPasswordEncoder encoder; 
public void add(Admin admin) {
	admin.setId(idWorker.nextId()+""); //主键值 
	//密码加密 
	String newpassword = encoder.encode(admin.getPassword());//加密后 的密码
	admin.setPassword(newpassword); 
	adminDao.save(admin); 
}

(2)管理员登陆密码校验
controller 层 的 @RequestBody 注解作用:可以将前端 JSON 格式数据转成对象 ;也能转成 Map,写法分别如下:
转成Map

    /** 用户登陆 
     * @param loginname 
     * @param password 
     * @return
     */
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public Result login(@RequestBody Map<String, String> loginMap) {
        Admin admin = adminService.findByLoginnameAndPassword(loginMap.get("loginname"), loginMap.get("password"));
        if (admin != null) {
            return new Result(true, StatusCode.OK, "登陆成功");
        } else {
            return new Result(false, StatusCode.LOGINERROR, "用户名或密码错 误");
        }
    }

转成对象

 @RequestMapping(value = "/login", method = RequestMethod.POST)
    public Result login(@RequestBody Admin admin) {
        Admin admin = adminService.login(admin);
        if (admin != null) {
            return new Result(true, StatusCode.OK, "登陆成功");
        } else {
            return new Result(false, StatusCode.LOGINERROR, "用户名或密码错误");
        }
    }

service层

    @Autowired
    private BCryptPasswordEncoder encoder;


    public Admin login(Admin admin) {
        //先根据用户名查询对象
        Admin adminLogin = adminDao.findByLoginname(admin.getLoginname());
        //然后拿数据库中的密码和用户输入的密码匹配是否相同
        if(adminLogin != null && encoder.matches(admin.getPassword(),
           adminLogin.getPassword())) {//前者是用户输入的密码 ,后者是加密后的密码
            //保证数据库中的对象中的密码和用户输入的密码是一致的,登录成功
            return adminLogin;
        }
        //登录失败
        return null;
    }

dao层

/**
 * admin数据访问接口
 * @author Administrator
 */
public interface AdminDao extends JpaRepository<Admin,String>, JpaSpecificationExecutor<Admin>{
    public Admin findByLoginname(String loginname);
}

用户的加密注册和登录

用户注册时,密码的加密功能

   /**
	 * 增加
	 * @param user
	 */
	public void add(User user) {
	    user.setId( idWorker.nextId()+"" );
	    //密码加密
        user.setPassword(encoder.encode(user.getPassword()));
        user.setFollowcount(0);//关注数
        user.setFanscount(0);//粉丝数
        user.setOnline(0L);//在线时长
        user.setRegdate(new Date());//注册日期
        user.setUpdatedate(new Date());//更新日期
        user.setLastdate(new Date());//最后登陆日期
		userDao.save(user);
	}

用户登录

    @RequestMapping(value = "/login",method = RequestMethod.POST)
	private Result login(@RequestBody User user) {
	    user = userService.login(user.getMobile(),user.getPassword());
	    if(user == null) {
	        return new Result(false,StatusCode.LOGINERROR,"登录失败");
        }
        String token = jwtUtil.createJWT(user.getId(), user.getMobile(), "user");
	    Map<String,Object> map = new HashMap<>();
	    map.put("token",token);
	    map.put("roles","user");
        return new Result(true,StatusCode.OK,"登录成功",map);
    }

常见的认证机制

认证就是登录
1. HTTP Basic Auth ----无状态的

  • HTTP Basic Auth简单点说明就是每次请求API时都提供用户的username 和 password,简言之,Basic Auth是配合RESTful API 使用的最简单的认证方式,只需提供 用户名密码即可,但由于有把用户名密码暴 露给第三方客户端的风险,在生产环境下被 使用的越来越少。因此,在开发对外开放的RESTful API时,尽量避免采用HTTP Basic Auth。

2. Cookie Auth

  • Cookie认证机制就是为一次请求认证在服务端创建一个Session对象,同时在客户端 的浏览器端创建了一个Cookie对象;通过客户端带上来Cookie对象来与服务器端的 session对象匹配来实现状态管理的。默认的,当我们关闭浏览器的时候,cookie会被删 除。但可以通过修改cookie 的expire time使cookie在一定时间内有效;

3. OAuth

  • OAuth(开放授权)是一个开放的授权标准,允许用户让第三方应用访问该用户在 某一web服务上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和 密码提供给第三方应用。
  • OAuth允许用户提供一个令牌,而不是用户名和密码来访问他们存放在特定服务提 供者的数据。每一个令牌授权一个特定的第三方系统(例如,视频编辑网站)在特定的时 段(例如,接下来的2小时内)内访问特定的资源(例如仅仅是某一相册中的视频)。这 样,OAuth让用户可以授权第三方网站访问他们存储在另外服务提供者的某些特定信 息,而非所有内容

4. Token Auth
使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是 这样的:

  1. 客户端使用用户名跟密码请求登录
  2. 服务端收到请求,去验证用户名与密码
  3. 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
  4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里
  5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
  6. 服务端收到请求,然后去验证客户端请求里面带着的Token,如果验证成功,就向客户端返回请求的数据。

应用场景:
这种基于OAuth的认证机制适用于个人消费者类的互联网产品,如社交类APP等应 用,但是不太适合拥有自有认证权限管理的企业应用。

JWT

组成: 由三部分组成,头部、载荷和签名。一个 JWT 实际上就是一个字符串。

  • 头部是描述JWT 的类型 以及签名所用的算法;
  • 载荷是有效的信息;
  • 签名就是头部加上载荷,再加上盐后进行加密。

Base64编码

优点:

  1. 无状态;

  2. 支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提 是传输的用户认证信息通过HTTP头传输;

  3. 因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防 范。

Java的JJWT实现JWT

JJWT: Java Json Web Token

JJWT是一个提供端到端的JWT创建和验证的Java库。永远免费和开源(Apache License,版本2.0),JJWT很容易使用和理解。它被设计成一个以建筑为中心的流畅界 面,隐藏了它的大部分复杂性。

快速入门

1. token 创建
2. token 解析

用户登录成功后,生成token, 客户端就拿着 token 来访问后端,后端首先需要对 token 进行解析验证。

我们刚才已经创建了token ,在web应用中这个操作是由服务端进行然后发给客户 端,客户端在下次向服务端发送请求时需要携带这个token(这就好像是拿着一张门票一 样),那服务端接到这个token 应该解析出token中的信息(例如用户id),根据这些信息 查询数据库返回相应的结果。

解析 token 就是在验证 token.

3. token过期校验
4. 自定义claims

十次方微服务鉴权

JWT 工具类中有 key ttl 两个属性,不在该工具类中写。将来这个方法是在用户登陆时使用,哪一个模块登陆,则需要在哪一个模块中调用这个工具类,则只需要在需要调用这个工具类中 写这两个属性即可。因此, 就是谁调用,谁给他传过期时间和盐两个参数。增强通用性。

管理员登陆后台签发token
删除用户功能鉴权

去公司一般先做后台,基本上就看你 Spring security 学的怎么样,你做的没问题了,领导才会把一些核心业务交给你完成。

删除某个用户的功能, 必须有admin角色才能删除

业务层是直接抛出异常信息,控制层则是直接返回。

//拦截器只是把头请求中包含token的进行解析验证

所有前端 MVC 框架,应该有哪些功能?在你知道这个框架之后,给你一个新的框架,你依然能够驾驭。

  • 能和前端做交互:比如页面上的类型很单一,只有var和JSON两种类型,但java后台类型丰富。作为 Spring MVC框架,必须有一个功能:能把界面上简单的参数类型 转成对应的 java 类型参数;
  • 能把后台的 model 转成 对应的 JSON 或者普通的 VAR 传给前台;
  • 能够处理异常;
  • 上传文件

工作之后,最好的资料就是现场百度。

学知识,重要的是学思路,而不是存一堆资料在你电脑上。

问题1:别人动态ip恶意攻击你的系统,怎么办?
可以使用第三方技术,解决。

问题2:quartz 在规定的时间没处理完事务,怎么办,需要配置哪些
默认就是多线程。要改成单线程执行

七子表达式:年月日时分秒 周,其中 周和日不能同时设置,不用的那个设置 ?.

单点登录: 登录一个模块,所有模块都登录。比如登录了 QQ, 就登录了QQ音乐、邮箱、空间等模块。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值