[转] 用WWW-Authenticate实现登录验证

用WWW-Authenticate实现登录验证

文章来源:http://www.keakon.cn/bbs/thread-1989-1-1.html
今天在研究HTTP协议时发现一个叫WWW-Authenticate的头字段,可以用于实现登录验证。它是在 RFC 2617中定义的。

用法很简单,将状态码设为401,在响应头中加上这个字段即可:
引用:
WWW-Authenticate: Basic realm="testrealm@keakon.cn"
浏览器接收到这个响应后,就会弹出这样的对话框:
用WWW-Authenticate实现登录验证 - keakon的blog -

然后用户输入用户名和密码,点确定进行登录。
此时用户名和密码会以冒号:分隔,并进行base64编码,在请求头中以Authorization字段发出:
引用:
Authorization: Basic base64编码过的登录信息
服务器只要获取Authorization字段,按base64解码,再以冒号区分用户名和密码,即可验证是否正确了。由于用户名一般不允许包含冒号,所以即使密码中输入了冒号也没关系。

一个简单的实现如下:
The py code:
  1. def get(self):   
  2.     authorization = self.request.headers.get('Authorization''')   
  3.     if authorization and authorization[:6] == 'Basic ':   
  4.         user, password = b64decode(authorization[6:]).split(':'1)   
  5.         if user == 'admin' and password == 'fuckgfw':   
  6.             self.echo('hello, ' + user)   
  7.             return  
  8.   
  9.     self.set_status(401)   
  10.     self.header['WWW-Authenticate'] = 'Basic realm="testrealm@keakon.cn"'  

当然,如果你直接这么实现的话,你的用户就惨了。因为HTTP协议是不安全的,任何窃听者都能获取Authorization字段,然后就能很轻易地获取密码了,所以这种简单的实现只能用于HTTPS。

为了确保用户的密码不被窃取,用户的登录信息应该被加密。而实际上并不需要完整的登录信息,只要一个可用于验证的摘要即可,于是服务器可以指定浏览器生成一个Digest。
所需的参数很多,有服务器生成的每次均唯一的字符串、用户请求的URI、请求序列号等。浏览器根据这些参数,与用户名、密码的MD5值用冒号组合起来,再求一次MD5,作为整个的摘要。
这样就非常安全了,只是对服务器负担较大,因为要生成一个随机字符串,还得记录请求序列号等。
好在有些库已经提供了这些功能,所以可以直接使用现成的。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Spring Boot中生成Token的一种常见方法是使用JSON Web Token(JWT)。JWT是一种轻量级的身份验证和授权协议,可以在网络应用程序中安全地传输信息。以下是在Spring Boot中使用JWT生成Token的步骤: 1. 添加依赖项:在pom.xml文件中添加以下依赖项: ```xml <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> ``` 2. 创建一个JWT工具类:创建一个名为JwtTokenUtil的工具类,用于生成和验证JWT令牌。以下是一个简单的例子: ```java import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.function.Function; @Component public class JwtTokenUtil { private static final long serialVersionUID = -2550185165626007488L; public static final long JWT_TOKEN_VALIDITY = 5 * 60 * 60; @Value("${jwt.secret}") private String secret; // retrieve username from jwt token public String getUsernameFromToken(String token) { return getClaimFromToken(token, Claims::getSubject); } // retrieve expiration date from jwt token public Date getExpirationDateFromToken(String token) { return getClaimFromToken(token, Claims::getExpiration); } public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) { final Claims claims = getAllClaimsFromToken(token); return claimsResolver.apply(claims); } // for retrieving any information from token we will need the secret key private Claims getAllClaimsFromToken(String token) { return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody(); } // check if the token has expired private Boolean isTokenExpired(String token) { final Date expiration = getExpirationDateFromToken(token); return expiration.before(new Date()); } // generate token for user public String generateToken(UserDetails userDetails) { Map<String, Object> claims = new HashMap<>(); return doGenerateToken(claims, userDetails.getUsername()); } // while creating the token - // 1. Define claims of the token, like Issuer, Expiration, Subject, and the ID // 2. Sign the JWT using the HS512 algorithm and secret key. // 3. According to JWS Compact Serialization(https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-41#section-3.1) compaction of the JWT to a URL-safe string private String doGenerateToken(Map<String, Object> claims, String subject) { return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() + JWT_TOKEN_VALIDITY * 1000)) .signWith(SignatureAlgorithm.HS512, secret).compact(); } // validate token public Boolean validateToken(String token, UserDetails userDetails) { final String username = getUsernameFromToken(token); return (username.equals(userDetails.getUsername()) && !isTokenExpired(token)); } } ``` 3. 创建一个Authentication Controller:创建一个名为AuthenticationController的控制器,用于处理用户身份验证和生成JWT令牌。以下是一个简单的例子: ```java import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.web.bind.annotation.*; @RestController @RequestMapping("/auth") public class AuthenticationController { @Autowired private AuthenticationManager authenticationManager; @Autowired private JwtTokenUtil jwtTokenUtil; @Autowired private UserDetailsService userDetailsService; @PostMapping("/login") public ResponseEntity<?> createAuthenticationToken(@RequestBody AuthenticationRequest authenticationRequest) throws Exception { try { authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(authenticationRequest.getUsername(), authenticationRequest.getPassword())); } catch (AuthenticationException e) { throw new Exception("Incorrect username or password", e); } final UserDetails userDetails = userDetailsService.loadUserByUsername(authenticationRequest.getUsername()); final String token = jwtTokenUtil.generateToken(userDetails); return ResponseEntity.ok(new AuthenticationResponse(token)); } } ``` 4. 在application.properties中设置JWT密钥: ```properties jwt.secret=mysecretkey ``` 现在,您可以通过向“/auth/login”端点发出POST请求来生成JWT令牌。请求主体应该是包含用户名和密码的JSON对象。如果成功验证用户凭据,控制器将返回一个包含JWT令牌的JSON对象。您可以将此令牌包含在后续请求的Authorization标头中,以进行身份验证和授权。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值