有一个需要用户身份验证的spring应用程序。
检查JWT cookie是否存在,然后允许用户访问,否则重定向到身份验证应用程序。
此身份验证应用程序根据数据库验证用户并使用JWT cookie(原始应用程序已知其私钥)作为url参数返回到原始应用程序。
原始应用程序然后设置JWT cookie,允许用户访问并向弹出后端发送ajax请求,重新初始化用户会话对象。
用户被定义为组件:
@Component
@Scope("session")
public class User {
}
在控制器中,我这样做:
@Controller
@RequestMapping("/login")
@Scope("request")
public class LoginController {
@Autowired
private User user;
@RequestMapping(value = "/do-login", method = RequestMethod.POST)
@ResponseBody
public String login(HttpServletRequest request) throws IOException{
user = new User()
// SET USER PROPERTIES USING JWT TOKEN
}
}
这是正确的做法吗?我应该直接在会话中设置值而不是使用spring组件吗?应该将jwt令牌存储在会话而不是cookie中吗?
答案 0 :(得分:0)
为何使用Spring security。
<强>配置:强>
在spring security configuration xml文件中使用security:form-login login-page
标记。它会自动将您的应用程序重定向到登录页面。
REMEBER: 在您的控制器中配置这些网址(security:intercept-url pattern
)。
<security:http auto-config="true" use-expressions="true">
<security:intercept-url pattern="/login"
access="permitAll" />
<security:intercept-url pattern="/accessDenied"
access="permitAll" />
<security:intercept-url pattern="/loginFail"
access="permitAll" />
<security:intercept-url pattern="/logout"
access="permitAll" />
<security:intercept-url pattern="/resources/**"
access="permitAll" />
<security:intercept-url pattern="/**"
access="hasRole('ROLE_ADMIN')" />
<security:access-denied-handler
error-page="/accessDenied" />
<security:form-login login-page="/login"
default-target-url="/home" always-use-default-target="true"
authentication-failure-url="/loginFail" username-parameter="username"
password-parameter="password" />
<security:logout logout-success-url="/logout" />
</security:http>
这是关于春季安全的最佳reference tutorial,我遇到过。请尝试根据此配置您的应用程序,如果您想要两个配置( JAVA / XML ),请参阅MKYONG示例。
推荐:使用Spring安全性,它是一个很好的弹簧工具来操作/处理身份验证过程,它非常容易配置,你不必深入研究。
我希望这会有所帮助。
答案 1 :(得分:0)
首先,你必须考虑为什么要使用JWT。 创建JWT是为了参加特定的problems of modern web applications,主要是代表cookie的服务器状态问题。
<强> 1。应用程序分布在许多服务器上
今天的许多应用程序的部署方式与它们不同 过去。对于应用程序来说,它现在非常普遍 - 而且通常是必需的 分布在许多服务器上,以便增加正常运行时间 延迟问题得到缓解。这带来了副作用, 当用户访问应用程序时,不再保证 他们总是访问同一台服务器。 由于传统的身份验证依赖于服务器来保持 用户在内存中的身份验证状态,当应用程序崩溃时 从不同的服务器访问。用户可能登录了一个 服务器,但不包括应用程序分发的其他服务器 对面。
<强> 2。应用程序使用API进行数据
以这种方式使用API非常棒,但事情可能会变得具有挑战性 在身份验证方面。传统的使用方法 用户身份的会话和cookie在以下方面效果不佳 这些情况因为它们的使用将状态引入应用程序。一 RESTful API的原则是它应该是无状态的,意思是 当发出请求时,某些参数内的响应可以 总是可以预期没有副作用。用户的身份验证 国家引入了这样的副作用,打破了这一原则。 保持API无状态,因此没有副作用意味着 可维护性和调试变得更加容易。
第3。 CORS(在单页应用程序中很常见)
此处的另一个挑战是,提供API非常常见&gt;从一个服务器和实际应用程序从另一个服务器使用它。 为实现这一目标,我们需要启用跨源资源共享 (CORS)。由于cookie只能用于它们所在的域 起源于它们对不同域上的API的帮助不大 申请。
RESTful API每天都比较常见,必须为stateless by definition。 无状态功能允许horizontal scaling,因为任何服务器都可以访问请求。 您可以使用更简单的JSON API和无状态后端,并从没有REST的水平scalling中受益。 因此,如果您需要Custom JWT authentication that integrates with Spring之类的复杂授权,则可以使用method authorization并从授权部分中受益。
当你说
时是否应将jwt令牌存储在会话而不是cookie中?
我认为你没有完全理解JWT,因为JWT令牌不必存储在服务器端(会话)中。这意味着服务器端的状态是JWT要避免的。 必须在针对登录端点(类似于/ login)的成功用户身份验证上创建JWT。这项工作将由注入UsernamePasswordAuthenticationFilter的AuthenticationSuccessHandler完成。例如:
public class JWTAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
protected JWSSigner jwsSigner;
public JWTAuthenticationSuccessHandler(JWSSigner jwsSigner){
this.jwsSigner = jwsSigner;
}
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
String ipaddress = request.getRemoteAddr();
JWTClaimsSet.Builder builder = new JWTClaimsSet.Builder();
JWTClaimsSet claimsSet = builder.subject("subject").issuer("issuer").expirationTime(new Date(new Date().getTime() + 60 * 1000)).claim("ipaddress",ipaddress).build();
SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), claimsSet);
try {
signedJWT.sign(jwsSigner);
String serializedJWT = signedJWT.serialize();
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getOutputStream().println(serializedJWT);
} catch (JOSEException e) {
e.printStackTrace();// TODO
}
}
}
然后,客户端必须将令牌存储在localStorage or cookie中并随每个请求发送。服务器将仅验证令牌的完整性,不再需要针对用户凭据的身份验证(除非令牌已过期)。
那么,您对JWT的期望是什么?哪些功能必须完成您的身份验证机制?