shiro+jwt如何实现单点登录,代码实例
时间: 2023-09-03 20:27:28 浏览: 178
### 回答1:
Shiro 支持使用 JSON Web Token (JWT) 实现单点登录 (SSO)。
实现步骤如下:
1. 在服务端生成 JWT 并返回给客户端。
2. 客户端保存 JWT 并在请求中加上 HTTP Header,如 "Authorization: Bearer JWT"。
3. 服务端收到请求后验证 JWT 的有效性。
4. 如果 JWT 有效,则允许访问请求的资源。
以下是一个使用 Shiro 实现 JWT 验证的示例代码:
```java
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
public class JwtRealm extends AuthorizingRealm {
private String secretKey;
public JwtRealm(String secretKey) {
this.secretKey = secretKey;
}
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof JwtToken;
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 这里可以根据 JWT 中的自定义字段来进行权限控制
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
JwtToken jwtToken = (JwtToken) token;
String jwt = jwtToken.getPrincipal().toString();
Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();
// 验证 JWT 是否过期
if (claims.getExpiration().before(new Date())) {
throw new AuthenticationException("JWT 已过期");
}
// 这里可以使用 claims 中的用户信息来创建 SimpleAuthenticationInfo 对象
return new SimpleAuthenticationInfo(jwt, jwt, "j
### 回答2:
Shiro JWT是一种基于JSON Web Token(JWT)的认证方式,可以用于实现单点登录(Single Sign-On,SSO)。下面是一个简单的代码示例,展示如何使用Shiro JWT实现单点登录。
首先,需要添加Shiro和JWT的依赖包,可以使用Maven进行管理。在pom.xml文件中添加以下依赖项:
```xml
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
```
然后,需要创建一个JWT工具类,用于生成和解析JWT:
```java
public class JWTUtil {
private static final String SECRET_KEY = "your-secret-key";
private static final long EXPIRATION_TIME = 86400000; // 24 hours
public static String createToken(String username) {
Date now = new Date();
Date expirationDate = new Date(now.getTime() + EXPIRATION_TIME);
return Jwts.builder()
.setSubject(username)
.setIssuedAt(now)
.setExpiration(expirationDate)
.signWith(SignatureAlgorithm.HS256, SECRET_KEY)
.compact();
}
public static String getUsernameFromToken(String token) {
Claims claims = Jwts.parser()
.setSigningKey(SECRET_KEY)
.parseClaimsJws(token)
.getBody();
return claims.getSubject();
}
}
```
接下来,在登录成功后生成JWT并返回给客户端:
```java
public class LoginController {
@PostMapping("/login")
public String login(@RequestParam String username, @RequestParam String password) {
// 验证用户名和密码
if (authenticateUser(username, password)) {
// 生成JWT
String token = JWTUtil.createToken(username);
return token;
} else {
return "登录失败";
}
}
}
```
在其他需要单点登录的接口中,可以使用Shiro的注解来验证JWT的有效性:
```java
public class UserController {
@RequiresAuthentication
@GetMapping("/user/{id}")
public String getUser(@PathVariable String id) {
// 处理业务逻辑
return "User " + id;
}
}
```
以上就是使用Shiro JWT实现单点登录的简单示例。在实际项目中,还需要结合数据库等存储方式来保存用户信息和JWT的校验过程,以及处理JWT过期等情况。
### 回答3:
在Shiro中,实现JWT(JSON Web Token)的单点登录,需要以下步骤:
首先,确保已经集成了Shiro和JWT相关的依赖。
然后,定义一个Shiro的自定义Realm,用于验证用户身份和生成JWT。如下示例:
```java
public class JWTRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// 授权逻辑,可根据具体需求进行自定义实现
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
JWTToken jwtToken = (JWTToken) token;
String jwt = jwtToken.getToken();
// 解析JWT并验证用户身份
String username = JWTUtils.getUsername(jwt);
String password = JWTUtils.getPassword(jwt);
// 根据用户名查询数据库或其他存储,获取用户信息
// 此处省略数据库查询逻辑
if (username == null || !password.equals("123456")) {
throw new IncorrectCredentialsException("用户身份验证失败");
}
// 用户身份验证通过,返回AuthenticationInfo对象
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username, jwt, getName());
return authenticationInfo;
}
@Override
public boolean supports(AuthenticationToken token) {
return token instanceof JWTToken;
}
}
```
接下来,配置Shiro的过滤链,让Shiro对请求进行JWT认证和授权的处理。如下示例:
```java
public class ShiroConfig {
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
// 添加自定义的JWT过滤器
Map<String, Filter> filters = new HashMap<>();
filters.put("jwt", new JWTFilter());
shiroFilterFactoryBean.setFilters(filters);
// 配置过滤链
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/**", "jwt");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
@Bean
public DefaultWebSecurityManager securityManager(ShiroRealm shiroRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(shiroRealm);
return securityManager;
}
@Bean
public ShiroRealm shiroRealm() {
return new ShiroRealm();
}
}
```
最后,创建一个JWT过滤器,用于处理JWT的验证和登录。如下示例:
```java
public class JWTFilter extends AuthenticatingFilter {
@Override
protected AuthenticationToken createToken(ServletRequest request, ServletResponse response) {
String jwt = getTokenFromRequest(request);
if (StringUtils.isNotBlank(jwt) && JWTUtils.verifyToken(jwt)) {
return new JWTToken(jwt);
}
return null;
}
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
redirectToLogin(request, response);
return false;
}
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
if (isLoginAttempt(request, response)) {
try {
executeLogin(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
return true;
}
private boolean isLoginAttempt(ServletRequest request, ServletResponse response) {
String jwt = getTokenFromRequest(request);
return StringUtils.isNotBlank(jwt) && JWTUtils.verifyToken(jwt);
}
private String getTokenFromRequest(ServletRequest request) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
String jwt = httpServletRequest.getHeader("Authorization");
if (StringUtils.isNotBlank(jwt) && jwt.startsWith("Bearer ")) {
return jwt.replace("Bearer ", "");
}
return null;
}
private void redirectToLogin(ServletRequest request, ServletResponse response) {
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
}
}
```
这样就实现了使用Shiro和JWT实现单点登录的功能。使用以上代码示例,可根据具体需求进行扩展和自定义。
阅读全文