http基本认证Authentication OAuth JWT

Authentication:

http是一种无状态的协议, 浏览器和web server可以通过cookie来识别身份。

应用程序一般不会使用cookie识别身份,通常是把 "用户名+密码"用BASE64编码放在请求头的Authorization中发送给服务端, 这种方式叫HTTP基本认证(Basic Authentication)。

1.client发送http request到web server 。

2.request中没有包含Authorization头,  web server返回一个401 Unauthozied 给client,在response的头WWW-Authenticate中添加信息。

3.client把username和passwd用编码(或者加密)后,放在Authorization头中发送给web server。

4.web server将Authorization头中的username和passwd解码(或解密)进行验证, 如果验证通过,将根据请求发送资源给客户端。

这样的请求在网络上用HTTP传输是很不安全的。 一般会用HTTPS传输,。

https在http基础上面添加了ssl安全证书,请求并发一旦上去的话耗时要比http多出很多,缓存没有http好。有时https也是有一定的缺点,https真是请求响应内容进行加密的,但HTTPS协议的加密范围有限,ssl证书信用链体系并不绝对安全,在可以控制CA根证书的情况下,中间人攻击一样可行。即使https协议在黑客攻击、ddos/cc、服务器劫持等方面起不到什么作用。

最好的方式就是内容https加密+身份验证机制。特别是在防爬虫、突破权限获取数据效果最为明显

 

OAuth:

OAuth对于Http来说,放在Authorization头中的不是用username和passwd,而是一个token。

OAuth是一个开放标准,提供了一种简单和标准的安全授权方法,允许用户无需将某个网站的用户名密码提供给第三方应用就可以让该第三方应用访问该用户在某网站上的某些特定信息(如简单的个人信息)。

我们通常在网站上注册的时候,要填写邮箱user信息很多东西balabala...,如果使用oauth协议会省略这个比较麻烦的步骤。网站后台在处理登陆的时候,调用了oauth协议,用户在登陆的时候可以使用第三方账号登陆。例如:在我们访问博客or论坛想要发帖或者下载东西时,都需要在登录网站后才可以操作。我们经常在网站登陆页面上,显示可以选择QQ/微信/微博登陆,优化了用户对页面的体验。这就是使用了第三方的登陆,oauth第三方协议成了现在较为流行的一种登陆方式。

现在一般用的是OAuth2.0

OAuth2.0协议交互流程

+--------+                               +---------------+
     |        |--(A)- Authorization Request ->|   Resource    |
     |        |                               |     Owner     |
     |        |<-(B)-- Authorization Grant ---|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(C)-- Authorization Grant -->| Authorization |
     | Client |                               |     Server    |
     |        |<-(D)----- Access Token -------|               |
     |        |                               +---------------+
     |        |
     |        |                               +---------------+
     |        |--(E)----- Access Token ------>|    Resource   |
     |        |                               |     Server    |
     |        |<-(F)--- Protected Resource ---|               |
     +--------+                               +---------------+

Token为获取信息的凭证,如上图的Access Token,关于Token的具体使用有相应的RFC文件指导

OAuth1.0和OAuth2.0 官方RFC文档:

https://tools.ietf.org/html/rfc5849

https://tools.ietf.org/html/rfc6750

Token的类型可分为两种:

    1.Bearer 包含一个简单的Token字符串.

    2.MAC 由消息授权码(Message Authentication Code)和Token组成

Authorization: Bearer sF_6.B7f-8.9xmP
Authorization: MAC id="t67vi01hd3",nonce="849662:fs873ka",mac="NsdHsdndKBkjfKfhKJN="

Token的认证请求的方式有三种,客户端可以选择任意一种:

    1.放在URI

        GET /index.html?access_token=sF_6.B7f-8.9xmP
        Host: test.com
    2.放在请求头

        GET /index.html HTTP/1.1
        Host: test.com
        Authorization: Bearer sF_6.B7f-8.9xmP
    3.放在请求体

        POST /index.html HTTP/1.1
        Host: test.com
        Content-Type: application/x-www-form-urlencoded
        access_token=Bearer sF_6.B7f-8.9xmP

 

Spring Security OAuth框架学习:

 https://spring.io/projects/spring-security-oauth

 

JWT:

JWT: 是一个开放的标准,规定了一种Token实现方式,以JSON为格式。

官方RFC文档:

https://tools.ietf.org/html/rfc7519

原理:

    1.server给client分配一个加密的token。

    2.client保存这个token,以后的每个请求client都会发送这个token。

    3.server通过token判断是否是鉴权过的用户,并返回请求的响应数据。

可以通过url/请求头/post参数发送,数据量小传输速度快。
payload中包含了所有用户所需要的信息,由于JWT是自包含的避免了多次查询数据库。

 

JWT结构分为三部分:

    Header: 存放Token类型和加密算法。

    Payload: 用户身份信息。

    Signature: 签名是将前面的Header,Payload信息以及一个密钥组合起来并使用Header中的算法进行加密。

                    算法(base64UrlEncode(header) + "." +  base64UrlEncode(payload),  密钥)

Signature用于验证消息的发送者以及消息内容有没有经过篡改。如果黑客获取到了payload中的用户信息,并进行了篡改,那么经过Base64编码后也会发生变化,而签名是根据Header和Payload共同决定的,签名也会不一样,服务器就会判断出不一致。

完整的JWT格式,它拼接了之前的Header, Payload以及秘钥签名:

1)用户在client输入用户名和密码登录。

2)server认证通过后,返回给用户一个JWT。

3)client只需在本地保存该token,通常使用local storage也可以使用cookie。

4)当用户下次访问时,在Authorization头部使用Bearer模式添加JWT,格式Authentication: Bearer <token>。

5)server检查请求头Authentication中的JWT,如果合法则允许用户的行为。

 

 

 

 


 

 

 

 

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Boot Security是一个非常流行的安全框架,可以帮助开发人员实现各种安全功能。其中,OAuth2和JWT是两个非常重要的安全技术,可以用于实现授权和认证。下面是一个基于Spring Boot Security的完整示例,演示如何使用OAuth2和JWT实现安全功能。 1. 创建一个Spring Boot项目 使用Spring Initializr创建一个新的Spring Boot项目,添加以下依赖: - Spring Web - Spring Security - Spring Data JPA - H2 Database - Spring Security OAuth2 - jjwt 2. 添加配置文件 在application.properties文件中添加以下配置: ``` spring.datasource.url=jdbc:h2:mem:testdb spring.datasource.driverClassName=org.h2.Driver spring.datasource.username=sa spring.datasource.password= spring.jpa.database-platform=org.hibernate.dialect.H2Dialect spring.jpa.hibernate.ddl-auto=create-drop spring.h2.console.enabled=true spring.h2.console.path=/h2-console spring.security.oauth2.client.registration.myapp.client-id=myapp spring.security.oauth2.client.registration.myapp.client-secret=myappsecret spring.security.oauth2.client.registration.myapp.scope=read,write spring.security.oauth2.client.provider.myapp.authorization-uri=http://localhost:8080/oauth/authorize spring.security.oauth2.client.provider.myapp.token-uri=http://localhost:8080/oauth/token spring.security.oauth2.client.provider.myapp.user-info-uri=http://localhost:8080/userinfo spring.security.oauth2.client.provider.myapp.user-name-attribute=name ``` 这些配置将用于配置数据源、Hibernate、H2控制台和OAuth2。 3. 创建实体类和仓库 创建一个User实体类,用于表示用户信息: ```java @Entity @Table(name = "user") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false, unique = true) private String username; @Column(nullable = false) private String password; @Column(nullable = false) private String email; // getters and setters } ``` 创建一个UserRepository接口,用于操作User实体类: ```java @Repository public interface UserRepository extends JpaRepository<User, Long> { Optional<User> findByUsername(String username); } ``` 4. 创建用户服务 创建一个UserService接口,用于定义获取用户和创建用户的方法: ```java public interface UserService { User createUser(String username, String password, String email); Optional<User> getUserByUsername(String username); } ``` 创建一个UserServiceImpl实现UserService接口,用于实现上述方法: ```java @Service public class UserServiceImpl implements UserService { @Autowired private UserRepository userRepository; @Autowired private PasswordEncoder passwordEncoder; @Override public User createUser(String username, String password, String email) { User user = new User(); user.setUsername(username); user.setPassword(passwordEncoder.encode(password)); user.setEmail(email); return userRepository.save(user); } @Override public Optional<User> getUserByUsername(String username) { return userRepository.findByUsername(username); } } ``` 5. 配置Spring Security 创建一个WebSecurityConfig类,用于配置Spring Security: ```java @Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserService userService; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/oauth/**").permitAll() .anyRequest().authenticated() .and() .csrf().disable() .formLogin().disable() .httpBasic().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(username -> userService.getUserByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("User not found: " + username))) .passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } ``` 这个配置类将所有请求都需要进行认证,但是允许OAuth2请求。同时,禁用了CSRF、表单登录、HTTP基本认证和会话管理。 6. 配置OAuth2 创建一个OAuth2Config类,用于配置OAuth2: ```java @Configuration @EnableAuthorizationServer public class OAuth2Config extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private UserService userService; @Autowired private PasswordEncoder passwordEncoder; @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { clients.inMemory() .withClient("myapp") .secret(passwordEncoder.encode("myappsecret")) .authorizedGrantTypes("authorization_code", "refresh_token") .scopes("read", "write") .redirectUris("http://localhost:8081/login/oauth2/code/myapp"); } @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.authenticationManager(authenticationManager) .userDetailsService(username -> userService.getUserByUsername(username) .orElseThrow(() -> new UsernameNotFoundException("User not found: " + username))) .accessTokenConverter(accessTokenConverter()) .pathMapping("/oauth/token", "/signin"); } @Bean public JwtAccessTokenConverter accessTokenConverter() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey("secret"); return converter; } @Bean public TokenStore tokenStore() { return new JwtTokenStore(accessTokenConverter()); } } ``` 这个配置类定义了一个OAuth2客户端,将授权码和刷新令牌作为授权类型,并允许读取和写入作用域。同时,定义了一个端点配置,将认证管理器、用户详情服务、访问令牌转换器和令牌存储配置到端点上。 7. 创建控制器 创建一个UserController类,用于处理用户相关的请求: ```java @RestController @RequestMapping("/users") public class UserController { @Autowired private UserService userService; @PostMapping public User createUser(@RequestBody UserDto userDto) { return userService.createUser(userDto.getUsername(), userDto.getPassword(), userDto.getEmail()); } @GetMapping("/{username}") public User getUser(@PathVariable String username) { return userService.getUserByUsername(username) .orElseThrow(() -> new NotFoundException("User not found: " + username)); } } ``` 这个控制器中定义了创建用户和获取用户的方法。 8. 创建JWT过滤器 创建一个JwtFilter类,用于在请求中验证JWT令牌: ```java public class JwtFilter extends OncePerRequestFilter { private static final String AUTHORIZATION_HEADER = "Authorization"; @Autowired private JwtAccessTokenConverter accessTokenConverter; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String authorizationHeader = request.getHeader(AUTHORIZATION_HEADER); if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { String token = authorizationHeader.substring(7); Authentication authentication = accessTokenConverter.extractAuthentication(token); SecurityContextHolder.getContext().setAuthentication(authentication); } filterChain.doFilter(request, response); } } ``` 这个过滤器会从请求头中获取JWT令牌,并使用令牌转换器验证令牌。如果验证通过,则将用户认证信息存储到Spring Security上下文中。 9. 注册JWT过滤器 在WebSecurityConfig类中,添加以下配置: ```java @Bean public JwtFilter jwtFilter() { return new JwtFilter(); } @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(jwtFilter(), UsernamePasswordAuthenticationFilter.class); // ... } ``` 这个配置将JwtFilter注册到Spring Security过滤器链中。 10. 创建JWT工具类 创建一个JwtUtils类,用于生成和解析JWT令牌: ```java public class JwtUtils { public static final String SUBJECT = "myapp"; public static String generateToken(User user) { Map<String, Object> claims = new HashMap<>(); claims.put("sub", SUBJECT); claims.put("id", user.getId()); claims.put("username", user.getUsername()); claims.put("email", user.getEmail()); Date now = new Date(); Date expiration = new Date(now.getTime() + 60 * 60 * 1000); return Jwts.builder() .setClaims(claims) .setIssuedAt(now) .setExpiration(expiration) .signWith(SignatureAlgorithm.HS256, "secret") .compact(); } public static Long getUserIdFromToken(String token) { Claims claims = Jwts.parser() .setSigningKey("secret") .parseClaimsJws(token) .getBody(); return claims.get("id", Long.class); } } ``` 这个工具类将用户信息存储到JWT令牌中,并使用HS256算法进行签名。 11. 创建DTO类 创建一个UserDto类,用于接收创建用户的请求: ```java public class UserDto { private String username; private String password; private String email; // getters and setters } ``` 12. 测试 启动应用程序,并使用以下命令创建一个用户: ``` curl -X POST -H 'Content-Type: application/json' -d '{"username":"test","password":"test123","email":"test@example.com"}' http://localhost:8080/users ``` 使用以下命令获取访问令牌: ``` curl -X POST -vu myapp:myappsecret http://localhost:8080/oauth/token -H 'Accept: application/json' -d 'grant_type=authorization_code&code={CODE}&redirect_uri=http://localhost:8081/login/oauth2/code/myapp' ``` 将{CODE}替换为授权码,并将返回的访问令牌用于获取用户信息: ``` curl -H 'Authorization: Bearer {ACCESS_TOKEN}' http://localhost:8080/users/test ``` 将{ACCESS_TOKEN}替换为访问令牌,在请求头中发送即可。 以上就是一个完整的Spring Boot Security OAuth2 JWT示例,演示了如何实现授权和认证

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值