auth2+jwt单点登录
时间: 2023-09-03 11:02:59 浏览: 45
Auth2(也称为OAuth2)是一种用于授权的开放标准,用于在不暴露用户凭据的情况下对第三方应用程序进行授权。JWT(JSON Web Token)是一种用于在网络应用间传递用于认证和授权的安全信息的开放标准。
单点登录(SSO)是一种身份验证机制,允许用户在一次成功的登录后,可以无需再次输入凭据即可访问多个关联应用程序。
在实现单点登录时,使用Auth2和JWT可以提供一种安全且有效的解决方案。
当用户尝试访问某个应用程序时,该应用程序将重定向用户到认证服务器(Auth Server)以获取授权。认证服务器验证用户凭据,并在身份验证成功后生成一个JWT令牌,并将其返回给应用程序。
应用程序接收到JWT令牌后,可以解析其中的信息,例如用户ID、权限等,并将其用于对用户进行身份验证和授权。
当用户尝试访问其他关联应用程序时,这些应用程序可以使用相同的JWT令牌进行身份验证,并验证其有效性。这样,用户无需再次输入凭据即可访问其他应用程序。
由于JWT令牌使用数字签名进行保护,因此可以防止黑客篡改令牌内容。此外,JWT令牌的过期时间可以被设置,以确保令牌在一段时间后失效,增加安全性。
综上所述,Auth2和JWT的组合可以实现单点登录,为用户提供一次登录即可访问多个应用程序的便利,并保证了安全性和授权的有效性。
相关问题
用springboot+JWT+Redis实现单点登录
单点登录(Single Sign-On,简称SSO)是一种身份验证技术,可以让用户只需一次登录,就可以访问多个应用程序。在实际开发中,我们可以使用Spring Boot、JWT和Redis来实现单点登录功能。
下面是实现单点登录的步骤:
1. 创建Spring Boot项目并引入所需依赖:spring-boot-starter-web、spring-boot-starter-data-redis和jjwt。
2. 创建一个User实体类,包含用户名和密码等信息。
3. 创建一个UserService,实现对用户信息的操作,包括注册、登录等。
4. 引入JWT依赖后,我们需要创建一个JWTUtil类,实现token的生成和解析。
5. 创建一个LoginController,用于处理用户的登录请求。在登录成功后,生成token并将其存储到Redis中。
6. 创建一个AuthController,用于验证用户的token是否有效。在验证成功后,可以获取用户信息并返回。
7. 在需要进行单点登录验证的应用程序中,只需要在请求中携带token,并调用AuthController进行验证即可。
具体实现细节可以参考以下代码示例:
User实体类:
```java
public class User {
private String username;
private String password;
// 省略setter和getter方法
}
```
UserService接口:
```java
public interface UserService {
void register(User user);
String login(String username, String password);
}
```
UserService实现类:
```java
@Service
public class UserServiceImpl implements UserService {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@Override
public void register(User user) {
// 省略用户注册逻辑
}
@Override
public String login(String username, String password) {
// 省略用户登录逻辑
// 登录成功后生成token并存储到Redis中
String token = JWTUtil.generateToken(username);
redisTemplate.opsForValue().set(username, token, 30, TimeUnit.MINUTES);
return token;
}
}
```
JWTUtil类:
```java
public class JWTUtil {
private static final String SECRET_KEY = "my_secret_key";
private static final long EXPIRATION_TIME = 3600000;
public static String generateToken(String username) {
return Jwts.builder()
.setSubject(username)
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
public static String getUsernameFromToken(String token) {
return Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody()
.getSubject();
}
}
```
LoginController:
```java
@RestController
public class LoginController {
@Autowired
private UserService userService;
@PostMapping("/login")
public ResponseEntity<String> login(@RequestBody User user) {
String token = userService.login(user.getUsername(), user.getPassword());
return ResponseEntity.ok(token);
}
}
```
AuthController:
```java
@RestController
public class AuthController {
@Autowired
private RedisTemplate<String, String> redisTemplate;
@GetMapping("/auth")
public ResponseEntity<User> auth(@RequestHeader("Authorization") String token) {
String username = JWTUtil.getUsernameFromToken(token);
if (StringUtils.isEmpty(username)) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
String redisToken = redisTemplate.opsForValue().get(username);
if (!token.equals(redisToken)) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
User user = new User();
user.setUsername(username);
return ResponseEntity.ok(user);
}
}
```
在请求中携带token的示例:
```java
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.setInterceptors(Collections.singletonList((request, body, execution) -> {
String token = // 从Redis中获取token
request.getHeaders().add("Authorization", token);
return execution.execute(request, body);
}));
return restTemplate;
}
}
```
以上就是使用Spring Boot、JWT和Redis实现单点登录的步骤和示例代码。
springsecurity+jwt实现单点登录代码流程
Spring Security结合JWT实现单点登录的代码流程如下:
1. 创建一个Spring Boot项目并添加以下依赖:
```
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
```
2. 在Spring Security配置类中添加以下代码:
```
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationEntryPoint unauthorizedHandler;
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Value("${jwt.secret}")
private String secret;
@Value("${jwt.expiration}")
private int expiration;
@Bean
public JwtAuthenticationFilter authenticationTokenFilter() {
return new JwtAuthenticationFilter();
}
@Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.userDetailsService(customUserDetailsService)
.passwordEncoder(passwordEncoder());
}
@Bean(BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors()
.and()
.csrf()
.disable()
.exceptionHandling()
.authenticationEntryPoint(unauthorizedHandler)
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/api/auth/**")
.permitAll()
.anyRequest()
.authenticated();
// 添加JWT过滤器
http.addFilterBefore(authenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
@Bean
public JwtTokenProvider jwtTokenProvider() {
return new JwtTokenProvider(secret, expiration);
}
}
```
3. 创建一个JwtTokenProvider类,实现JWT的生成、解析和验证:
```
@Service
public class JwtTokenProvider {
private final String secret;
private final long expiration;
@Autowired
public JwtTokenProvider(@Value("${jwt.secret}") String secret, @Value("${jwt.expiration}") long expiration) {
this.secret = secret;
this.expiration = expiration;
}
public String generateToken(Authentication authentication) {
UserPrincipal userPrincipal = (UserPrincipal) authentication.getPrincipal();
Date now = new Date();
Date expiryDate = new Date(now.getTime() + expiration);
return Jwts.builder()
.setSubject(Long.toString(userPrincipal.getId()))
.setIssuedAt(new Date())
.setExpiration(expiryDate)
.signWith(SignatureAlgorithm.HS512, secret)
.compact();
}
public Long getUserIdFromToken(String token) {
Claims claims = Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
return Long.parseLong(claims.getSubject());
}
public boolean validateToken(String token) {
try {
Jwts.parser().setSigningKey(secret).parseClaimsJws(token);
return true;
} catch (SignatureException ex) {
System.out.println("Invalid JWT signature");
} catch (MalformedJwtException ex) {
System.out.println("Invalid JWT token");
} catch (ExpiredJwtException ex) {
System.out.println("Expired JWT token");
} catch (UnsupportedJwtException ex) {
System.out.println("Unsupported JWT token");
} catch (IllegalArgumentException ex) {
System.out.println("JWT claims string is empty.");
}
return false;
}
}
```
4. 创建一个JwtAuthenticationFilter类,拦截请求并验证JWT:
```
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Autowired
private JwtTokenProvider jwtTokenProvider;
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
try {
String jwt = getJwtFromRequest(request);
if (StringUtils.hasText(jwt) && jwtTokenProvider.validateToken(jwt)) {
Long userId = jwtTokenProvider.getUserIdFromToken(jwt);
UserDetails userDetails = customUserDetailsService.loadUserById(userId);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
} catch (Exception ex) {
logger.error("Could not set user authentication in security context", ex);
}
filterChain.doFilter(request, response);
}
private String getJwtFromRequest(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7, bearerToken.length());
}
return null;
}
}
```
5. 创建一个JwtAuthenticationEntryPoint类,处理未授权的请求:
```
@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
}
}
```
6. 创建一个UserPrincipal类,实现Spring Security的UserDetails接口:
```
public class UserPrincipal implements UserDetails {
private Long id;
private String username;
private String email;
private String password;
private Collection<? extends GrantedAuthority> authorities;
public UserPrincipal(Long id, String username, String email, String password, Collection<? extends GrantedAuthority> authorities) {
this.id = id;
this.username = username;
this.email = email;
this.password = password;
this.authorities = authorities;
}
public Long getId() {
return id;
}
public String getEmail() {
return email;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
```
7. 创建一个CustomUserDetailsService类,实现Spring Security的UserDetailsService接口:
```
@Service
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserRepository userRepository;
@Override
@Transactional
public UserDetails loadUserByUsername(String usernameOrEmail) throws UsernameNotFoundException {
User user = userRepository.findByUsernameOrEmail(usernameOrEmail, usernameOrEmail)
.orElseThrow(() ->
new UsernameNotFoundException("User not found with username or email : " + usernameOrEmail)
);
return UserPrincipal.create(user);
}
@Transactional
public UserDetails loadUserById(Long id) {
User user = userRepository.findById(id)
.orElseThrow(() ->
new ResourceNotFoundException("User", "id", id)
);
return UserPrincipal.create(user);
}
}
```
以上就是Spring Security结合JWT实现单点登录的代码流程,可以根据具体的需求进行相应的修改和调整。