1.网页常用的几种验证方式
(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让用户可以授权第三方网站访问他们存储在另外服务提供者的某些特定信息,而非所有内容这种基于OAuth的
认证机制适用于个人消费者类的互联网产品,如社交类APP等应用,但是不太适合拥有自有认证
权限管理的企业应用。
(4)Token Auth
使用基于 Token 的身份验证方法,在服务端不需要存储用户的登录记录。大概的流程是这样的:
1. 客户端使用用户名跟密码请求登录
2. 服务端收到请求,去验证用户名与密码
3. 验证成功后,服务端会签发一个 Token,再把这个 Token 发送给客户端
4. 客户端收到 Token 以后可以把它存储起来,比如放在 Cookie 里
5. 客户端每次向服务端请求资源的时候需要带着服务端签发的 Token
6. 服务端收到请求,然后去验证客户端请求里面带着的 Token,如果验证成功,就向客户端返回请求的数据
Token Auth的优点
支持跨域访问: Cookie是不允许垮域访问的,这一点对Token机制是不存在的,前提是传输的用户认证信息通
过HTTP头传输.
无状态(也称:服务端可扩展行):Token机制在服务端不需要存储session信息,因为Token 自身包含了所有登
录用户的信息,只需要在客户端的cookie或本地介质存储状态信息.
更适用CDN: 可以通过内容分发网络请求你服务端的所有资料(如:javascript,HTML,图片等),而你的服
务端只要提供API即可.
去耦: 不需要绑定到一个特定的身份验证方案。Token可以在任何地方生成,只要在你的API被调用的时候,你
可以进行Token生成调用即可.
更适用于移动应用: 当你的客户端是一个原生平台(iOS, Android,Windows 8等)时,Cookie是不被支持的
(你需要通过Cookie容器进行处理),这时采用Token认证机制就会简单得多。
CSRF:因为不再依赖于Cookie,所以你就不需要考虑对CSRF(跨站请求伪造)的防范。
性能: 一次网络往返时间(通过数据库查询session信息)总比做一次HMACSHA256计算 的Token验证和解析
要费时得多.
不需要为登录页面做特殊处理: 如果你使用Protractor 做功能测试的时候,不再需要为登录页面做特殊处理.
基于标准化:你的API可以采用标准化的 JSON Web Token (JWT). 这个标准已经存在多个后端库(.NET, Ruby,
Java,Python, PHP)和多家公司的支持(如:Firebase,Google, Microsoft)
2.什么是JWT
JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的
信息。在Java世界中通过JJWT实现JWT创建和验证。
token的创建
创建maven工程,引入依赖
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.6.0</version> </dependency>
创建类createJwtDemo,用于生成token
package com.common.token; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import java.util.Date; public class createJwtDemo { /** * 通过jjwt创建token * @param args */ public static void main(String[] args) { JwtBuilder jwtBuilder = Jwts.builder().setId("id") .setSubject("赵") //用户信息 .setIssuedAt(new Date()) //签名时间 .signWith(SignatureAlgorithm.HS256, "bgyz") .claim("userId","123456") .claim("name","赵天") ;//设置签名防止被篡改 /** * bgyz 注意最少4个字符,否则会报 * Exception in thread "main" java.lang.IllegalArgumentException: secret key byte array cannot be null or empty. * 错误 */ String token = jwtBuilder.compact(); System.out.println(token); } }
token的解析
View Code
package com.common.token; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; public class ParseJwt { /** * 解析 jwtToken字符串 * @param args */ public static void main(String[] args) { String token="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJpZCIsInN1YiI6Iui1tSIsImlhdCI6MTU4MDAyNjIxMiwidXNlcklkIjoiMTIzNDU2IiwibmFtZSI6Iui1teWkqSJ9.XFILGV-nflhhd_kO4df7aGcm_Z7ZRJ3gdx4HtU2Spfo"; Claims claims = Jwts.parser().setSigningKey("bgyz").parseClaimsJws(token).getBody(); //私有数据存放在 claims System.out.println(claims.getId()); System.out.println(claims.getSubject()); System.out.println(claims.getIssuedAt()); /** * 解析自定义的claim中的内容 */ System.out.println(claims.get("userId").toString()); System.out.println(claims.get("name").toString()); } }
上面只是测试token,现在创建一个token验证的工具类

package com.common.utils; import io.jsonwebtoken.Claims; import io.jsonwebtoken.JwtBuilder; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import lombok.Getter; import lombok.Setter; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import java.util.Date; import java.util.Map; /** * 1.如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某个项值,使用@Value * * 2、如果说,我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties */ @Getter @Setter @ConfigurationProperties("jwt.config") public class JwtUtils { //签名私钥 private String key; //签名的失效时间 // @Value("${jwt.config.ttl}") private Long ttl; /** * 设置认证token * id:登录用户id * subject:登录用户名 * */ public String createJwt(String id,String name,Map<String ,Object> map) { //1.设置失效时间 long now = System.currentTimeMillis();//当前毫秒 // System.out.println(ttl); long exp = now + ttl; //2.创建jwtBuilder JwtBuilder jwtBuilder = Jwts.builder().setId(id).setSubject(name) .setIssuedAt(new Date()) .signWith(SignatureAlgorithm.HS256, key); //3.根据map设置claims for(Map.Entry<String,Object> entry : map.entrySet()) { jwtBuilder.claim(entry.getKey(),entry.getValue()); } jwtBuilder.setExpiration(new Date(exp)); //4.创建token String token = jwtBuilder.compact(); return token; } /** * 解析token字符串获取clamis */ public Claims parseJwt(String token) { Claims claims = Jwts.parser().setSigningKey(key).parseClaimsJws(token).getBody(); return claims; } }
jwt.config 配置在 application.yml文件中
jwt:
config:
key: bgyg
ttl: 50000
springboot 启动类添加
@Bean public JwtUtil jwtUtil(){ return new util.JwtUtil(); }
用户登录获取token和请求时携带token 后台解析token中的用户信息(写的简单例子,可以根据具体业务封装返回数据)
package com.zhao.system.controller; import com.common.utils.JwtUtils; import io.jsonwebtoken.Claims; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map; @RestController public class usercontroller { @Autowired private JwtUtils jwtUtils; /** * 使用jjwt token 进行验证登录 */ @ResponseBody @GetMapping("/login") public String login(){ Map<String ,Object> map= new HashMap(); map.put("userName","张三"); String token = jwtUtils.createJwt("1","zhao",map); return token; } // /** * 解析token 用get获取的 主要是测试 */ // @ResponseBody // @GetMapping("/userInformation/{token}") // public String parseDemoToken(@PathVariable("token") String token){ // Claims claims = jwtUtils.parseJwt(token); // claims.get("userName"); 获取设置的用户 // return claims.get("userName").toString(); // } /** * 解析token */ @ResponseBody @GetMapping("/userInformation") public String parseToken(HttpServletRequest request){ /** * 从请求头信息中获取token信息 token放在哪和前端约定就行了 * 1.获取请求头 中的 名称=Authorization * 2.替换 Bearer +空格 * 3.解析 token * 4.获取clamis * */ String authorization = request.getHeader("Authorization"); //spring 判断为空的方法 if(StringUtils.isEmpty(authorization)){ return "请进行登录"; } //获取到token 信息 String token = authorization.replace("Bearer", ""); Claims claims = jwtUtils.parseJwt(token); // claims.get("userName"); 获取设置的用户 return claims.get("userName").toString(); } }