Skip to content

Commit 4209fef

Browse files
committed
include examples of overriding default /login page
1 parent 1e3d42a commit 4209fef

2 files changed

Lines changed: 187 additions & 0 deletions

File tree

Test/AppHost.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using ServiceStack.Auth;
44
using ServiceStack.Configuration;
55
using ServiceStack.Data;
6+
using ServiceStack.Host.Handlers;
67
using ServiceStack.Logging;
78
using ServiceStack.NativeTypes.Java;
89
using ServiceStack.NativeTypes.TypeScript;
@@ -41,6 +42,10 @@ public override void Configure(Container container)
4142
{
4243
// this.GlobalHtmlErrorHttpHandler = new RazorHandler("/error");
4344

45+
// RawHttpHandlers.Add(req => req.PathInfo.StartsWith("/login")
46+
// ? new RedirectHttpHandler { RelativeUrl = "/metadata" }
47+
// : null);
48+
4449
SetConfig(new HostConfig
4550
{
4651
AdminAuthSecret = "secretz",

Test/wwwroot/Templates/login.html

Lines changed: 182 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<title>Sign In</title>
6+
<link rel="stylesheet" href="${BaseUrl}/css/bootstrap.css">
7+
<link rel="stylesheet" href="${BaseUrl}/css/buttons-svg.css">
8+
<link rel="stylesheet" href="${BaseUrl}/css/buttons.css">
9+
<link rel="stylesheet" href="${BaseUrl}/css/svg-auth.css">
10+
<script src="${BaseUrl}/js/servicestack-client.js"></script>
11+
<style>
12+
body {
13+
margin: 0;
14+
padding: 0 0 50px 0;
15+
color: #333;
16+
}
17+
a#logo {
18+
position: absolute;
19+
top: 4px;
20+
right: 0;
21+
width: 50px;
22+
height: 50px;
23+
background-size: 42px 42px;
24+
background-repeat: no-repeat;
25+
background-image: url("data:image/svg+xml,%3Csvg width='100' height='100' viewBox='0 0 100 100' xmlns='http://www.w3.org/2000/svg'%3E %3Cstyle%3E .path%7B%7D %3C/style%3E %3Cg id='servicestack-svg'%3E%3Cpath fill='%23ffffff' class='path' stroke='null' d='m16.564516,43.33871c16.307057,2.035887 54.629638,20.41875 60.67742,46.306452l-78.241936,0c19.859879,-1.616734 36.825605,-27.344758 17.564516,-46.306452zm6.387097,-30.33871c6.446976,7.105645 9.520766,16.74617 9.26129,26.666129c16.546573,6.726411 41.376412,24.690121 46.625807,49.979033l19.161291,0c-8.123589,-43.132863 -54.529839,-73.551412 -75.048388,-76.645162z' /%3E%3C/g%3E%3C/svg%3E");
26+
}
27+
h1 {
28+
color: #FFF;
29+
font-size: 26px;
30+
font-weight: normal;
31+
margin: 0;
32+
padding: 0 0 0 15px;
33+
line-height: 48px;
34+
min-height: 48px;
35+
border-radius: 0px;
36+
border-bottom: 1px solid #191e23;
37+
background: #2c3742; /* Old browsers */
38+
background: linear-gradient(to bottom, #2c3742 0%,#28303a 100%); /* W3C */
39+
}
40+
.stacktrace {
41+
background: #f1f1f1;
42+
padding: 1em;
43+
margin: 1em 0 .5em 0;
44+
border-radius: 5px;
45+
border: 1px solid #ccc;
46+
white-space: pre-wrap;
47+
}
48+
#auth {
49+
max-width: 350px;
50+
}
51+
@media (max-width: 768px)
52+
{
53+
.container {
54+
max-width: 700px;
55+
}
56+
}
57+
</style>
58+
</head>
59+
<body>
60+
<a id="logo" href="https://servicestack.net" title="ServiceStack"></a>
61+
<h1 id="title">
62+
<div class="container">Sign In</div>
63+
</h1>
64+
65+
<div>
66+
<div id="content" class="container mt-4">
67+
68+
<div class="row">
69+
<div class="col-5">
70+
71+
<form action="${BaseUrl}/auth/credentials" method="post">
72+
<div class="form-row">
73+
<div class="form-group" data-validation-summary="userName,password"></div>
74+
</div>
75+
<div class="form-row">
76+
<div class="form-group">
77+
<input class="form-control form-control-lg" name="userName" type="text"
78+
placeholder="UserName">
79+
</div>
80+
</div>
81+
<div class="form-row">
82+
<div class="form-group">
83+
<input class="form-control form-control-lg" name="password" type="password"
84+
placeholder="Password">
85+
</div>
86+
<div class="form-group col-md-4">
87+
<button type="submit" class="btn btn-lg btn-primary">Login</button>
88+
</div>
89+
</div>
90+
<div class="form-row">
91+
<div class="form-group">
92+
<input type="checkbox" id="rememberMe" name="rememberMe" value="true">
93+
<label for="rememberMe">Remember Me</label>
94+
</div>
95+
</div>
96+
</form>
97+
</div>
98+
99+
<div class="col-7">
100+
<div class="row justify-content-end">
101+
<div id="auth"></div>
102+
</div>
103+
</div>
104+
105+
</div>
106+
</div>
107+
</div>
108+
109+
110+
<script>
111+
Object.assign(window, window['@servicestack/client']) //import into global namespace
112+
client = new JsonServiceClient('/')
113+
// regen dtos: `x ts && tsc wwwroot/assets/js/dtos.ts`
114+
</script>
115+
116+
<script>
117+
let BaseUrl = "${BaseUrl}";
118+
let qs = queryString(location.href);
119+
let CONTINUE = qs['continue'] || qs.ReturnUrl || qs.redirect || (BaseUrl + '/auth')
120+
121+
function isValidUrl(url) {
122+
try {
123+
return url.indexOf(':') === -1 || new URL(url).origin === location.origin
124+
} catch (_) {
125+
return false
126+
}
127+
}
128+
function redirect(url) {
129+
if (!isValidUrl(url))
130+
alert('Invalid Redirect URL: "' + url + '"')
131+
else
132+
location.href = url
133+
}
134+
135+
function inIframe () {
136+
try {
137+
return window.self !== window.top
138+
} catch (e) {
139+
return true
140+
}
141+
}
142+
143+
bootstrapForm(document.querySelector('form'), {
144+
success: function (r) {
145+
redirect(CONTINUE)
146+
}
147+
})
148+
149+
fetch(BaseUrl + '/auth.json')
150+
.then(function (r) {
151+
if (r.ok) {
152+
redirect(CONTINUE)
153+
}
154+
})
155+
156+
fetch(BaseUrl + '/metadata/nav.json')
157+
.then(function(r){ return r.json(); })
158+
.then(function(r) {
159+
let sb = []
160+
let iframe = inIframe()
161+
let auth = (r.navItemsMap || r.NavItemsMap || {})['auth']
162+
if (auth)
163+
{
164+
for (let i=0; i<auth.length; i++) {
165+
let nav = auth[i]
166+
let meta = nav.meta || nav.Meta
167+
if (iframe && !(meta && meta.allows === 'embed')) continue
168+
169+
let cls = nav.className || nav.ClassName
170+
let iconCls = nav.iconClass || nav.IconClass
171+
sb.push('<a href="' + BaseUrl + (nav.href || nav.Href) + '" class="btn btn-block btn-lg ' + cls + '">')
172+
sb.push('<b class="' + iconCls + '"></b>')
173+
sb.push(nav.label || nav.Label)
174+
sb.push('</a>')
175+
}
176+
document.querySelector('#auth').innerHTML = sb.join('')
177+
}
178+
})
179+
</script>
180+
181+
</body>
182+
</html>

0 commit comments

Comments
 (0)